PIEバイナリとLD_PRELOAD

PIE (位置独立実行形式) を作成する - bkブログ
この辺読んでたらPIEはPLT経由の呼出じゃ無い為LD_PRELOADで上書き不可
と書いてあったので、どうなってるのだろうと思い実験してみる。

対象コード

$ cat test.c
int main(int argc, char ** argv){
        printf("a\n");
        hoge();
        return 0;
}
int hoge(){
        putchar('b');
        putchar('\n');
        return 0;
}

対象ライブラリコード

$ cat test_ld.c
int printf(const char * format, ...){
        putchar('A');
        putchar('\n');
        return 0;
}
int hoge(){
        putchar('B');
        putchar('\n');
        return 0;
}

それぞれコンパイル

# デフォ
$ gcc -c test.c && gcc -o exe_default test.o
# PIE付き
$ gcc -c -fPIE test.c && gcc -o exe_pie -pie test.o
# ライブラリ
$ gcc -c -fPIC test_ld.c && gcc -shared -o test_ld.so test_ld.o

実行

$ ./exe_default
a
b
$ ./exe_pie
a
b
$ LD_PRELOAD=./test_ld.so ./exe_default
A
b
$ LD_PRELOAD=./test_ld.so ./exe_pie
A
b

実行バイナリ自体が持っている関数hogeが乗っ取れないのはbindingの対象に
ならないので良いとして、何故かPIEの場合でも関数乗っ取りが効いている。


私が読み違えていて、実は共有ライブラリ内で呼んでいる関数の事なのかと思い
ライブラリ自体をPIC/PIEで作ってみたけど、共にPLT経由で呼び出している。

$ gcc -c -fPIE test_ld.c && gcc -shared -pie -o test_link.so.pie test_ld.o
$ gcc -c -fPIC test_ld.c && gcc -shared -o test_link.so.pic test_ld.o
$ readelf -s test_link.so.pic  | grep putchar
    11: 00000000   266 FUNC    GLOBAL DEFAULT  UND putchar@GLIBC_2.0 (2)
    43: 00000000   266 FUNC    GLOBAL DEFAULT  UND putchar@@GLIBC_2.0
$ readelf -s test_link.so.pie  | grep putchar
    11: 00000000   266 FUNC    GLOBAL DEFAULT  UND putchar@GLIBC_2.0 (2)
    44: 00000000   266 FUNC    GLOBAL DEFAULT  UND putchar@@GLIBC_2.0
$ objdump -d test_link.so.pic | grep putchar | grep call
 50c:   e8 07 ff ff ff          call   418 <putchar@plt>
 519:   e8 fa fe ff ff          call   418 <putchar@plt>
$ objdump -d test_link.so.pie | grep putchar | grep call
 4d8:   e8 07 ff ff ff          call   3e4 <putchar@plt>
 4e5:   e8 fa fe ff ff          call   3e4 <putchar@plt> 

dlopen,dlsymしてる場合は効かないけど、これは検索対象がそのときにopenした物
だけなのでそもそもLD_PRELOADの対象外のはず。LD_DEBUGでトレースしてみても
該当ライブラリのみしかopenしていなかった。


PLT未使用でPosition independentかつLD_PRELOADでシンボル置き換え不可と
いうのは実装的に気になる所なんだけど、再現させられなかったので謎のまま。