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

`ssh...

foo現在、シェルセッションにシェル関数が定義されているとします。その後、コマンド

typeset -f foo

関数のソースコードを印刷します。これは、少なくとも原則として、次sshの操作を実行してリモートホストでこの機能を実行できることを意味します。

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

(この質問の目的のために言及されているすべてのコマンドとファイルシステムパスがfoo利用可能であるとします<REMOTE-HOST>。また、両端がbashシェルであるとします。)

foo私の直感では、このように自動的に生成されたソースコードを盲目的にキャッチすることは非常に脆弱ですが、このイディオムが失敗する関数の例を考えることはできません。

私の質問は、この慣用語がどれほど安全ですか?安全でない場合、誰かが私にこれがどのように失敗するかの具体的な例を与えることができますか? (安全に関する質問には以下が含まれます。bashこの使用はtypeset -f安全であることが保証されていますか?)

気づく:この記事では、私は代替案を探しているわけではありません。私はこの特定のイディオムの属性を理解したいと思います。


編集:明確にするために、これはbash両端のシェルです。

ベストアンサー1

コードが生成されたロケールと同じロケールで解釈されない場合(またはロケール名前同じですが、SSHクライアントホストとサーバーホスト間でロケール定義が異なります。

blank特に重要なのは、alphaクラス、クラス、クラスの文字エンコーディングと文字メンバーシップですalnum

たとえば、αBIG5文字セット(ギリシャ語の小文字のアルファ)の文字は、\ASCII(およびBIG5を含むすべての文字セット)で0xa3 0x5c、0x5cにエンコードされます。

fooしたがって、対応する文字セットで関数を定義すると、次のようになります。

foo() {
  echo α
}

typeset -fこのように出力されますが、別のロケール(例:C)として解釈されると、0xa3 0x5cはaとして扱われず、α未知の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の文字エンコーディングはà0xc3 0xa0です。 iso8859-1やその他の複数のiso8859文字セットでは、0xa0は改行しない空白文字です。一部のシステムでは、スペース文字クラスなので、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 -psetlocale意味はシェルに再入力するのは良いことですが、これらのロケールの問題に加えて、さまざまな実装にいくつかの既知の問題があり、さらに多くの問題があっても驚くことはありません。

はい。私はこれが危険で良い考えであることに同意します。そして、出力データがどこから来るのかを知っている状況でのみ使用するのが最善です。たとえば、次の条件を満たす関数にのみtypeset -f foo使用してください。fooあなた定義されます(そしてASCII以外の文字を使用しないでください)。

おすすめ記事