Unerwartete Ausführungsberechtigung von mmap, wenn Assembly-Dateien im Projekt enthalten sind

94

Ich stoße damit meinen Kopf gegen die Wand.

Wenn ich in meinem Projekt Speicher mit mmapdem Mapping ( /proc/self/maps) zuordne, zeigt dies, dass es sich um einen lesbaren und ausführbaren Bereich handelt, obwohl ich nur lesbaren Speicher angefordert habe.

Nachdem ich mir strace (was gut aussah) und anderes Debugging angesehen hatte, konnte ich das einzige identifizieren, das dieses seltsame Problem zu vermeiden scheint: Baugruppendateien aus dem Projekt entfernen und nur reines C belassen (was?!)

Hier ist mein seltsames Beispiel: Ich arbeite an Ubunbtu 19.04 und Standard-GCC.

Wenn Sie die ausführbare Zieldatei mit der ASM-Datei (die leer ist) kompilieren, wird mmapein lesbarer und ausführbarer Bereich zurückgegeben. Wenn Sie ohne erstellen, verhält sie sich korrekt. Siehe die Ausgabe, /proc/self/mapsdie ich in mein Beispiel eingebettet habe.

Beispiel.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;
}

Beispiel.s : Ist eine leere Datei!

Ausgänge

Mit der in ASM enthaltenen Version

VirtualBox:~/mechanics/build$ gcc example.c example.s -o example && ./example
7f78d6e08000-7f78d6e0a000 r-xp 00000000 00:00 0 

Ohne die mitgelieferte ASM-Version

VirtualBox:~/mechanics/build$ gcc example.c -o example && ./example
7f1569296000-7f1569298000 r--p 00000000 00:00 0 
Ben Hirschberg
quelle
5
Das ist ernsthaft komisch.
Fuz
6
Ich habe es geschafft, dies nur mit GCC (kein CMake) zu reproduzieren, also habe ich die Frage bearbeitet, um das Beispiel minimaler zu machen.
Joseph Sible-Reinstate Monica
2
Möglicherweise verwandte stackoverflow.com/questions/32730643/…
Sami Kuhmonen
Sie könnten Recht haben, ein Teil der Antwort muss um READ_IMPLIES_EXEC Persona sein
Ben Hirschberg
Stellen Sie Ihre Quelldateien mit zusammen -Wa,--noexecstack.
JWW

Antworten:

90

Linux hat eine Ausführungsdomäne namens READ_IMPLIES_EXEC, die bewirkt, dass alle zugewiesenen Seiten PROT_READebenfalls angegeben werden PROT_EXEC. Dieses Programm zeigt Ihnen, ob dies für sich selbst aktiviert ist:

#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;
}

Wenn Sie das zusammen mit einer leeren .sDatei kompilieren , werden Sie sehen, dass es aktiviert ist, aber ohne eine wird es deaktiviert. Der Anfangswert hierfür stammt aus den ELF-Metainformationen in Ihrer Binärdatei . Tu es readelf -Wl example. Diese Zeile wird angezeigt, wenn Sie ohne die leere .sDatei kompiliert haben :

  GNU_STACK      0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW  0x10

Aber dieses, als Sie damit kompilierten:

  GNU_STACK      0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RWE 0x10

Beachten Sie RWEstatt nur RW. Der Grund dafür ist, dass der Linker davon ausgeht, dass Ihre Assembly-Dateien read-implizite-exec erfordern, es sei denn, es wird ausdrücklich darauf hingewiesen, dass dies nicht der Fall ist. Wenn ein Teil Ihres Programms read-implizite-exec erfordert, ist es für Ihr gesamtes Programm aktiviert . Die Assembly-Dateien, die GCC kompiliert, geben an, dass dies in dieser Zeile nicht erforderlich ist (dies wird angezeigt, wenn Sie mit kompilieren -S):

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

Wenn Sie diese Zeile eingeben, example.swird dem Linker mitgeteilt, dass er sie auch nicht benötigt, und Ihr Programm funktioniert dann wie erwartet.

Joseph Sible-Reinstate Monica
quelle
13
Heiliger Mist, das ist ein seltsamer Standard. Ich denke, die Toolchain existierte vor noexec, und wenn noexec zum Standard gemacht wurde, könnte dies zu Problemen führen. Jetzt bin ich gespannt, wie andere Assembler wie NASM / YASM .oDateien erstellen ! Aber ich denke, dies ist der Mechanismus, der gcc -zexecstackverwendet wird, und warum er nicht nur den Stapel, sondern alles ausführbar macht.
Peter Cordes
23
@Peter - Deshalb fügen Projekte wie Botan, Crypto ++ und OpenSSL, die den Assembler verwenden, hinzu -Wa,--noexecstack. Ich denke, es ist eine sehr böse scharfe Kante. Der stille Verlust von nx-Stacks sollte eine Sicherheitslücke sein. Die Binutil-Leute sollten es reparieren.
JWW
14
@jww Es ist in der Tat ein Sicherheitsproblem, seltsam, dass niemand es zuvor gemeldet hat
Ben Hirschberg
4
+1, aber diese Antwort wäre viel besser, wenn die Bedeutung / Logik der Zeile .note.GNU-stack,"",@progbits erklärt würde - im Moment ist sie undurchsichtig, was "diese magische Zeichenfolge verursacht diesen Effekt" entspricht, aber die Zeichenfolge sieht eindeutig so aus, als hätte sie eine Art Semantik.
mtraceur
33

Alternativ zum Ändern Ihrer Assembly-Dateien mit GNU-spezifischen Varianten der Abschnittsanweisung können Sie -Wa,--noexecstackIhrer Befehlszeile das Erstellen von Assembly-Dateien hinzufügen . Sehen Sie zum Beispiel, wie ich es in Musls mache configure:

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

Ich glaube, zumindest einige Versionen von clang mit integriertem Assembler erfordern möglicherweise die Übergabe als --noexecstack(ohne -Wa), daher sollte Ihr Konfigurationsskript wahrscheinlich beide prüfen und prüfen, welche akzeptiert werden.

Sie können auch verwenden -Wl,-z,noexecstack zur Linkzeit (in LDFLAGS) verwenden, um das gleiche Ergebnis zu erhalten. Dies hat den Nachteil, dass es nicht hilft, wenn Ihr Projekt statische ( .a) Bibliotheksdateien zur Verwendung durch andere Software erstellt, da Sie dann die Verbindungszeitoptionen nicht steuern, wenn sie von anderen Programmen verwendet werden.

R .. GitHub HÖREN SIE AUF, EIS ZU HELFEN
quelle
1
Hmm ... Ich wusste nicht, dass du Rich Felker bist, bevor ich diesen Beitrag gelesen habe. Warum ist Ihr Anzeigename nicht Dalias?
SS Anne