いくつかのシェル関数foo
が現在のシェルセッションで定義されていると仮定します。次に、コマンド
typeset -f foo
この関数のソースコードを出力します。これは、少なくとも原則として、以下に示すように、ssh
を介してリモートホストでこの関数を実行できることを意味します。
ssh <REMOTE-Host> "$(typeset -f foo); foo"
(この質問の目的上、foo
で言及されているすべてのコマンドとファイルシステムパスが<REMOTE-Host>
で使用可能であると想定します。また、bash
が両方のシェルであると想定します。終了します。)
私の本能は、このような自動生成されたソースコードを盲目的に調達することは非常に脆弱であるということですが、このイディオムが失敗する関数foo
の例を思い付くことができませんでした。
私の質問は:このイディオムはどれくらい安全ですか?安全でない場合、誰かがそれがどのように失敗するかを説明する具体的な例を教えてもらえますか? (安全性の問題には次のものが含まれます:bash
はtypeset -f
のそのような使用が安全であることを保証しますか?)
NB:この投稿では、代替案を探していません。この特定のイディオムの特性を理解したいだけです。
編集:bash
が両端のシェルであることを明確にしました。
コードが生成されたロケールと同じロケールで解釈されない場合(またはロケールnameが同じであるが、そのロケールの定義は、sshクライアントホストとサーバーホストで異なります)。
特に重要なのは、blank
、alpha
、およびalnum
カテゴリの文字のエンコードと文字のメンバーシップです。
たとえば、BIG5文字セットの_α
_文字(ギリシャ文字の小文字のアルファ)は0xa3 0x5cとしてエンコードされ、0x5cはASCII(および以下を含むすべての文字セット)の_\
_です。 BIG5)。
したがって、その文字セットでfoo
関数が次のように定義されている場合:
_foo() {
echo α
}
_
_typeset -f
_はそのように出力しますが、Cのような別のロケールで解釈された場合、その0xa3 0x5cは_α
_としてではなく、不明な0xa3文字とそれに続くバックスラッシュとして解釈されます。これは、次のように悪用できます。
_$ 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: `}'
_
別のロケールで解釈すると、foo() { echo α\;}; echo gotcha; }
はfoo() { echo <0xa3>\\; }; echo gotcha; }
になりました。
その他の問題:
UTF-8の_à
_文字は、0xc30xa0としてエンコードされます。 iso8859-1およびその他のいくつかの_iso8859
_文字セットでは、0xa0は改行なしスペース文字です。一部のシステムでは、その文字はblank文字クラスに含まれているため、構文のトークン区切り文字としてbashによって尊重されます。
Solarisは、U + 00A0が空白と見なされるそのようなシステムの1つです。
_$ 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
_
方法をご覧ください:
_nawk -v x=àBEGIN... 1
_
次のように解釈されました:
_nawk -v x=<0xc3> 'BEGIN{system("...")}' 1
_
0xa0が空白ではないロケール、または0xa3 0x5cがアルファであるロケールで関数が定義されている場合、_typeset -f
_は、空白のロケールで呼び出されても同じように出力されることに注意してください(解釈)
_$ LC_ALL=zh_TW.big5 bash -c $'f() { echo \xa3\x5c$(uname); }; export LC_ALL=C; typeset -f f | bash'
bash: line 3: syntax error near unexpected token `('
bash: line 3: ` echo �\$(uname)'
_
より一般的には、typeset
、alias
、_export -p
_、set
、locale
の出力はすべてmeant toシェルへの再入力に適していますが、これらのロケールの問題に加えて、さまざまな実装にいくつかの問題があることが知られており、さらに多くの問題があったとしても驚かないでしょう。
ですから、そうです、あなたがそれを危険だと考えるのは正しいと思います。出力されるデータがどこから来ているのかがわかっている状況でのみ使用することをお勧めします。たとえば、_typeset -f foo
_の場合は、yoで定義されているfoo
関数でのみ使用してください(非ASCII文字の使用は避けてください)。