現在のユーザーがファイルに対して実行(--x)権限しか持っていない場合、どのユーザーの下でインタープリター(ファイルの先頭に#!/path/to/interpreter
で指定)が実行されますか?
ファイルを読み取る権限がないため、現在のユーザーにはなれません。インタープリターに含まれる任意のコードがルートアクセスを取得するため、ルートにすることはできません。
では、どのユーザーとして、インタープリタープロセスが実行されますか?
編集:私の質問は、ファイルがどのインタープリターを指定するかを知るのに十分に読み取られていることを前提としていますが、実際にはそれほど遠くにはなりません。ターゲットファイルを実行するコマンドを解釈する現在のシェル(通常はb/a/sh)は、それを読み取ろうとして失敗します。
ユーザーが実行可能スクリプトに対する読み取り権限を持っていない場合、ユーザーがCAP_DAC_OVERRIDE
機能を持っていない限り、実行しようとすると失敗します。 。彼女はルートです):
$ cat > yup; chmod 100 yup
#! /bin/sh
echo yup
^D
$ ./yup
/bin/sh: 0: Can't open ./yup
インタープリターは(失敗したか成功したかにかかわらず)常に現在のユーザーとして実行され、スクリプトのsetuidビットまたはsetcap拡張属性を無視します。
実行可能スクリプトは、インタープリターがスクリプトを実行するために開いて読み取ることができる必要があるという点で、バイナリとは異なります。ただし、それらは単に引数としてインタープリターに渡されることに注意してください。インタープリターはそれらをまったく読み取ろうとはしませんが、まったく異なることを行います。
$ cat > interp; chmod 755 interp
#! /bin/sh
printf 'you said %s\n' "$1"
^D
$ cat > script; chmod 100 script
#! ./interp
nothing to see here
^D
$ ./script
you said ./script
もちろん、インタプリタ自体は、setuidまたはcap_dac_override=ep
- setcapバイナリである可能性があります(または、スクリプトのパスを引数としてそのようなバイナリ)、この場合、昇格された特権で実行され、ファイルのアクセス許可を無視する可能性があります。
Linuxでは、binfmt_misc
モジュールを使用して、実行可能スクリプトのすべての制限を回避できます(そしてシステムを破壊します;-))。
ルートとして:
# echo ':interp-test:M::#! ./interp::./interp:C' \
> /proc/sys/fs/binfmt_misc/register
# cat > /tmp/script <<'EOT'; chmod 4001 /tmp/script # just exec + setuid
#! ./interp
id -u
EOT
通常のユーザーとして:
$ echo 'int main(void){ dup2(getauxval(AT_EXECFD), 0); execl("/bin/sh", "sh", "-p", (void*)0); }' |
cc -include sys/auxv.h -include unistd.h -x c - -o ./interp
$ /tmp/script
0
ヤッピー!
詳細については、カーネルソースの Documentation/admin-guide/binfmt-misc.rst
を参照してください。
-p
オプションは、一部のシェルでエラーを引き起こす可能性があります(単純にドロップされる可能性があります)が、新しいバージョンのdash
およびbash
では、それらを防ぐために必要です- 特権の削除 要求されなくても。
スクリプトの実行は2つのフェーズで機能します。最初に、カーネルはファイルの先頭を読み取り、それが#!
で始まることを確認するため、 Shebang 行を読み取り、呼び出すインタープリターを決定します。次に、カーネルは元のコマンドラインをインタープリターへのパス、Shebang行のオプション¹(存在する場合)、ファイルへのパス、および元のオプションに変換します。次に、これがずっとコマンドラインであったかのように、このコマンドラインを実行しますが、それ以上のShebang処理は実行しません。
これまでのところ、カーネルは、呼び出し元がスクリプトファイルに対する実行権限を持っていることを確認しています。読み取り許可は機能していません。カーネルはファイルの実行の一部としてファイルの先頭を読み取るため、これは読み取り権限ではなく実行権限によって制御されます。
2番目のフェーズでは、インタープリターが実行されます。コマンドラインにスクリプトファイル名が表示されているため、おそらくそれを開こうとします。これは、読み取り許可が必要なポイントです。インタプリタにファイルを読み取る権限がない場合、そのopen
呼び出しは失敗し、おそらくインタプリタはエラーメッセージを出力してあきらめます。これはすべての賢明な通訳が行うことであるため、私は「おそらく」と言いますが、このように物事が起こるという技術的義務はありません。 Shebangラインでインタプリタではないプログラムを使用する場合、最初のフェーズでは何の違いもありませんが、プログラムは2番目のフェーズで行うことは何でも行います。たとえば、#!/bin/echo
で始まる「スクリプト」は、スクリプトファイル名と追加のコマンドライン引数を出力して終了するだけで、スクリプトはそのために実行可能である必要があります。
¹ Linuxを含む多くのカーネルでは、1つのオプションしか許可されていません。
一般に、ファイルを所有している場合でも、「r」権限がないとスクリプトを実行できません。
_$ ls -l tst
---x--x--x 1 sweh sweh 24 May 4 21:22 tst*
$ ./tst
/bin/bash: ./tst: Permission denied
$ Sudo cat tst
#!/bin/bash
echo hello
_
編集した質問で。
プログラムの_#!
_部分は、カーネルによってexec()
システムコールの一部として解釈されます。したがって、これまでのところ、スクリプトは読み取り可能である必要はありません。
事実上、私の例では、カーネルが私の_./tst
_を_/bin/bash ./tst
_呼び出しに変換します。
この変換は、スクリプトが処理されるためにr
アクセスを必要とする理由を説明しますが、カーネルは使用されるインタープリターを決定するためにx
を必要とするだけです。