システムのどの部分が原因なのか実際にはわかりませんが、なぜ失敗するのかはわかります。一方で.dtors
、バイナリで書き込み可能とマークされ、それはそれのように見えます(に沿って.ctors
、GOT、およびいくつかの他のもの)メモリに独立し、非書き込み可能なページにマッピングされています。私のシステムで.dtors
は、に置かれてい0x8049f14
ます:
$ readelf -S test
[17] .ctors PROGBITS 08049f0c 000f0c 000008 00 WA 0 0 4
[18] .dtors PROGBITS 08049f14 000f14 000008 00 WA 0 0 4
[19] .jcr PROGBITS 08049f1c 000f1c 000004 00 WA 0 0 4
[20] .dynamic DYNAMIC 08049f20 000f20 0000d0 08 WA 6 0 4
[21] .got PROGBITS 08049ff0 000ff0 000004 04 WA 0 0 4
[22] .got.plt PROGBITS 08049ff4 000ff4 00001c 04 WA 0 0 4
[23] .data PROGBITS 0804a010 001010 000008 00 WA 0 0 4
[24] .bss NOBITS 0804a018 001018 000008 00 WA 0 0 4
実行可能ファイルを実行してチェックすると/proc/PID/maps
、次のようになります。
08048000-08049000 r-xp 00000000 08:02 163678 /tmp/test
08049000-0804a000 r--p 00000000 08:02 163678 /tmp/test
0804a000-0804b000 rw-p 00001000 08:02 163678 /tmp/test
.data
/ .bss
はまだ自分のページで書き込み可能ですが、他のページは書き込み可能で0x8049000-0x804a000
はありません。これはカーネルのセキュリティ機能だと思いますが(あなたが言ったように、「最近、読み取り専用の.dtors、plt、最近入手された」という動きがありました)、私はそれが何と呼ばれているのか特にわかりません(OpenBSDには非常によく似たものがあります)W ^ X ; LinuxにはPaXがありますが、ほとんどのカーネルには組み込まれていません)
mprotect
ページのメモリ内属性を変更できるで回避できます。
mprotect((void*)0x8049000, 4096, PROT_WRITE);
これでテストプログラムはクラッシュしませんが、.dtors
(0x8049f18
)の終了センチネルを別の関数のアドレスで上書きしようとしても、その関数は実行されません。私にはわからないその部分。
うまくいけば、他の誰かがページを読み取り専用にする責任があること、および変更.dtors
が私のシステムで何もしないように見える理由を知っています