Bashで組み込みコマンドを明示的かつ安全に強制する方法

Bashで組み込みコマンドを明示的かつ安全に強制する方法

一つあるエマルジョンcd組み込み呼び出しを置き換える場合など、「ラッパー」シナリオを処理しますcd

しかし、shellshockなどを考慮し、bashが環境から関数を取得することを知っていくつかのテストを実行しましたが、cdスクリプト内で組み込み関数を安全に呼び出す方法が見つかりませんでした。

これについて考える

cd() { echo "muahaha"; }
export -f cd

この環境で使用法呼び出しを使用するすべてのスクリプトcdは中断されます(同様の効果を考慮cd dir && rm -rf .)。

命令の種類を確認する命令(便宜上と呼ばれる)と、関数(および)の代わりに組み込みtypeバージョンを実行する命令があります。しかし、見て、これらは関数を使用して上書きすることができます。builtincommand

builtin() { "$@"; }
command() { "$@"; }
type() { echo "$1 is a shell builtin"; }

次の結果が生成されます。

$ type cd
cd is a shell builtin
$ cd x
muahaha
$ builtin cd x
muahaha
$ command cd x
muahaha

bashが組み込みコマンドを使用するように安全に強制するか、少なくとも環境全体を消去せずにコマンドが組み込みコマンドではないことを検出する方法はありますか?

誰かがあなたの環境を制御すると問題が発生する可能性がありますが、少なくともエイリアスを使用すると、エイリアスの\前に挿入してエイリアスを呼び出さないように選択できます。

答え1

オリビエD.ほぼ正しいです。ただし、POSIXLY_CORRECT実行する前に設定する必要がありますunset。 POSIXには概念があります特殊内蔵バッシュはこれをサポートしますunsetそれは組み込まれています。 、およびを含む検索リストSPECIAL_BUILTINからbashソースを検索します。builtins/*.csetunsetexportevalsource

$ unset() { echo muahaha-unset; }
$ unset unset
muahaha-unset
$ POSIXLY_CORRECT=1
$ unset unset

これで不良は環境から削除され、unset設定を解除すると続行できますが、後でPOSIX以外の動作や高度なbash機能に依存している場合は続行できません。commandtypebuiltinunset POSIXLY_CORRECT

これ確かにただし、アドレスはエイリアスなので、次のものを使用する必要があります\unset(または任意の形式の引用/エスケープインタラクティブシェルで動作しているかどうかを確認する(またはexpand_aliases動作している場合に備えて常に)

妄想症の患者にとって、これはしなければならないすべての問題を解決するには、次のように考えます。

POSIXLY_CORRECT=1
\unset -f help read unset
\unset POSIXLY_CORRECT
re='^([a-z:.\[]+):' # =~ is troublesome to escape
while \read cmd; do 
    [[ "$cmd" =~ $re ]] && \unset -f ${BASH_REMATCH[1]}; 
done < <( \help -s "*" )

while、、、doおよびdone[[予約語なので注意は必要ありません。エイリアスや関数名には使用=できないため、設定時に注意は必要ありません。)POSIXLY_CORRECTunset -f同じ名前空間があれば、両方とも同時に存在できます(Etan Reisnerのおかげで)。この場合、設定を2回オフにすると問題が解決します。あなたできる機能を読み取り専用としてマークしてください。 bash は bash-4.2 以前の読み取り専用機能の設定解除を妨げません。 bash-4.3はあなたを止めますが、POSIXLY_CORRECT設定時に特別な組み込み機能を尊重します。

読み取り専用はPOSIXLY_CORRECT実際の問題ではなく、ブールまたはフラグでもありません。現在のPOSIX モードを有効にするため、読み取り専用として存在する場合、値が空であってもゼロであっても POSIX 機能を使用できます。上記とは異なり、問題となる機能を設定解除するだけです。おそらく切り取りと貼り付けを使用してください。

\help -s "*" | while IFS=": " read cmd junk; do echo \\unset -f $cmd; done

(そしてエラーを無視したり)他のことに参加してください。文字論


その他の注意事項:

  • function予約語であり、エイリアスとして使用できますが、関数でオーバーライドすることはできません。 (エイリアシングはfunction少し面倒です。\function いいえこの問題を解決する方法として許可されます)
  • [[]]予約語であり、別名を指定できますが(無視されます)、関数によってオーバーライドすることはできません(関数名はそのように指定できます)
  • ((関数またはエイリアスの有効な名前ではありません。

追加の提案をいただきありがとうございます。

答え2

私は誰かがあなたの環境を制御するならば、あなたは台無しになるかもしれないことに気づきました。

そうそう。不明な環境でスクリプトを実行すると、LD_PRELOADスクリプトを読む前にシェルプロセスがランダムなコードを実行することから始めて、さまざまな問題が発生する可能性があります。スクリプト内の敵対的な環境から保護する試みは役に立ちません。

10年以上にわたり、Sudoはbash関数定義のように見えるものをすべて取り除き、環境を衛生的に保ってきました。 ~からシェルショック、完全に信頼できない環境でシェルスクリプトを実行する他の環境もこれに従いました。

信頼できないエンティティによって設定された環境では、スクリプトを安全に実行することはできません。したがって、関数定義について心配するのは非生産的です。環境をクリーンアップすると、bashは変数を関数定義として解釈します。

答え3

このコマンドを使用して関数とをunset -f 削除できます。builtincommandtype

関連情報