Ciò che accade in entrambi i casi è lo stesso:per eseguire direttamente un file, è necessario impostare il bit di esecuzione e il filesystem non può essere montato noexec. Ma queste cose non impediscono a nulla di leggere quei file.
Quando lo script bash viene eseguito come ./hello_world
e il file non è eseguibile (nessun bit di autorizzazione exec o noexec sul filesystem), il #!
la riga non è nemmeno selezionata , perché il sistema non carica nemmeno il file. Lo script non viene mai "eseguito" nel senso pertinente.
Nel caso di bash ./hello_world
, beh, l'opzione del filesystem noexec semplicemente non è così intelligente come vorresti che fosse. Il bash
il comando eseguito è /bin/bash
e /bin
non è su un filesystem con noexec
. Quindi, non funziona nessun problema. Al sistema non importa che bash (o python o perl o altro) sia un interprete. Esegue semplicemente il comando che hai dato (/bin/bash
) con l'argomento che risulta essere un file. Nel caso di bash o di un'altra shell, quel file contiene un elenco di comandi da eseguire, ma ora abbiamo "superato" tutto ciò che controllerà i bit di esecuzione del file. Quell'assegno non è responsabile di ciò che accade dopo.
Considera questo caso:
$ cat hello_world | /bin/bash
… o per coloro a cui non piace l'uso inutile del gatto:
$ /bin/bash < hello_world
Lo "shbang" #!
sequence all'inizio di un file è solo una bella magia per fare efficacemente la stessa cosa quando si tenta di eseguire il file come comando. Potresti trovare utile questo articolo di LWN.net:Come vengono eseguiti i programmi.
Le risposte precedenti spiegano perché noexec
L'impostazione non impedisce l'esecuzione di uno script quando l'interprete (nel tuo caso /bin/bash
) viene chiamato in modo esplicito dalla riga di comando. Ma se fosse tutto qui, anche questo comando avrebbe funzionato:
/lib64/ld-linux-x86-64.so.2 hello_world
E come hai notato, non funziona. Questo perché noexec
ha anche un altro effetto. Il kernel non consentirà file mappati in memoria da quel file system con PROT_EXEC
abilitato.
I file mappati in memoria vengono utilizzati in più scenari. I due scenari più comuni riguardano gli eseguibili e le librerie. Quando un programma viene avviato utilizzando il execve
chiamata di sistema, il kernel creerà internamente mappature di memoria per il linker e l'eseguibile. Tutte le altre librerie necessarie sono mappate in memoria dal linker tramite mmap
chiamata di sistema con PROT_EXEC
abilitato. Se hai provato a usare una libreria da un filesystem con noexec
il kernel si rifiuterebbe di eseguire il mmap
chiama.
Quando hai invocato /lib64/ld-linux-x86-64.so.2 hello_world
il execve
la chiamata di sistema creerà solo una mappatura della memoria per il linker e il linker aprirà il hello_world
eseguibile e tenta di creare una mappatura della memoria più o meno nello stesso modo in cui avrebbe fatto per una libreria. E questo è il punto in cui il kernel si rifiuta di eseguire il mmap
chiama e ricevi l'errore:
./hello_world: error while loading shared libraries: ./hello_world: failed to map segment from shared object: Operation not permitted
Il noexec
l'impostazione consente ancora la mappatura della memoria senza il permesso di esecuzione (come talvolta viene utilizzato per i file di dati) e consente anche la normale lettura dei file, motivo per cui bash hello_world
ha funzionato per te.
Esecuzione del comando in questo modo:
bash hello_world
fai bash
letto dal file hello_world
(che non è proibito).
In altri casi il sistema operativo tenta di eseguire questo file hello_world
e fallisce a causa di noexec
bandiera