script.shから:
#!/bin/bash
func(){
echo "I am here a func."
}
export -f func
export variable="I am here a variable"
sudo -E bash -c "func ; echo $variable"
出力は次のとおりです。
bash: func: command not found
I am here a variable
- なぜ?
- 初期シェルでsudoを介して[script.shで宣言された]関数を呼び出すことができるソリューションはありますか?
実際、私は次の方法を知っています。
#!/bin/bash
func(){
echo "I am here a func."
}
FUNC=$(declare -f func)
export variable="I am here a variable"
sudo -E bash -c "$FUNC; func ; echo $variable"
ところで、このようにすべての機能を登録しなければならないので重すぎると思います。
答え1
export -f func
私の環境で以下を確認した後:
$ env | grep func
BASH_FUNC_func%%=() …
Bashは、同じ名前BASH_FUNC_foo%%
で始まる値を持つ変数として関数をエクスポートします()
。シェルショック名前にはプレフィックス()がありませんfoo=() …
。 Appleプレフィックスは__BASH_FUNC<
。とにかく値は()
。
sudo
これらの名前と環境全体に非常に注意を払ってください。sudo
Bashスクリプトを実行するためにスクリプトを使用できると想像してください。スクリプトが合法的に使用されていると想像してくださいcat
。あなたという名前のシェル関数をエクスポートすると、cat
スクリプトを効果的に変更し、任意のコードを実行できます。
自分のものを使うことができます$PATH
(そしてこれを行う方法はありますか?;ただし、管理者はこれを防ぐ方法もあります。または利用可能な場合$LD_PRELOAD
(それは簡単ではありません。参照)man 5 sudoers
)を言及したLD_
。
エクスポートしたシェル関数に戻りましょう。まずsudo -V
root(sudo sudo -V
一般ユーザー)として実行すると、出力の一部は次のようになります。
Environment variables to remove:
*=()*
または:
Environment variables to remove:
__BASH_FUNC<*
BASH_FUNC_*
バージョンによって異なると思いますsudo
。
次の行を使用して、リストからこれらのパターンを削除することができますsudoers
(ただし、そうしないで最初に完全な答えを読んでください)。
Defaults env_delete -= "*=()* BASH_FUNC_* __BASH_FUNC<*"
「メンテナンス」リストに追加することもできます(追加する必要はありません)。
Defaults env_keep += "*=()* BASH_FUNC_* __BASH_FUNC<*"
ただし、エクスポートされた関数が必ずしも一緒に動作するわけではありませんsudo
。これは、パターンがハード*=()*
コーディングされ、sudo
拒否変数の一部のバージョン値がで始まるためです()
。この行動は進化しました。利用可能なソリューションは、sudo
使用しているバージョンによって異なります。
~からman 5 sudoers
:
コマンド環境
環境変数はプログラムの動作に影響を与える可能性があるため、
sudoers
実行中のコマンドによって継承されるユーザー環境の変数を制限する方法が提供されます。 sudoersには、環境変数を処理する2つの方法があります。デフォルトでは、この
env_reset
オプションは有効になっています。 [...]HOME
、、環境変数はターゲットユーザーに基づいて初期化され、SHELL
LOGNAME
USER
SUDO_*
DISPLAY
PATH
TERM
env_check
env_keep
()
env_keep
env_check
ただし
env_reset
、このオプションが無効になっている場合、およびenv_check
オプションenv_delete
によって明示的に拒否されていないすべての変数は、呼び出しプロセスによって継承されます。この場合のenv_check
動作はenv_delete
ブラックリストと同じです。バージョン 1.8.21 以前では、()
値が で始まる環境変数は常に削除されました。バージョン 1.8.21 以降、パターンを使用してenv_delete
bash シェル機能を一致させます。潜在的に危険な環境変数をすべてブラックリストに登録することは不可能であるため、デフォルトの動作をenv_reset
お勧めします。
env_check
、またはでenv_delete
指定された環境変数には、ゼロ個以上の文字に一致するenv_keep
1つ以上の文字を含めることができます。*
他のワイルドカード文字はサポートされていません。デフォルトでは、環境変数は名前で一致します。ただし、パターンに等号(
=
)が含まれている場合は、変数名と値の両方が一致する必要があります。たとえば、bashシェル関数は次のように一致することができます。env_keep += "BASH_FUNC_my_func%%=()*"
=()*
サフィックスがない場合、bash シェル機能はデフォルトで維持されないため、一致しません。
ご覧のとおり、env_reset
これは重要です。おそらく活性化されているでしょう。-E
option() の要点は、要求に応じてsudo -E
無効にすることです。env_reset
私のKubuntu 18.04.3 LTSでは、私のsudo
バージョンは1.8.21です。デフォルトでは、*=()*
削除する変数のリストに配置されます。次の行はsudoers
これを停止します。
Defaults env_delete -= "*=()*"
これにより、sudo -E
エクスポートされたシェル機能はすべて保存されます。これが私の主な答えです。
私のDebian 9sudo
バージョンは1.8.19です。デフォルトでは、削除する変数のリストにBASH_FUNC_*
およびが配置されます。__BASH_FUNC<*
これらの項目を削除しても効果はありません()
。これはハードコードされているように見える値が何であれ、このツールはほとんど常に変数を拒否するためです。
このバージョンのマニュアルはいくつかの手がかりを提供します。解決策が見つかりました。
Defaults env_keep += "BASH_FUNC_func%%=()*"
それからsudo
いいえ -E
func
エクスポートすると、この特定のシェル機能()が維持されます。欠点(場合によっては利点かもしれません):
- これは適用されないため、
sudo -E
必要に応じて残りの環境を単純に維持することはできません。 - ワイルドカードなしで変数のフルネームを明示的に指定する必要があります。
BASH_FUNC_*%%=()*
それ以外の場合はBASH_FUNC_*
動作*=()*
しません。
この方法は1.8.21でも動作します。
マニュアルによると、バージョン1.8.11より前は、で始まる変数は()
常に削除されました。あなたがsudo
その年齢であれば、質問に使用したトリック(または同様のトリック)以外の解決策はありません。
メモ:
sudoers
他のファイルのように編集しないでくださいvisudo
。万一の場合に備えたその他の予防措置:- 別の「代替」シェルをルート()で始めます
sudo -i
。sudoers
メインシェルで愚かなことをした場合は、このファイルに頼らずにrootとして実行できます。 - SSH経由で接続する場合は、昇格シェルを作成する前にまたはを使用してください
tmux
。screen
愚かなことをしてsudoers
(偶然に)接続が失敗した場合、管理者権限シェルは通常のユーザーが終了するのではなく再接続するのを待ちます。 cp -a
特に実験している場合は、まずファイルのバックアップコピーを作成します()。- 作業が完了したと思われる場合は、「代替」昇格シェルを終了する前に、root アクセス権を再度取得できることを確認してください。
- 別の「代替」シェルをルート()で始めます
sudo
あなたが唯一のユーザーであり、sudoerが任意のコードを実行することを許可するトリックに対する防御を強化することにあまり意味がない場合でも(あなたは任意のトリックなしで任意のsudo
コードを自由に実行でき、それを望むので)あまりにも多くを許可するする前に2回考えてください。 。シェル機能をそのまま維持すればsudo
今はすぐではありませんが、将来は簡単に攻撃を受けることができます。