web-dev-qa-db-ja.com

イディオム `ssh ..." $(typeset -f foo); foo "`はどれくらい安全ですか?

いくつかのシェル関数fooが現在のシェルセッションで定義されていると仮定します。次に、コマンド

typeset -f foo

この関数のソースコードを出力します。これは、少なくとも原則として、以下に示すように、sshを介してリモートホストでこの関数を実行できることを意味します。

ssh <REMOTE-Host> "$(typeset -f foo); foo"

(この質問の目的上、fooで言及されているすべてのコマンドとファイルシステムパスが<REMOTE-Host>で使用可能であると想定します。また、bashが両方のシェルであると想定します。終了します。)

私の本能は、このような自動生成されたソースコードを盲目的に調達することは非常に脆弱であるということですが、このイディオムが失敗する関数fooの例を思い付くことができませんでした。

私の質問は:このイディオムはどれくらい安全ですか?安全でない場合、誰かがそれがどのように失敗するかを説明する具体的な例を教えてもらえますか? (安全性の問題には次のものが含まれます:bashtypeset -fのそのような使用が安全であることを保証しますか?)

NB:この投稿では、代替案を探していません。この特定のイディオムの特性を理解したいだけです。


編集:bashが両端のシェルであることを明確にしました。

3
kjo

コードが生成されたロケールと同じロケールで解釈されない場合(またはロケールnameが同じであるが、そのロケールの定義は、sshクライアントホストとサーバーホストで異なります)。

特に重要なのは、blankalpha、および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)'
_

より一般的には、typesetalias、_export -p_、setlocaleの出力はすべてmeant toシェルへの再入力に適していますが、これらのロケールの問題に加えて、さまざまな実装にいくつかの問題があることが知られており、さらに多くの問題があったとしても驚かないでしょう。

ですから、そうです、あなたがそれを危険だと考えるのは正しいと思います。出力されるデータがどこから来ているのかがわかっている状況でのみ使用することをお勧めします。たとえば、_typeset -f foo_の場合は、yoで定義されているfoo関数でのみ使用してください(非ASCII文字の使用は避けてください)。

4