Warum benötigt die Bash-Quelle das Ausführungsbit nicht?

57

Mit Bashs ist sourcees möglich, ein Skript ohne gesetztes Ausführungsbit auszuführen. Dies ist dokumentiertes und erwartetes Verhalten, aber ist dies nicht gegen die Verwendung eines Ausführungsbits?

Ich weiß, das sourceschafft keine Unterschale.

Motte001
quelle
2
Die Tatsache, dass chmodSie Berechtigungen (einschließlich `x) mit einer Oktalzahl festlegen können, gibt einen Hinweis darauf, aus welcher Ära sie stammt. Es würde mich nicht wundern, wenn es als schneller und schmutziger Indikator "Dies ist eine Binärdatei, die Sie ausführen können" aus den Tagen vor der
Erfindung von She
9
Wenn SUID ins Spiel kommt, werden unterschiedliche Schutzniveaus für verschiedene Benutzerkategorien wichtiger. Gehen Sie voran und lesen Sie mein SUID-Programm, wenn Sie möchten. Wenn Sie es jedoch durch einfaches Lesen ausführen, kommen die SUID-Kräfte nicht mit
am
@infixed Der Linux-Programmlader wird den shebang erst dann anschauen, wenn das Ausführungsbit gesetzt ist. (Um ein bisschen auf mein eigenes Horn zu hören: siehe hier .)
Kyle Strand
Sie können auch + xr haben, aber das ist etwas seltsam, weil es normalerweise möglich ist, die Binärdatei durch
Niklas B.
@KyleStrand durch „ wenn Sie es ausführen über es einfach zu lesen, die SUID Kräfte kommen nicht zusammen mit ihm“ Ich war etwas entlang der Linien von Vorstellungsvermögencp /sbin/suidexecutable /tmp/mycopy; /tmp/mycopy
Infix

Antworten:

36

Bash ist ein Dolmetscher; Es akzeptiert Eingaben und macht, was es will. Das ausführbare Bit muss nicht beachtet werden. Tatsächlich ist Bash portabel und kann auf Betriebssystemen und Dateisystemen ausgeführt werden, die kein Konzept für ein ausführbares Bit haben.

Was für das ausführbare Bit wichtig ist, ist der Betriebssystemkern. Wenn der Linux-Kernel execbeispielsweise prüft, dass das Dateisystem nicht mit einer noexecOption angehängt ist , prüft er das ausführbare Bit der Programmdatei und erzwingt alle Anforderungen, die von Sicherheitsmodulen (wie SELinux oder AppArmor) gestellt werden.

Beachten Sie, dass das ausführbare Bit eine eher diskretionäre Art der Steuerung ist. Auf einem Linux x86-64-System können Sie beispielsweise die Überprüfung des ausführbaren Bits durch den Kernel umgehen, indem Sie explizit /lib/x86_64-linux-gnu/ld-linux-x86-64.so.2als Interpreter aufrufen :

cp /bin/ls /tmp/
chmod -x /tmp/ls
/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 /tmp/ls

Dies ist etwas analog zur Beschaffung von Bash-Quellcode in Bash, außer dass dies ld.soder Interpreter ist und der Code, den er ausführt, Maschinencode im ELF-Format ist.

200_erfolg
quelle
3
Verwendung des Loaders als "Interpreter" für "Bytecode", der zufällig eine echte ausführbare Binärdatei ist ..... genial. Danke für das.
Kyle Strand
@KyleStrand Es kann mehrere Indirektionsebenen geben (der Unterschied zwischen dem gespeicherten Programm und dem geladenen Prozess und wie der Speicher zugeordnet ist, verschiedene Supervisors, VMs usw.), aber im Prinzip kann der Maschinencode direkt von der CPU ausgeführt werden (kein Mikrocode, usw.) und daher wird der Maschinencode nicht interpretiert: Die Hardware versteht ihn so, wie er ist - es ist die Muttersprache -, es sind keine Dolmetscher erforderlich.
jfs
2
@JFSebastian Ja, wir wissen, dass es sich um nativen Code handelt, daher steht "Interpreter" in Anführungszeichen. Die Aufgabe von ld.soist das dynamische Verknüpfen.
200_success
@JFSebastian Was 200_success gesagt hat. Das habe ich auch mit "real executable binary" gemeint und "bytecode" in Anführungszeichen gesetzt (da AFAIK "bytecode" normalerweise nicht verwendet wird, um auf tatsächlich kompilierten nativ ausführbaren Binärcode zu verweisen). Auch netter Benutzername.
Kyle Strand
@JFSebastian Ich glaube, dass moderne x86-ähnliche CPUs tatsächlich intern RISC sind, wobei der alte CISC-Befehlssatz im Wesentlichen die Mikrocode-Ausführung entsprechender RISC-Befehle antreibt, wobei ein CISC-Befehl die Ausführung vieler RISC-Befehle verursachen kann. In gewissem Sinne ist es also zumindest ein gültiges mentales Modell, zu bezeichnen, was die CPU mit dem RISC-Maschinencode "interpretieren" macht, wenn dies technisch nicht völlig korrekt ist. AES-NI ist wahrscheinlich eines der extremeren Beispiele: ein CISC-Befehl pro AES-Runde!
ein CVn
57

sourceoder das Äquivalent , aber Standard - Punkt. nicht ausführen das Skript, aber lesen Sie die Befehle aus Skriptdatei, dann führen sie, Zeile für Zeile, in der aktuellen Shell - Umgebung.

Es spricht nichts gegen die Verwendung des Ausführungsbits, da die Shell nur Leseberechtigungen benötigt , um den Inhalt der Datei zu lesen.

Das Ausführungsbit wird nur benötigt, wenn Sie das Skript ausführen . Hier wird die Shell einen fork()neuen Prozess execve()ausführen und dann mithilfe der Funktion ein neues Prozessabbild aus dem Skript erstellen, das eine reguläre ausführbare Datei sein muss.

cuonglm
quelle
5
@alexis: Ich bin mir nicht sicher, ob ich wirklich folge. Wenn Sie dies tun bash < script, erhalten Sie im Wesentlichen das gleiche Ergebnis wie source script. Welchen Schutz bietet eine Ausführungsbitprüfung?
Auffälliger Compiler
27
@alexis, es ist nicht die Aufgabe eines Interpreters, die Berechtigungen der von ihm interpretierten Skripte zu überprüfen. Das macht nichts - nicht Python, nicht Ruby, nicht die Java Virtual Machine, nicht andere zufällige Shells. Das Ausführungsbit steuert, ob die OS execv* -Familie von Systemaufrufen mit einer ausführbaren Datei verwendet werden kann, nicht, ob sie von einem Interpreter ausgeführt wird. Warum Menschen verwirren (und die Fähigkeit zum Bewerten von aus Nicht-Datei-Quellen gestreamtem Code beeinträchtigen), indem Konventionen verletzt werden?
Charles Duffy
14
@alexis, ... außerdem gibt es eine wertvolle Bedeutung für eine Shell-Bibliothek, die nicht ausführbar ist: "Ich bin eine Bibliothek, kein Befehl - Quelle, führe mich nicht aus". Andernfalls müssen Sie Code schreiben, um den Missbrauch von Code zu erkennen und zu beheben, der nur als Quelle dient. Wenn Sie jedoch nicht über die Berechtigung + x verfügen, können Sie sicherstellen, dass Benutzer eine Bibliothek nicht auf diese Weise missbrauchen können (wollen).
Charles Duffy
6
@alexis "es war eine Entscheidung der Autoren" Nur in dem Sinne, dass jedes andere mögliche Stück Code, das nicht enthalten war, eine Entscheidung war. Die Shell öffnet die Datei zum Lesen, um die Befehle daraus auszulesen. Ich würde nicht erwarten, dass es nach Leseberechtigungen sucht. Es wird nur versucht, die Datei zu öffnen, und es schlägt fehl, wenn dies nicht möglich ist. Ebenso wird nicht nach Schreib- oder Ausführungsberechtigungen gesucht, da diese für das Lesen der Datei nicht relevant sind.
Randy Orrison
2
@alexis Dies wird in der Praxis verwendet, zum Beispiel bei Pythons virtualenv. Das Skript zur Aktivierung dieses Skripts ist dafür vorgesehen, dass es aus dem Quellcode stammt und nicht ausgeführt wird. Es bin/activateverfügt daher nicht über ein ausführbares Bit. Skripte können Bibliotheken oder ähnliche Dinge sein. Ich denke, .sh zu haben könnte auch ein Signal sein, aber ein Minimum an ./bin/activate. bin/activate
Fußgewehren zu haben
20

Das ausführbare Bit (im Gegensatz zum Rest) für nicht-setuid- und nicht-setguid-Dateien ist kein wirklicher Sicherheitsmechanismus. Alles, was Sie lesen können, können Sie indirekt ausführen, und Linux lässt Sie indirekt alles lesen, was Sie ausführen können, aber nicht direkt lesen (das sollte ausreichen, um ein Loch in das Konzept von non-set (g) uid x-bit als a zu schlagen Sicherheitsmaßnahme).

Es ist eher eine praktische Sache: Lassen Sie das System es direkt für mich ausführen, wenn das Bit gesetzt ist, andernfalls muss ich es indirekt ausführen ( bash the_script;oder etwas hacken, um das Speicher-Image einer ausführbaren Datei ohne Leseberechtigung zu erhalten ).

Sie können es bequem einstellen, wenn Sie beabsichtigen, Ihr Insourcable sowohl in der Quelle als auch in der Ausführung auszuführen.

Offensichtlich teilen jedoch viele Implementierer von gemeinsam genutzten Bibliotheken Ihre Meinung und folglich erfordern viele Systeme, dass gemeinsam genutzte Bibliotheken, die im Wesentlichen das native Äquivalent von Shell-Insourcables sind, als ausführbar markiert werden, um verwendbar zu sein. Siehe Warum können gemeinsam genutzte Bibliotheken ausgeführt werden? .

PSkocik
quelle
3
@ Motte001 Diese Anhänge können sie ausführen, wenn sie es wirklich wollen. Es ist eine Annehmlichkeit.
PSkocik
2
Das ausführbare Bit dient nicht der Sicherheit: Wenn ich eine Datei besitze, kann ich sie frei chmodausführen. Es dient zum Sortieren von Daten aus Programmen, daher ist die Frage des OP eine vernünftige.
Alexis
1
@ Motte001 Das ist eher eine Sicherheitsfunktion des GUI-Dateibrowsers / der E-Mail-Anwendung - es kann leicht entschieden werden, dass ein Doppelklick auf eine Datei, deren Name auf ".sh" endet, in einem Terminal ausgeführt wird (Windows-Stil) oder umgekehrt. Wenn Sie auf eine Datei im Verzeichnis "Heruntergeladene Anhänge" klicken, wird eine integrierte Sandbox-Vorschau-App aufgerufen. Das xBit ist nur ein zusätzlicher Ort, an dem es einen Hinweis darauf lesen / schreiben kann, was zu tun ist.
IMSoP
3
Ein Grund, warum wir das ausführbare Bit benötigen, besteht darin, setuid-Programme auszuführen, insbesondere jene, die root gehören. Sie können sie zwar auf eigene Faust ausführen, das Betriebssystem muss sie jedoch ausführen, damit sie über die erforderlichen Berechtigungen verfügen. In einigen anderen Fällen ist es nur eine Annehmlichkeit.
Waleed Khan
2
"Linux lässt Sie alles lesen, was Sie über / proc ausführen können" - Nun, mein /tmp$ cp /bin/cat ./cat ; chmod a-rw ./cat ; ./cat & cp /proc/$!/exe /tmp/cat2cp: cannot stat ‘/proc/16260/exe’: Permission denied
aktueller
9

Das ist eine gute Frage! Unix verwendet das ausführbare Bit, um zwischen Programmen und Daten zu unterscheiden. Das Betriebssystem benötigt das Ausführungsbit nicht, da kein bezogenes Skript zur Ausführung als neuer Prozess an das Betriebssystem übergeben wird. Die Shell behandelt ein bezogenes Skript jedoch als Programm und sucht $PATHnach der Datei, die Sie als Quelle verwenden möchten. Die Shell selbst hätte also Ausführungsberechtigungen für Quelldateien benötigen können. aber das tat es nicht.

Die Frage muss längst aufgetaucht sein. Das Design der Bourne-Shell war das Ergebnis einer "langen Abfolge von Modifikationen, Dialogen und Diskussionen" unter den Bewohnern von Bell Labs, und viele Designentscheidungen wurden im Laufe der Jahre von SR Bourne und anderen diskutiert. Leider fand mein kurzer Blick keine Diskussion über das Quellfeature (zu meiner Verteidigung ist es schwer, darauf zu googeln). Was ich gefunden habe, ist das "." Der Befehl wird in dieser frühen Einführung in die Shell von Bourne selbst nicht angezeigt, ist jedoch in der ausgereifteren Version 7 enthalten .

Abwesende Autorität, hier ist meine eigene Interpretation:

  1. Der .Befehl, auch bekannt als source, wird in Textform (wie #includeim C-Präprozessor) in den Quellcode des ausführenden Skripts oder der interaktiven Sitzung eingefügt. Daher wird die enthaltene Datei möglicherweise nicht "ausgeführt".

  2. Die Unix-Philosophie war es schon immer, den Programmierern genügend Seile zum Aufhängen zu geben. Zu viel Händchenhalten und willkürliche Einschränkungen stehen einfach im Weg. Einige Distributionen rm -r /weigern sich erst vor kurzem, das zu tun, wonach Sie fragen. (Dieser Befehl weist Sie rman, alles auf Ihrem Computer zu löschen. Versuchen Sie es nicht als root! Oder besser noch gar nicht.) Also, vielleicht Bourne at al. Ich habe gerade entschieden, dass Sie beim Versuch, eine Datei zu erstellen, wissen müssen, was Sie tun. Das vermeidet auch unnötige Arbeit und Zyklen waren damals sehr wichtig.

alexis
quelle
Aber man sollte auf keinen Fall das tun, was @cat gesagt hat.
TOOGAM
Ich bin überrascht, dass @TOOGAM nicht markiert und gelöscht wurde, aber ich habe das / s eingegeben!
Katze
Dort weiß ich nicht, was @cat geschrieben hat, aber ich habe die Antwort noch kindersicherer gemacht. (Aber komm schon, es war schon aus dem Zusammenhang klar genug.)
Alexis
4

Für das Betriebssystem besteht eine Datei, die ein Shell-Skript enthält, nur aus Daten. Wenn Sie den Namen einer solchen Datendatei an den sourceBefehl übergeben oder in der Befehlszeile an einen Aufruf der Bash-Shell übergeben, sieht das Betriebssystem nur eine Zeichenfolge, die zufällig mit dem Namen einer Datei übereinstimmt, die Daten enthält.

Wie wäre das Ausführungsbit in diesem Fall überhaupt relevant?

Stephen M. Webb
quelle
3

Die Unterscheidung ist wichtig, da Sie möglicherweise eine Datei mit Shell-Befehlen haben, die nicht als ausführbare Datei, sondern nur als Quelle nützlich ist. Für diese Datei können Sie das Ausführungsbit ausschalten und dann wird nur dann darauf zugegriffen, wenn dies ausdrücklich in einem Quellbefehl angegeben ist. Der Grund für so etwas ist, dass es Nebenwirkungen auf die Shell hat, von der aus es ausgeführt wird. Für ein konkretes Beispiel habe ich ein Skript namens fix_path, das den Pfad betrachtet und ändert.

KARTE
quelle
1

Nur für den Fall, dass jemand Interesse an weiteren Studien und / oder Erläuterungen hat: In einer vor einiger Zeit implementierten, nahezu POSIX-konformen Shell sind die internen Abläufe der Funktionen 'exec_program ()' und 'builtin_source ()' sehr vorbildlich. In diesen Funktionen sehen Sie genau, was der Unterschied zwischen ihnen ist:

https://github.com/rsenn/shish/blob/master/src/builtin/builtin_source.c

https://github.com/rsenn/shish/blob/master/src/exec/exec_program.c

Im Grunde kann Sourcing als die Shell angesehen werden, die ihren internen Dateideskriptor vorübergehend umleitet, von wo aus sie das Shell-Skript analysiert (das Terminal im interaktiven Modus). es ist also sehr ähnlich zu anderen Umleitungen wie <input_file.txtund >>append_to_something.listund diese müssen nur Dateien öffnen und schließen.

Die Ausführung erfolgt also durch den execve()Systemaufruf, für den das Ausführungsbit obligatorisch ist.

Ich erinnere mich, dass ich einige Systeme gesehen habe, die die Ausführung von ELF / a.out-Binärdateien erlauben, aber über die Ausführung von "/lib/ld-dynamic-linker.so" und mit dem Binärprogramm (ohne exec-Bit) als erstes Argument. Ich glaube, das war auf einigen DEC Alpha oder VAX Maschinen (Könnte es SCO Unix gewesen sein?)

rsenn
quelle
-2

Eine andere Sicht:

Quellenskript besteht im Wesentlichen aus Shell-Buildins und Programmaufrufen. Shell-Builtins ( sourcedarunter) sind Teile der Shell und die Shell muss an erster Stelle ausführbar sein. Für jedes aufgerufene Programm (also ELF, ein anderes Skript mit shebang, was auch immer) muss das Ausführungsbit gesetzt sein, sonst wird es nicht ausgeführt.

Es ist also nicht gegen die Verwendung eines Ausführungsbits, da nichts ohne Ausführungsbit ausgeführt wird. Die Überprüfung wird nicht für das gesamte Quellenskript durchgeführt. es wird für jeden Teil separat durchgeführt, aber es ist.

Kamil Maciorowski
quelle
Shell-Buildins werden nicht aus einem Shell-Skript bezogen. Normalerweise sind sie Teil der ausführbaren Shell-Datei. In ksh93, zsh und einigen anderen Shells können sie Shell-Erweiterungen sein.
Fpmurphy
@ fpmurphy1 Ist das nicht mein Satz "Shell Builtins (...) sind Teile der Shell"?
Kamil Maciorowski