Was in beiden Fällen passiert, ist dasselbe:Um eine Datei direkt auszuführen, muss das Ausführungsbit gesetzt werden, und das Dateisystem kann nicht mit noexec gemountet werden. Aber diese Dinge halten nichts vom Lesen ab diese Dateien.
Wenn das Bash-Skript als ./hello_world
ausgeführt wird und die Datei nicht ausführbar ist (entweder kein exec-Berechtigungsbit oder noexec im Dateisystem), #!
Zeile wird nicht einmal überprüft , weil das System die Datei nicht einmal lädt. Das Skript wird niemals im eigentlichen Sinne "ausgeführt".
Im Fall von bash ./hello_world
, nun, die noexec-Dateisystemoption ist einfach nicht so schlau, wie Sie es gerne hätten. Die bash
Der ausgeführte Befehl ist /bin/bash
, und /bin
befindet sich nicht auf einem Dateisystem mit noexec
. Also läuft er ohne Probleme. Dem System ist es egal, dass Bash (oder Python oder Perl oder was auch immer) ein Interpreter ist. Es führt einfach den von Ihnen gegebenen Befehl aus (/bin/bash
) mit dem Argument, das zufällig eine Datei ist. Im Fall von Bash oder einer anderen Shell enthält diese Datei eine Liste von auszuführenden Befehlen, aber jetzt sind wir an allem vorbei, was Dateiausführungsbits überprüfen wird. Diese Prüfung ist nicht verantwortlich für das, was später passiert.
Betrachten Sie diesen Fall:
$ cat hello_world | /bin/bash
… oder für diejenigen, die Pointless Use of Cat nicht mögen:
$ /bin/bash < hello_world
Der "shbang" #!
Sequenz am Anfang einer Datei ist nur eine nette Magie, um effektiv dasselbe zu tun, wenn Sie versuchen, die Datei als Befehl auszuführen. Vielleicht finden Sie diesen LWN.net-Artikel hilfreich:Wie Programme ausgeführt werden.
Vorherige Antworten erklären, warum die noexec
Die Einstellung verhindert nicht, dass ein Skript ausgeführt wird, wenn der Interpreter (in Ihrem Fall /bin/bash
) wird explizit von der Befehlszeile aus aufgerufen. Aber wenn das alles gewesen wäre, hätte dieser Befehl auch funktioniert:
/lib64/ld-linux-x86-64.so.2 hello_world
Und wie du schon bemerkt hast, geht das nicht. Das liegt daran, dass noexec
hat noch eine andere Wirkung. Der Kernel erlaubt keine speicherabgebildeten Dateien von diesem Dateisystem mit PROT_EXEC
aktiviert.
Speicherabgebildete Dateien werden in mehreren Szenarien verwendet. Die beiden häufigsten Szenarien betreffen ausführbare Dateien und Bibliotheken. Wenn ein Programm mit execve
gestartet wird Systemaufruf erstellt der Kernel intern Speicherzuordnungen für den Linker und die ausführbare Datei. Alle anderen benötigten Bibliotheken werden vom Linker über mmap
im Speicher abgebildet Systemaufruf mit PROT_EXEC
aktiviert. Wenn Sie versucht haben, eine Bibliothek aus einem Dateisystem mit noexec
zu verwenden der Kernel würde sich weigern, mmap
auszuführen anrufen.
Wenn Sie /lib64/ld-linux-x86-64.so.2 hello_world
aufgerufen haben die execve
Der Systemaufruf erstellt nur eine Speicherzuordnung für den Linker und der Linker öffnet den hello_world
ausführbar und versuchen Sie, eine Speicherzuordnung auf ziemlich dieselbe Weise zu erstellen, wie Sie es für eine Bibliothek getan hätten. Und das ist der Punkt, an dem der Kernel sich weigert, mmap
auszuführen aufrufen und Sie erhalten den Fehler:
./hello_world: error while loading shared libraries: ./hello_world: failed to map segment from shared object: Operation not permitted
Die noexec
Die Einstellung erlaubt immer noch Speicherzuordnungen ohne Ausführungsberechtigung (wie sie manchmal für Datendateien verwendet wird) und erlaubt auch das normale Lesen von Dateien, weshalb bash hello_world
für Sie gearbeitet.
Befehl auf diese Weise ausführen:
bash hello_world
Sie machen bash
aus Datei hello_world
lesen (was nicht verboten ist).
In anderen Fällen versucht das Betriebssystem, diese Datei hello_world
auszuführen und wegen noexec
fehlschlagen Flagge