To, co se děje v obou případech, je stejné:pro přímé spuštění souboru je třeba nastavit spouštěcí bit a souborový systém nelze připojit noexec. Ale tyto věci nic nebrání čtení tyto soubory.
Když je bash skript spuštěn jako ./hello_world
a soubor není spustitelný (buď žádný bit oprávnění exec, nebo noexec v souborovém systému), #!
řádek není ani zaškrtnutý , protože systém ani nenačte soubor. Skript není nikdy „spuštěn“ v příslušném smyslu.
V případě bash ./hello_world
, no, volba souborového systému noexec prostě není tak chytrá, jak byste chtěli. bash
příkaz, který se spustí, je /bin/bash
a /bin
není na souborovém systému s noexec
. Takže to běží bez problémů. Systému je jedno, že bash (nebo python nebo perl nebo cokoli jiného) je interpret. Pouze spustí příkaz, který jste zadali (/bin/bash
) s argumentem, který je náhodou soubor. V případě bash nebo jiného shellu tento soubor obsahuje seznam příkazů k provedení, ale nyní jsme „minuli“ vše, co bude kontrolovat bity spouštění souboru. Tato kontrola nezodpovídá za to, co se stane později.
Zvažte tento případ:
$ cat hello_world | /bin/bash
… nebo pro ty, kteří nemají rádi nesmyslné používání kočky:
$ /bin/bash < hello_world
"shbang" #!
sekvence na začátku souboru je jen pěkné kouzlo pro efektivní provedení stejné věci, když se pokusíte spustit soubor jako příkaz. Tento článek na LWN.net vám může pomoci:Jak se spouštějí programy.
Předchozí odpovědi vysvětlují, proč noexec
nastavení nebrání spuštění skriptu při interpretaci (ve vašem případě /bin/bash
) se explicitně volá z příkazového řádku. Ale pokud by to bylo všechno, tento příkaz by fungoval také:
/lib64/ld-linux-x86-64.so.2 hello_world
A jak jsi poznamenal, nefunguje to. To proto, že noexec
má i jiný efekt. Jádro nepovolí soubory mapované do paměti z tohoto souborového systému s PROT_EXEC
povoleno.
Soubory mapované do paměti se používají ve více scénářích. Dva nejběžnější scénáře jsou pro spustitelné soubory a knihovny. Když je program spuštěn pomocí execve
systémové volání, jádro interně vytvoří mapování paměti pro linker a spustitelný soubor. Jakékoli další potřebné knihovny jsou paměti mapované linkerem prostřednictvím mmap
systémové volání s PROT_EXEC
povoleno. Pokud jste se pokusili použít knihovnu ze souborového systému s noexec
jádro by odmítlo provést mmap
zavolejte.
Když jste zavolali /lib64/ld-linux-x86-64.so.2 hello_world
execve
systémové volání vytvoří pouze mapování paměti pro linker a linker otevře hello_world
spustitelný a pokusit se vytvořit mapování paměti v podstatě stejným způsobem, jakým by to bylo pro knihovnu. A to je bod, ve kterém jádro odmítá provést mmap
zavolejte a dostanete chybu:
./hello_world: error while loading shared libraries: ./hello_world: failed to map segment from shared object: Operation not permitted
noexec
nastavení stále umožňuje mapování paměti bez povolení ke spuštění (jak se někdy používá u datových souborů) a také umožňuje normální čtení souborů, proto bash hello_world
pracoval pro vás.
Provedení příkazu tímto způsobem:
bash hello_world
uděláte bash
číst ze souboru hello_world
(což není zakázáno).
V ostatních případech se OS pokusí spustit tento soubor hello_world
a selže kvůli noexec
vlajka