スクリプトで$ 0に依存するのは危険だと言われています(しばしば偽に引用されている場合:exec -a ...)。はい、書き込み権限を持つディレクトリから$ 0を偽造するためにスクリプトにシンボリックリンクをかけることができます。しかし、書き込み権限のないパス(例:以下の/bin/pwd)を$ 0に指定するにはどうすればよいですか?
以下では、私のスクリプトがshebangを使用していると仮定すると、実装できません。ターゲットスクリプトがshebangを使用すると実行できますか?
$ (exec -a /bin/pwd /tmp/a0.sh)
no-shebang: argv0=/bin/pwd /proc/.../cmdline=/bin/bash^@--noediting^@-i^@
$ (exec -a /bin/pwd /tmp/a1.sh)
yes-shebang: argv0=/tmp/a1.sh /proc/.../cmdline=/bin/sh^@/tmp/a1.sh^@
$ head /tmp/a0.sh /tmp/a1.sh
==> /tmp/a0.sh <==
echo no-shebang: argv0="$0" /proc/.../cmdline=$(cat -v /proc/$$/cmdline)
==> /tmp/a1.sh <==
#!/bin/sh
echo yes-shebang: argv0="$0" /proc/.../cmdline=$(cat -v /proc/$$/cmdline)
つまり、スクリプト(およびその親ディレクトリ)が書き込み禁止になっていてshebangを使用している場合は、他の書き込み禁止パスを偽造せずに$ 0を使用するのは安全ですか?
これは$ 0の単純な偽造でbashのexecステートメント(centos 7で)を使用します。 execve() を使用する C プログラムは違いませんか? bashのexecが弱すぎるのではなく、execve()(カーネルまたはshebang-targetで)のダウンストリームを偽にするのは失敗ですか?
編集:Cのexecve()もshebangの場合は$ 0を偽造せず、出力は上記と同じです。
#include <stdio.h>
int main(void) {
char* argv[] = { "/bin/pwd", NULL };
execve("/tmp/a1.sh", argv, NULL);
perror(NULL);
}
ユーザーにrootアクセス権がある場合は、偽の$ 0が問題にならないことがわかります。しかし、私の書き込み禁止スクリプト(shebangを使用)は、root以外のユーザーが$ 0(他の書き込み禁止パス)を偽造するために使用することはできません。 $ 0のリスク(「単にexec -a ...」を使用)は間違っているようです。 。
答え1
素晴らしい、マニュアルexecve(2)
ページ説明する:
通訳者スクリプト
インタプリタスクリプトは実行権限が有効なテキストファイルで、最初の行の形式は次のとおりです。
#!interpreter [optional-arg]
インタプリタは実行可能ファイルの有効なパス名でなければなりません。
execve()のパス名引数がインタプリタ
スクリプトを指定すると、
インタプリタは次の引数を使用して呼び出されます。interpreter [optional-arg] pathname arg...
そのため、実行するとexec -a /bin/pwd /tmp/a1.sh
システムが実行され/bin/sh /tmp/a1.sh
、これを実行すると$0
スクリプトファイル名に基づいてシェルが設定されます。
シェルから取得した値はargv[0]
表示されません。たとえば、exec -a foobar /bin/sh /tmp/a1.sh
まだ表示されていると判断すると、スクリプトの実行時に設定された値はとにかく失われます。/tmp/a1.sh
$0
/proc/.../cmdline
しかし、これはスクリプトに表示されている値を$0
偽造できないという意味ではありません。ユーザーはスクリプトへのシンボリックリンクを作成し、リンクを介してそれを呼び出すことも、次のこともできます。
/bin/sh -c ". /tmp/a1.sh" foobar
これは単にソース$0
をに設定します。foobar
/tmp/a1.sh