Supposons qu'une fonction shell foo
est défini dans la session shell en cours. Puis la commande
typeset -f foo
affiche le code source de cette fonction. Cela signifie que, au moins en principe, on peut exécuter cette fonction sur un hôte distant via ssh
comme indiqué ci-dessous :
ssh <REMOTE-HOST> "$(typeset -f foo); foo"
(Pour les besoins de cette question, supposons que toutes les commandes et les chemins de système de fichiers mentionnés par foo
sont disponibles dans <REMOTE-HOST>
. Supposons également que bash
est la coque aux deux extrémités.)
Mon instinct est qu'il serait extrêmement fragile de trouver aveuglément du code source généré automatiquement comme celui-ci, mais je n'ai pas été en mesure de trouver un exemple de fonction foo
où cet idiome échoue.
Ma question est :à quel point cet idiome est-il sûr ? Si ce n'est pas sûr, quelqu'un peut-il me donner un exemple concret qui illustre comment cela échoue ? (La question de la sécurité comprend les éléments suivants :est-ce que bash
garantir que de telles utilisations de typeset -f
sont en sécurité ?)
NB : Dans ce post, je ne cherche pas d'alternatives; Je veux juste comprendre les propriétés de cet idiome particulier.
EDIT :a précisé que bash
est la coquille aux deux extrémités.
Réponse acceptée :
Ce n'est pas sûr si le code n'est pas interprété dans la même locale que celle où il a été généré (ou si la locale nom est le même mais la définition de cette locale diffère entre l'hôte du client ssh et l'hôte du serveur).
L'encodage des caractères et l'appartenance des caractères dans le blank
sont particulièrement importants. , alpha
et alnum
catégories.
Par exemple, le α
caractère (lettre grecque minuscule alpha) dans le jeu de caractères BIG5 est codé comme 0xa3 0x5c, 0x5c étant en ASCII (et tous les jeux de caractères y compris BIG5).
Donc, si vous avez un foo
fonction définie dans ce jeu de caractères comme :
foo() {
echo α
}
typeset -f
le sortira comme tel, mais s'il est interprété dans une locale différente comme C, ce 0xa3 0x5c ne sera pas considéré comme un α
mais comme un caractère 0xa3 inconnu suivi d'une barre oblique inverse. Cela peut être exploité comme avec :
$ 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: `}'
Le foo() { echo α;}; echo gotcha; }
est devenu foo() { echo <0xa3>\; }; echo gotcha; }
lorsqu'il est interprété dans les différents paramètres régionaux.
Autres problèmes :
Le à
Le caractère en UTF-8 est codé comme 0xc3 0xa0. En iso8859-1 et plusieurs autres iso8859
jeux de caractères, 0xa0 est le caractère espace insécable. Sur certains systèmes, ce caractère est inclus dans le vide classe de caractères, donc honorée par bash en tant que délimiteur de jeton dans sa syntaxe.
Solaris est l'un de ces systèmes où U+00A0 est considéré comme un blanc :
$ 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
Découvrez comment :
nawk -v x=àBEGIN... 1
a été interprété comme :
nawk -v x=<0xc3> 'BEGIN{system("...")}' 1
Notez que si la fonction a été définie dans une locale où 0xa0 n'était pas un blanc ou où 0xa3 0x5c était alpha, typeset -f
le produira toujours de la même manière même s'il est appelé dans une locale où il s'agit d'un blanc (produisant une sortie différente lorsqu'il est interprété)
$ 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)'
Plus généralement, la sortie de typeset
, alias
, export -p
, set
, locale
sont tous signifiés pour convenir à la réintroduction dans un shell, mais en plus de ces problèmes de paramètres régionaux, diverses implémentations sont connues pour avoir plusieurs problèmes, et je ne serais pas surpris s'il y en avait encore beaucoup plus.
Donc, oui, je suis d'accord que vous avez raison de considérer cela comme dangereux, et c'est une bonne idée de ne les utiliser que dans un contexte où vous savez d'où proviennent les données qui sont sorties. Par exemple, dans le cas de typeset -f foo
, ne l'utilisez que sur un foo
fonction que vous ont défini (et évitez d'y utiliser des caractères non ASCII).