Kann jemand im Detail erklären, was mit dem Folgenden los ist. Stellen wir uns vor, ich mounte ein Verzeichnis mit der folgenden noexec
Option:
mount -o noexec /dev/mapper/fedora-data /data
Um dies zu überprüfen, lief ich mount | grep data
:
/dev/mapper/fedora-data on /data type ext4 (rw,noexec,relatime,seclabel,data=ordered)
Jetzt /data
erstelle ich ein einfaches Skript mit dem Namen hello_world
:
#!/bin/bash
echo "Hello World"
whoami
Also habe ich das Skript ausführbar gemacht von chmod u+x hello_world
(dies hat jedoch keine Auswirkungen auf ein Dateisystem mit noexec
Optionen) und versucht, es auszuführen :
# ./hello_world
-bash: ./hello_world: Permission denied
Das Voranstellen bash
der Datei ergibt jedoch Folgendes :
# bash hello_world
Hello World
root
Also habe ich eine einfache hello_world.c
mit folgenden Inhalten erstellt:
#include <stdio.h>
int main()
{
printf("Hello World\n");
return 0;
}
Kompiliert mit cc -o hello_world hello_world.c
Jetzt läuft:
# ./hello_world
-bash: ./hello_world: Permission denied
Also habe ich versucht, es mit auszuführen
/lib64/ld-linux-x86-64.so.2 hello_world
Der Fehler:
./hello_world: error while loading shared libraries: ./hello_world: failed to map segment from shared object: Operation not permitted
Dies ist natürlich wahr, da ldd
Folgendes zurückgegeben wird:
ldd hello_world
ldd: warning: you do not have execution permission for `./hello_world'
not a dynamic executable
Auf einem anderen System, auf dem die noexec
Mount-Option nicht angewendet wird, wird Folgendes angezeigt:
ldd hello_world
linux-vdso.so.1 (0x00007ffc1c127000)
libc.so.6 => /lib64/libc.so.6 (0x00007facd9d5a000)
/lib64/ld-linux-x86-64.so.2 (0x00007facd9f3e000)
Meine Frage lautet nun: Warum funktioniert das Ausführen eines Bash-Skripts auf einem Dateisystem mit noexec
Option, jedoch nicht auf einem c
kompilierten Programm? Was passiert unter der Haube?
chmod o+x «filename»
Erteilt dem Benutzer oder der Gruppe, die die Datei besitzt, keine Ausführungsberechtigung. Verwenden Siechmod ugo+x «filename»
oderchmod +x «filename»
chmod u+x hello_world
aber vergessen, das in der Frage zu ändern. Vielen Dank für den Hinweis.Antworten:
Was in beiden Fällen passiert, ist dasselbe: Um eine Datei direkt auszuführen, muss das Ausführungsbit gesetzt werden und das Dateisystem kann noexec nicht gemountet werden. Aber diese Dinge hindern nichts daran , diese Dateien zu lesen .
Wenn das Bash-Skript als ausgeführt wird
./hello_world
und die Datei nicht ausführbar ist (entweder kein Exec-Berechtigungsbit oder noexec im Dateisystem), wird die#!
Zeile nicht einmal überprüft , da das System die Datei nicht einmal lädt. Das Skript wird niemals im relevanten Sinne "ausgeführt".Im Fall von
bash ./hello_world
, na ja, die Option noexec-Dateisystem ist einfach nicht so intelligent, wie Sie es gerne hätten. Derbash
Befehl, der ausgeführt wird/bin/bash
, ist und/bin
befindet sich nicht in einem Dateisystem mitnoexec
. Es läuft also kein Problem. Dem System ist es egal, dass Bash (oder Python oder Perl oder was auch immer) ein Interpreter ist. Es wird nur der Befehl ausgeführt, den Sie (/bin/bash
) mit dem Argument gegeben haben, das zufällig eine Datei ist. Im Fall von Bash oder einer anderen Shell enthält diese Datei eine Liste der auszuführenden Befehle, aber jetzt haben wir alles "hinter uns", was die Dateiausführungsbits überprüfen soll. Diese Überprüfung ist nicht verantwortlich für das, was später passiert.Betrachten Sie diesen Fall:
… Oder für diejenigen, die den sinnlosen Gebrauch von Katzen nicht mögen:
Die "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. Dieser Artikel von LWN.net ist möglicherweise hilfreich: Wie Programme ausgeführt werden .quelle
/bin/bash
die im Dateisystem ohne gespeichert wirdnoexec
, während sich das OP-Skript imnoexec
Dateisystem befindet.In früheren Antworten wird erläutert, warum die
noexec
Einstellung die Ausführung eines Skripts nicht verhindert, wenn der Interpreter (in Ihrem Fall/bin/bash
) explizit über die Befehlszeile aufgerufen wird. Aber wenn das alles gewesen wäre, hätte dieser Befehl auch funktioniert:Und wie Sie bemerkt haben, funktioniert das nicht. Das liegt daran, dass es auch
noexec
einen anderen Effekt hat. Der Kernel lässt keinePROT_EXEC
aktivierten Speicherdateien von diesem Dateisystem zu, wenn diese aktiviert sind.Speicherzuordnungsdateien werden in mehreren Szenarien verwendet. Die beiden häufigsten Szenarien betreffen ausführbare Dateien und Bibliotheken. Wenn ein Programm mit dem
execve
Systemaufruf gestartet wird, erstellt der Kernel intern Speicherzuordnungen für den Linker und die ausführbare Datei. Alle anderen benötigten Bibliotheken werden vom Linker über denmmap
Systemaufruf mitPROT_EXEC
aktiviertem Speicher zugeordnet . Wenn Sie versuchen, eine Bibliothek aus einem Dateisystem mitnoexec
dem Kernel zu verwenden, wird dermmap
Aufruf abgelehnt .Wenn Sie
/lib64/ld-linux-x86-64.so.2 hello_world
denexecve
Systemaufruf aufrufen, wird nur eine Speicherzuordnung für den Linker erstellt, und der Linker öffnet diehello_world
ausführbare Datei und versucht, eine Speicherzuordnung auf die gleiche Weise zu erstellen, wie dies für eine Bibliothek der Fall gewesen wäre. Und an diesem Punkt weigert sich der Kernel, denmmap
Aufruf auszuführen , und Sie erhalten den Fehler:Die
noexec
Einstellung ermöglicht weiterhin Speicherzuordnungen ohne Ausführungsberechtigung (wie dies manchmal für Datendateien verwendet wird) und ermöglicht auch das normale Lesen von Dateien, weshalb diesbash hello_world
für Sie funktioniert hat.quelle
Befehl auf folgende Weise ausführen:
Sie
bash
lesen aus einer Dateihello_world
(was nicht verboten ist).In anderen Fällen versucht das Betriebssystem, diese Datei auszuführen,
hello_world
und schlägt aufgrund desnoexec
Flags fehlquelle
./hello_world
würde also das gleiche Recht bedeuten oder verpasse ich hier den Punkt?Wenn Sie das Skript über Bash ausführen, liest es nur die Datei ein und interpretiert sie.
Wenn Sie jedoch den Namen an den Kernel übergeben, wird die Datei wirklich auf "#!" und lädt den gemäß der Kerneloption "CONFIG_BINFMT_SCRIPT" angegebenen Interpreter. Es sagt:
Das Obige ist der Hilfetext, der dieser Option zugeordnet ist. Für einen weiteren interessanten Unterschied. Ich habe mein Drehbuch geschrieben:
Wenn Sie es mit bash ausführen, wird immer noch der Bash-Interpreter ausgeführt:
Der Kernel tut jetzt jedoch:
Der Kernel druckte das Skript einschließlich der ersten Zeile aus, da es 'cat' hieß.
Im Fall des C-Programms rufen Sie keinen Interpreter auf, um die Binärdatei auszuführen. Der Kernel versucht es direkt auszuführen. Wenn Sie Ihre gesamte ausführbare Datei mit einigen Debuggern in den Speicher geladen haben, können Sie Ihr Programm dennoch "ausführen", während es über den Debugger geladen wird.
Die Option 'noexec' ist wie das Ausschalten des Ausführungsbits in Ihrer Binärdatei und verhindert, dass der Kernel die Binärdatei "nativ" ausführt.
Dies macht übrigens einen Unterschied, wenn für Ihr Programm ein SetUID-Bit im Programm gesetzt war. Wenn Sie es mit einem Interpreter laden, wird Ihre UID nicht festgelegt. Nur wenn der Kernel sie lädt, kann dieses Privileg aktiviert werden.
FWIW - Windows hat den gleichen Mechanismus.
Wenn Sie ".sh" als "ausführbares Suffix" wie ".exe" oder ".vbs" hinzufügen, führt Windows Ihre Datei automatisch aus, je nachdem, wie Sie die auszuführenden ".sh" -Dateien eingerichtet haben. Theoretisch könnten Sie ".txt" -Dateien so einrichten, dass sie automatisch eingegeben werden, wenn Sie ihren Namen in die Befehlszeile eingeben.
Ebenso können Sie ein Programm kurz aufrufen, um Textdateien auf dem Bildschirm auszudrucken. Dies ist ein Grund, sich nicht an einem öffentlichen Ort angemeldet zu lassen.
quelle
Weil sich die ausführbare Bash-Datei nicht auf dem Dateisystem befindet.
quelle
./hello_world
würde auch uns,/bin/bash
die sich nicht auf einem Dateisystem mitnoexec
aktivierter Option befinden. Wenn das wahr istc
, würde das Programm auch korrekt ausgeführt werden?In diesem Dokument erfahren Sie, warum
https://chromium.googlesource.com/chromiumos/docs/+/master/security/noexec_shell_scripts.md
und
Natürlich ist ein anderer Weg:
oder
quelle