プロジェクトにアセンブリファイルが含まれている場合のmmapからの予期しないexec権限


94

これで頭を壁に打ちつけています。

私のプロジェクトではmmap、マッピング(/proc/self/maps)を使用してメモリを割り当てているときに、読み取り可能なメモリのみを要求したにもかかわらず、それが読み取り可能で実行可能な領域であることを示しています。

strace(見栄えは良かった)やその他のデバッグを調べたところ、この奇妙な問題を回避していると思われる唯一のこと、つまりプロジェクトからアセンブリファイルを削除し、純粋なCのみを残すことを特定できました(何ですか?)。

だからここに私の奇妙な例が​​あります、私はUbunbtu 19.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 

5
これは非常に奇妙です。
-fuz

6
私はこれをGCC(CMakeなし)だけで再現できたので、例を最小限に抑えるために質問を編集しました。
ジョセフ・サイブル復活モニカ


あなたは正しいかもしれませんが、彼の回答の一部は、READ_IMPLIES_EXECペルソナに関連している必要があります
Ben Hirschberg

でソースファイルをアセンブルします-Wa,--noexecstack
-jww

回答:


90

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がコンパイルするアセンブリファイルは、これを必要としないことを次の行で伝えます(でコンパイルすると、これが表示されます-S)。

        .section        .note.GNU-stack,"",@progbits

その行をに入れるとexample.s、リンカに不要であることを伝え、プログラムは期待どおりに動作します。


13
なんてこった、それは奇妙なデフォルトです。noexecの前にツールチェーンが存在していたと思います。noexecをデフォルトにすると、問題が発生する可能性があります。NASM / YASMのような他のアセンブラが.oファイルを作成する方法に興味があります。しかし、とにかく、これがgcc -zexecstack使用するメカニズムであり、それがスタックだけでなくすべてを実行可能にする理由だと思います。
Peter Cordes

23
@Peter-これが、Botan、Crypto ++、OpenSSLなどのアセンブラーを使用するプロジェクトにを追加する理由-Wa,--noexecstackです。非常に厄介な鋭いエッジだと思います。nxスタックのサイレント損失は、セキュリティの脆弱性です。Binutilの人々はそれを修正するべきです。
jww

14
@jww確かにセキュリティの問題で、誰もそれを以前に報告したことがないのは奇妙です
Ben Hirschberg

4
+1ですが、行の意味/ロジック.note.GNU-stack,"",@progbitsが説明されている場合、この答えははるかに優れています-現在のところ、「この文字の魔法の文字列がこの効果を引き起こす」のと同じように不透明ですが、文字列はある種のように見えますセマンティクス。
mtraceur

33

GNU固有のセクションディレクティブバリアントでアセンブリファイルを変更する代わりに、アセンブリファイルをビルドする-Wa,--noexecstackためのコマンドラインを追加できます。たとえば、私がmuslでそれを行う方法を参照してくださいconfigure

https://git.musl-libc.org/cgit/musl/commit/configure?id=adefe830dd376be386df5650a09c313c483adf1a

統合アセンブラーを備えたclangの少なくともいくつかのバージョンでは、それを--noexecstack(なしで-Wa)として渡す必要がある場合があるため、構成スクリプトはおそらく両方をチェックし、どちらが受け入れられるかを確認する必要があります。

-Wl,-z,noexecstackリンク時に(でLDFLAGS)使用して、同じ結果を取得することもできます。これの欠点は、プロジェクトが.a他のソフトウェアで使用するための静的()ライブラリファイルを生成する場合に役に立たないことです。これは、他のプログラムで使用されるときにリンク時オプションを制御しないためです。


1
うーん...この投稿を読む前は、あなたがリッチフェルカーであることを知りませんでした。なぜあなたの表示名はダリアスではないのですか?
SSアン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.