Angenommen, eine Shell-Funktion foo
wird in der aktuellen Shell-Session definiert. Dann der Befehl
typeset -f foo
gibt den Quellcode dieser Funktion aus. Das bedeutet, dass man diese Funktion zumindest prinzipiell per ssh
auf einem entfernten Host ausführen kann wie unten gezeigt:
ssh <REMOTE-HOST> "$(typeset -f foo); foo"
(Für die Zwecke dieser Frage gehen Sie davon aus, dass alle Befehle und Dateisystempfade, die von foo
erwähnt werden sind in <REMOTE-HOST>
verfügbar . Nehmen Sie außerdem an, dass bash
ist die Schale an beiden Enden.)
Mein Instinkt ist, dass die blinde Beschaffung von automatisch generiertem Quellcode wie diesem extrem zerbrechlich wäre, aber ich konnte kein Beispiel für eine Funktion foo
finden wo diese Redewendung versagt.
Meine Frage ist:Wie sicher ist diese Redewendung? Wenn es nicht sicher ist, kann mir jemand ein konkretes Beispiel geben, das veranschaulicht, wie es fehlschlägt? (Die Sicherheitsfrage beinhaltet folgendes:tut bash
garantieren, dass solche Verwendungen von typeset -f
sind sicher?)
Hinweis: In diesem Beitrag suche ich nicht nach Alternativen; Ich möchte nur die Eigenschaften dieses speziellen Idioms verstehen.
BEARBEITEN:klargestellt, dass bash
ist die Schale an beiden Enden.
Akzeptierte Antwort:
Es ist nicht sicher, wenn der Code nicht in demselben Gebietsschema interpretiert wird, in dem es generiert wurde (oder wenn das Gebietsschema name ist die gleiche, aber die Definition dieses Gebietsschemas unterscheidet sich zwischen dem ssh-Client-Host und dem Server-Host).
Besonders wichtig ist die Kodierung von Zeichen und die Zugehörigkeit von Zeichen zum blank
, alpha
und alnum
Kategorien.
Zum Beispiel α
Zeichen (griechischer Kleinbuchstabe Alpha) im BIG5-Zeichensatz wird als 0xa3 0x5c codiert, wobei 0x5c ist in ASCII (und allen Zeichensätzen einschließlich BIG5).
Wenn Sie also einen foo
haben Funktion, die in diesem Zeichensatz definiert ist als:
foo() {
echo α
}
typeset -f
wird es als solches ausgeben, aber wenn es in einem anderen Gebietsschema wie C interpretiert würde, würde dieses 0xa3 0x5c nicht als α
genommen werden sondern als unbekanntes 0xa3-Zeichen gefolgt von einem Backslash. Das kann ausgenutzt werden wie mit:
$ env LC_ALL=zh_TW.big5 $'BASH_FUNC_foo%%=() { echo xa3\\;}; echo gotcha; }' bash -c 'typeset -f foo' | bash
gotcha
bash: line 5: syntax error near unexpected token `}'
bash: line 5: `}'
Der foo() { echo α;}; echo gotcha; }
wurde foo() { echo <0xa3>\; }; echo gotcha; }
wenn sie in einem anderen Gebietsschema interpretiert werden.
Andere Probleme:
Der à
Zeichen in UTF-8 wird als 0xc3 0xa0 codiert. In iso8859-1 und mehreren anderen iso8859
Zeichensätze, 0xa0 ist das geschützte Leerzeichen. Auf einigen Systemen ist dieses Zeichen im Leerzeichen enthalten Zeichenklasse, die von der Bash als Token-Trennzeichen in ihrer Syntax geehrt wird.
Solaris ist ein solches System, bei dem U+00A0 als Leerzeichen betrachtet wird:
$ env $'BASH_FUNC_foo%%=() { nawk -v x=àBEGIN'{system("echo gotcha")}' 1;}' bash -c 'typeset -f foo; echo foo' | ssh solaris LC_ALL=en_GB.ISO8859-1 bash
gotcha
Sehen Sie, wie die:
nawk -v x=àBEGIN... 1
wurde interpretiert als:
nawk -v x=<0xc3> 'BEGIN{system("...")}' 1
Beachten Sie, dass, wenn die Funktion in einem Gebietsschema definiert wurde, in dem 0xa0 kein Leerzeichen war oder in dem 0xa3 0x5c Alpha war, typeset -f
wird es immer noch gleich ausgeben, selbst wenn es in einem Gebietsschema aufgerufen wird, in dem es ein Leerzeichen ist (erzeugt eine andere Ausgabe, wenn es interpretiert wird)
$ LC_ALL=zh_TW.big5 bash -c $'f() { echo xa3x5c$(uname); }; export LC_ALL=C; typeset -f f | bash'
bash: line 3: syntax error near unexpected token `('
bash: line 3: ` echo �$(uname)'
Allgemeiner gesagt, die Ausgabe von typeset
, alias
, export -p
, set
, locale
sind alle gemeint für die Neueingabe in eine Shell geeignet sein, aber abgesehen von diesen Gebietsschemaproblemen sind verschiedene Implementierungen dafür bekannt, dass sie mehrere Probleme haben, und ich wäre nicht überrascht, wenn es noch viele weitere gäbe.
Also, ja, ich stimme zu, dass Sie es zu Recht für gefährlich halten, und es ist eine gute Idee, sie nur in einem Kontext zu verwenden, in dem Sie wissen, woher die ausgegebenen Daten stammen. Zum Beispiel im Fall von typeset -f foo
, verwenden Sie es nur auf einem foo
Funktion, die Sie definiert haben (und vermeiden Sie die Verwendung von Nicht-ASCII-Zeichen darin).