誰もが以下で何が起こっているのか詳細に説明できますか?次のようにnoexec
オプションを使用してディレクトリをマウントするとします。
mount -o noexec /dev/mapper/Fedora-data /data
これを確認するために、私はmount | grep data
を実行しました:
/dev/mapper/Fedora-data on /data type ext4 (rw,noexec,relatime,seclabel,data=ordered)
/data
内で、次のようにhello_world
という簡単なスクリプトを作成しています。
#!/bin/bash
echo "Hello World"
whoami
そのため、スクリプトをchmod u+x hello_world
で実行可能にしました(ただし、これはnoexec
オプションを使用したファイルシステムには影響しません)。実行しようとしました。
# ./hello_world
-bash: ./hello_world: Permission denied
ただし、bash
をファイルに事前に追加すると、次のようになります。
# bash hello_world
Hello World
root
それで、次の内容のシンプルなhello_world.c
を作成しました。
#include <stdio.h>
int main()
{
printf("Hello World\n");
return 0;
}
cc -o hello_world hello_world.c
を使用してコンパイルしました
現在実行中:
# ./hello_world
-bash: ./hello_world: Permission denied
だから私はそれを使って実行しようとしました
/lib64/ld-linux-x86-64.so.2 hello_world
エラー:
./hello_world: error while loading shared libraries: ./hello_world: failed to map segment from shared object: Operation not permitted
したがって、ldd
は以下を返すため、これはもちろん当てはまります。
ldd hello_world
ldd: warning: you do not have execution permission for `./hello_world'
not a dynamic executable
noexec
マウントオプションが適用されない別のシステムでは、次のようになります。
ldd hello_world
linux-vdso.so.1 (0x00007ffc1c127000)
libc.so.6 => /lib64/libc.so.6 (0x00007facd9d5a000)
/lib64/ld-linux-x86-64.so.2 (0x00007facd9f3e000)
今私の質問はこれです:noexec
オプションを使用してファイルシステムでbashスクリプトを実行しても、c
コンパイル済みプログラムが機能しないのはなぜですか?内部で何が起こっていますか?
どちらの場合も同じです。ファイルを直接実行するには、実行ビットを設定する必要があり、ファイルシステムをnoexecでマウントできません。しかし、これらはこれらのファイルの読み取りを停止するものではありません。
Bashスクリプトが./hello_world
として実行され、ファイルが実行可能でない場合(exec許可ビットがない、またはファイルシステムで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の記事が役に立つかもしれません: プログラムの実行方法 。
以前の回答は、インタープリター(あなたの場合は/bin/bash
)がコマンドラインから明示的に呼び出されたときに、noexec
設定がスクリプトの実行を妨げない理由を説明しています。しかし、それがすべてだった場合、このコマンドも機能します。
/lib64/ld-linux-x86-64.so.2 hello_world
そして、あなたが指摘したように、それは機能しません。これは、noexec
にも別の効果があるためです。カーネルは、PROT_EXEC
が有効になっているファイルシステムからのメモリマップファイルを許可しません。
メモリマップファイルは、複数のシナリオで使用されます。最も一般的な2つのシナリオは、実行可能ファイルとライブラリのシナリオです。 execve
システムコールを使用してプログラムを起動すると、カーネルは内部でリンカーと実行可能ファイルのメモリマッピングを作成します。その他の必要なライブラリは、PROT_EXEC
を有効にしてmmap
システムコールを介してリンカーによってマップされたメモリです。 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
フラグのために失敗
Bashを介してスクリプトを実行すると、ファイルを読み込んで解釈するだけです。
ただし、名前をカーネルに渡すと、ファイルの「#!」が本当に検査されます。そして、カーネルオプション「CONFIG_BINFMT_SCRIPT」に従って指定されたインタプリタをロードします。それは言う:
「#!」で始まる解釈済みスクリプトを実行する場合は、ここでYと言います。その後にインタープリターへのパスが続きます。
このサポートはモジュールとして構築できます。ただし、そのモジュールが読み込まれるまで、スクリプトを実行できません。したがって、このモジュールをinitramfsからロードする場合、このモジュールをロードする前のinitramfsの部分は、コンパイルされたバイナリのみで構成されている必要があります。
ここでMまたはNと言った場合、ほとんどのシステムは起動しません。不明な場合はYと言ってください。
上記は、このオプションに関連するヘルプテキストです。別の興味深い違いについて。私は自分のスクリプトを書いた:
> cat myprog.sh
#!/bin/cat
echo "Hello World"
> chmod +x myprog.sh
Bashで実行すると、bashのインタープリターが実行されます。
> bash myprog.sh
Hello World
ただし、カーネルは次のことを行います。
> myprog.sh
#!/bin/cat
echo "Hello World"
カーネルは 'cat'を呼び出したため、1行目を含むスクリプトを出力しました。
Cプログラムの場合、バイナリーを実行するためにインタープリターを呼び出すことはありません。カーネルはそれを直接実行しようとします。それでも、一部のデバッガーを使用してすべての実行可能ファイルをメモリにロードした場合でも、デバッガーを介してロードされているため、プログラムを「実行」できます。
「noexec」オプションは、バイナリの実行ビットをオフにして、カーネルがバイナリを「自然に」実行することを無効にするようなものです。
ところで、プログラムにSetUIDビットが設定されている場合は違いがあります-インタープリターでプログラムをロードしてもUIDは設定されません。カーネルがロードしたときにのみ、その特権を有効にできます。
FWIW-Windowsにも同じタイプのメカニズムがあります。
「.exe」や「.vbs」などの「実行可能なサフィックス」として「.sh」を追加すると、実行する「.sh」ファイルの設定方法に従って、ウィンドウが自動的にファイルを実行します。理論的には、「。txt」ファイルを設定して、コマンドラインで名前を入力した場合に自動的に入力されるようにすることができます。
同様に、テキストファイルを画面に出力するプログラムに短い呼び出しをかけることができます。そのため、公共の場所にログインしたままにしないでください。
Bash実行可能ファイルが上記のファイルシステムに存在しないためです。