Linux には READ_IMPLIES_EXEC という実行ドメインがあります。 、これにより、すべてのページが PROT_READ で割り当てられます PROT_EXEC も与えられる .古い Linux カーネルは、gcc -z execstack と同等のものを使用する実行可能ファイルにこれを使用していました .このプログラムは、それが有効になっているかどうかを表示します:
#include <stdio.h>
#include <sys/personality.h>
int main(void) {
printf("Read-implies-exec is %s\n", personality(0xffffffff) & READ_IMPLIES_EXEC ? "true" : "false");
return 0;
}
空の .s と一緒にコンパイルすると ファイルが有効になっていることがわかりますが、ファイルがない場合は無効になります。この初期値は、バイナリの ELF メタ情報から取得されます。 readelf -Wl example を実行 .空の .s なしでコンパイルすると、この行が表示されます ファイル:
GNU_STACK 0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW 0x10
しかし、これをコンパイルしたときのこれ:
GNU_STACK 0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RWE 0x10
RWE に注意してください RW の代わりに .これは、リンカがアセンブリ ファイルに read-implies-exec が必要であると明示的に指示されていない限り、必要であると想定し、プログラムのいずれかの部分で read-implies-exec が必要な場合は、プログラム全体で有効になるためです。 . GCC がコンパイルするアセンブリ ファイルは、この行でこれが必要ないことを伝えます (-S でコンパイルすると、これが表示されます)。 ):
.section .note.GNU-stack,"",@progbits
デフォルトのセクション権限には ex が含まれていません ec。 .section の ELF 部分を参照してください 「フラグ」と @attributes の意味に関するドキュメント。
(そして .text のような別のセクションに切り替えることを忘れないでください または .data その後 .section .s の場合、ディレクティブ .text に依存していました デフォルトのセクションがファイルの先頭にあるためです。)
その行を example.s に入れます (および他のすべての .s プロジェクト内のファイル)。あの.note.GNU-stackの存在 セクションは、このオブジェクト ファイルが実行可能スタックに依存していないことをリンカーに伝える役割を果たします。そのため、リンカーは RW を使用します。 RWE の代わりに GNU_STACK で メタデータ、およびプログラムは期待どおりに動作します。
同様に、NASM の場合は section 正しいフラグを持つディレクティブは、実行不可能なスタックを指定します。
最新の Linux カーネル 5.4 から 5.8 で動作が変更されました ELF プログラムローダーの。 x86-64 の場合、READ_IMPLIES_EXEC を有効にするものはありません もう。最大 (RWE GNU_STACK の場合) ld によって追加されました )、読み取り可能なすべてのページではなく、スタック自体が実行可能になります。 (この回答は 5.8 の最後の変更をカバーしていますが、その質問は .data でコードの実行が成功したことを示しているため、それ以前に他の変更があったに違いありません x86-64 Linux 5.4)
exec-all (READ_IMPLIES_EXEC ) リンカーが GNU_STACK を追加しなかった従来の 32 ビット実行可能ファイルでのみ発生します ヘッダーエントリはすべて。しかし、ここに示されているように、現代の ld 入力 .o の場合でも、常にいずれかの設定でそれを追加します ファイルにメモがありません。
この .note を引き続き使用する必要があります 通常のプログラムで実行不可能なスタックを通知するセクション。しかし、.data で自己変更コードをテストしたい場合は、 または、シェルコードをテストするための古いチュートリアルに従ってください。これは、最新のカーネルではオプションではありません。
GNU 固有のセクション ディレクティブのバリアントを使用してアセンブリ ファイルを変更する代わりに、 -Wa,--noexecstack を追加できます。 アセンブリ ファイルをビルドするためのコマンド ラインに追加します。たとえば、musl の configure でそれを行う方法を参照してください。 :
https://git.musl-libc.org/cgit/musl/commit/configure?id=adefe830dd376be386df5650a09c313c483adf1a
統合アセンブラを使用するclangの少なくとも一部のバージョンでは、--noexecstackとして渡す必要があると思います (-Wa なし) )、したがって、構成スクリプトはおそらく両方をチェックして、どちらが受け入れられるかを確認する必要があります。
-Wl,-z,noexecstack も使用できます リンク時 (LDFLAGS) )同じ結果が得られます。これの欠点は、プロジェクトが静的 (.a) を生成する場合に役に立たないことです。 ) 他のソフトウェアで使用するためのライブラリ ファイル。これは、他のプログラムで使用されている場合、リンク時のオプションを制御できないためです。