GNU/Linux >> Linux Esercitazione >  >> Linux

Autorizzazione exec imprevista da mmap quando i file di assemblaggio sono inclusi nel progetto

Linux ha un dominio di esecuzione chiamato READ_IMPLIES_EXEC , che provoca l'allocazione di tutte le pagine con PROT_READ da dare anche PROT_EXEC . I vecchi kernel Linux lo usavano per gli eseguibili che usavano l'equivalente di gcc -z execstack . Questo programma ti mostrerà se è abilitato per se stesso:

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

Se lo compili insieme a un .s vuoto file, vedrai che è abilitato, ma senza uno sarà disabilitato. Il valore iniziale di questo viene dalle meta-informazioni ELF nel tuo binario. Esegui readelf -Wl example . Vedrai questa riga quando hai compilato senza il .s vuoto file:

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

Ma questo quando lo hai compilato:

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

Nota RWE invece di solo RW . La ragione di ciò è che il linker presuppone che i tuoi file assembly richiedano read-implies-exec a meno che non sia esplicitamente detto che non lo fanno, e se qualsiasi parte del tuo programma richiede read-implies-exec, allora è abilitato per l'intero programma . I file assembly che GCC compila gli dicono che non ne ha bisogno, con questa riga (lo vedrai se compili con -S ):

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

I permessi di sezione predefiniti non includono ex ec. Vedi la parte ELF del .section documentazione per il significato dei "flag" e degli @attributi.

(E non dimenticare di passare a un'altra sezione come .text o .data dopo quel .section direttiva, se il tuo .s faceva affidamento su .text perché la sezione predefinita all'inizio del file.)

Inserisci quella riga in example.s (e ogni altro .s file nel tuo progetto). La presenza di quel .note.GNU-stack servirà per dire al linker che questo file oggetto non dipende da uno stack eseguibile, quindi il linker userà RW invece di RWE sul GNU_STACK metadati e il tuo programma funzionerà come previsto.

Analogamente per NASM, un section direttiva con i flag giusti specifica stack non eseguibili.

I moderni kernel Linux tra 5.4 e 5.8 hanno cambiato il comportamento del caricatore di programmi ELF. Per x86-64, non si attiva nulla READ_IMPLIES_EXEC più. Al massimo (con un RWE GNU_STACK aggiunto da ld ), otterrai che lo stack stesso sia eseguibile, non tutte le pagine leggibili. (Questa risposta copre l'ultima modifica, in 5.8, ma devono esserci state altre modifiche prima, poiché quella domanda mostra l'esecuzione corretta del codice in .data su x86-64 Linux 5.4)

exec-all (READ_IMPLIES_EXEC ) si verifica solo per gli eseguibili legacy a 32 bit in cui il linker non ha aggiunto un GNU_STACK voce di intestazione a tutti. Ma come mostrato qui, ld moderno lo aggiunge sempre con un'impostazione o con l'altra, anche quando un input .o manca una nota.

Dovresti comunque usare questo .note sezione per segnalare stack non eseguibili nei normali programmi. Ma se speravi di testare il codice automodificante in .data o seguire qualche vecchio tutorial per testare lo shellcode, non è un'opzione sui kernel moderni.


In alternativa alla modifica dei file assembly con varianti di direttive di sezione specifiche di GNU, puoi aggiungere -Wa,--noexecstack alla riga di comando per la creazione di file di assieme. Ad esempio, guarda come lo faccio in configure di musl :

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

Credo che almeno alcune versioni di clang con l'assembler integrato potrebbero richiedere che venga passato come --noexecstack (senza -Wa ), quindi il tuo script di configurazione dovrebbe probabilmente controllare entrambi e vedere quale è accettato.

Puoi anche usare -Wl,-z,noexecstack al momento del collegamento (in LDFLAGS ) per ottenere lo stesso risultato. Lo svantaggio di questo è che non aiuta se il tuo progetto produce file statici (.a ) file di libreria per l'utilizzo da parte di altri software, poiché non controlli le opzioni di tempo di collegamento quando viene utilizzato da altri programmi.


Linux
  1. Cosa succede esattamente quando eseguo un file nella shell?

  2. Come modificare l'autorizzazione su un singolo file?

  3. Il miglior "distruggidocumenti" per rimuovere i file dal sistema.?

  4. Esame dei file Berkeley DB dalla CLI

  5. Lettura da un file in assembly

Copia i file nel terminale Linux

Sposta i file nel terminale Linux

I 6 modi migliori per visualizzare i file in Linux

Gestione file Linux dal terminale

Come modificare i file in base ai risultati del comando find

Come eliminare i file .fuse_hidden*?