ファイルを直接実行するには、実行ビットを設定する必要があり、ファイルシステムを noexec でマウントすることはできません。しかし、これらは読書を止めるものではありません それらのファイル。
./hello_world
として bash スクリプトを実行した場合 ファイルは実行可能ではありません (実行許可ビットがないか、ファイルシステムに noexec のいずれか)、 #!
行はチェックさえされていません 、システムはファイルをロードさえしないためです。スクリプトは、関連する意味で「実行」されることはありません。
bash ./hello_world
の場合 ええと、noexec ファイルシステム オプションは単純に、あなたが望むほどスマートではありません。 bash
実行されるコマンドは /bin/bash
です 、および /bin
noexec
のファイルシステムにありません .したがって、問題なく実行されます。システムは、bash (または python や perl など) がインタープリターであることを気にしません。指定したコマンドを実行するだけです (/bin/bash
) たまたまファイルである引数を使用します。 bash やその他のシェルの場合、そのファイルには実行するコマンドのリストが含まれていますが、ファイルの実行ビットをチェックするものはすべて「過去」にします。そのチェックは、後で何が起こるかについて責任を負いません。
この場合を考えてみましょう:
$ cat hello_world | /bin/bash
…または猫の無意味な使用が嫌いな人向け:
$ /bin/bash < hello_world
"shbang" #!
ファイルの先頭にあるシーケンスは、ファイルをコマンドとして実行しようとしたときに効果的に同じことを行うための素晴らしい魔法です。この LWN.net の記事が役に立つかもしれません:How programs get run.
以前の回答が noexec
の理由を説明しています 設定は、インタープリターのときにスクリプトが実行されるのを妨げません(あなたの場合は /bin/bash
) は、コマンド ラインから明示的に呼び出されます。しかし、それがすべてである場合、このコマンドも同様に機能します:
/lib64/ld-linux-x86-64.so.2 hello_world
そして、あなたが指摘したように、それはうまくいきません。それはnoexec
だからです 別の効果もあります。カーネルは、PROT_EXEC
のファイル システムからメモリ マップされたファイルを許可しません。
メモリ マップト ファイルは、複数のシナリオで使用されます。最も一般的な 2 つのシナリオは、実行可能ファイルとライブラリです。 execve
を使用してプログラムを起動した場合 システム コールを実行すると、カーネルはリンカーと実行可能ファイルのメモリ マッピングを内部的に作成します。その他の必要なライブラリは、mmap
を介してリンカによってメモリ マップされます。 PROT_EXEC
のシステムコール 有効にします。 noexec
のファイルシステムからライブラリを使用しようとした場合 カーネルは mmap
を拒否します
/lib64/ld-linux-x86-64.so.2 hello_world
を呼び出したとき execve
システム コールはリンカのメモリ マッピングのみを作成し、リンカは hello_world
を開きます。 実行可能ファイルを作成し、ライブラリの場合とほとんど同じ方法でメモリ マッピングを作成しようとします。そして、これがカーネルが mmap
の実行を拒否するポイントです を呼び出すと、エラーが発生します:
./hello_world: error while loading shared libraries: ./hello_world: failed to map segment from shared object: Operation not permitted
noexec
この設定では、実行権限なしでメモリ マッピングが引き続き許可され (データ ファイルに使用されることがあります)、ファイルの通常の読み取りも許可されます。これが bash hello_world
の理由です。
この方法でコマンドを実行:
bash hello_world
あなたは bash
を作ります ファイル hello_world
から読み取る (これは禁止されていません)。
それ以外の場合、OS はこのファイルを実行しようとします hello_world
noexec
のために失敗します フラグ