これで頭を壁にぶつけています。
私のプロジェクトでは、mmap
でメモリを割り当てているときに、マッピング(/proc/self/maps
)が読み取り可能で実行可能な領域であることを示していますにもかかわらず読み取り可能なメモリのみを要求しました。
Strace(見栄えがよかった)と他のデバッグを調べた後、この奇妙な問題を回避しているように見える唯一のものを特定することができました:プロジェクトからアセンブリファイルを削除し、純粋なCのみを残します(何?!)
ここに私の奇妙な例があります。Ubunbtu19.04とデフォルトのgccで作業しています。
ASMファイル(空)を使用してターゲット実行可能ファイルをコンパイルすると、mmap
は読み取り可能で実行可能な領域を返します。それなしでビルドすると、正しく動作します。例に埋め込んだ/proc/self/maps
の出力を参照してください。
example.c
#include <stdio.h>
#include <string.h>
#include <sys/mman.h>
int main()
{
void* p;
p = mmap(NULL, 8192,PROT_READ,MAP_ANONYMOUS|MAP_PRIVATE,-1,0);
{
FILE *f;
char line[512], s_search[17];
snprintf(s_search,16,"%lx",(long)p);
f = fopen("/proc/self/maps","r");
while (fgets(line,512,f))
{
if (strstr(line,s_search)) fputs(line,stderr);
}
fclose(f);
}
return 0;
}
example.s:空のファイルです!
出力
ASM付属バージョン
VirtualBox:~/mechanics/build$ gcc example.c example.s -o example && ./example
7f78d6e08000-7f78d6e0a000 r-xp 00000000 00:00 0
ASM付属バージョンなし
VirtualBox:~/mechanics/build$ gcc example.c -o example && ./example
7f1569296000-7f1569298000 r--p 00000000 00:00 0
LinuxにはREAD_IMPLIES_EXEC
と呼ばれる 実行ドメイン があり、PROT_READ
で割り当てられたすべてのページにPROT_EXEC
も与えられます。 。このプログラムは、それが有効になっているかどうかを示します。
#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がコンパイルするAssemblyファイルは、次の行を使用して、これを必要としないことを示しています(-S
でコンパイルすると、これが表示されます)。
.section .note.GNU-stack,"",@progbits
その行をexample.s
に入れると、リンカにそれも必要ないことを伝え、プログラムは期待どおりに動作します。
GNU固有のセクションディレクティブバリアントを使用してアセンブリファイルを変更する代わりに、アセンブリファイルをビルドするためのコマンドラインに-Wa,--noexecstack
を追加できます。たとえば、muslのconfigure
でどのように実行するかを参照してください。
https://git.musl-libc.org/cgit/musl/commit/configure?id=adefe830dd376be386df5650a09c313c483adf1a
少なくとも統合アセンブラを備えたclangのいくつかのバージョンでは、--noexecstack
(-Wa
なし)として渡す必要があるため、configureスクリプトはおそらく両方をチェックし、どちらが受け入れられるかを確認する必要があります。
リンク時に(LDFLAGS
で)-Wl,-z,noexecstack
を使用して同じ結果を取得することもできます。これの欠点は、プロジェクトが他のソフトウェアで使用するときに静的(.a
)ライブラリファイルを生成しても助けにならないことです。これは、他のプログラムで使用するときにリンク時オプションを制御しないためです。