Lo que sucede en ambos casos es lo mismo:para ejecutar un archivo directamente, se debe establecer el bit de ejecución y el sistema de archivos no se puede montar noexec. Pero estas cosas no impiden nada de leer esos archivos.
Cuando el script bash se ejecuta como ./hello_world
y el archivo no es ejecutable (ya sea sin bit de permiso exec o noexec en el sistema de archivos), el #!
la línea ni siquiera está marcada , porque el sistema ni siquiera carga el archivo. El script nunca se "ejecuta" en el sentido relevante.
En el caso de bash ./hello_world
, bueno, la opción del sistema de archivos noexec simplemente no es tan inteligente como le gustaría que fuera. El bash
el comando que se ejecuta es /bin/bash
y /bin
no está en un sistema de archivos con noexec
. Entonces, corre sin problema. Al sistema no le importa que bash (o python o perl o lo que sea) sea un intérprete. Simplemente ejecuta el comando que diste (/bin/bash
) con el argumento que resulta ser un archivo. En el caso de bash u otro shell, ese archivo contiene una lista de comandos para ejecutar, pero ahora hemos "pasado" todo lo que va a verificar los bits de ejecución del archivo. Ese cheque no es responsable de lo que suceda después.
Considere este caso:
$ cat hello_world | /bin/bash
… o para los que no les gusta el uso inútil de Cat:
$ /bin/bash < hello_world
El "shbang" #!
La secuencia al comienzo de un archivo es solo una buena magia para hacer efectivamente lo mismo cuando intenta ejecutar el archivo como un comando. Puede encontrar útil este artículo de LWN.net:Cómo se ejecutan los programas.
Las respuestas anteriores explican por qué noexec
configuración no evita que se ejecute un script cuando el intérprete (en su caso, /bin/bash
) se llama explícitamente desde la línea de comando. Pero si eso fuera todo, este comando también habría funcionado:
/lib64/ld-linux-x86-64.so.2 hello_world
Y como has notado, eso no funciona. Eso es porque noexec
tiene otro efecto también. El kernel no permitirá archivos mapeados en memoria de ese sistema de archivos con PROT_EXEC
activado.
Los archivos asignados a la memoria se utilizan en múltiples escenarios. Los dos escenarios más comunes son para ejecutables y bibliotecas. Cuando un programa se inicia usando el execve
llamada al sistema, el núcleo creará internamente asignaciones de memoria para el enlazador y el ejecutable. Cualquier otra biblioteca necesaria es mapeada en memoria por el enlazador a través del mmap
llamada al sistema con PROT_EXEC
activado. Si intentó usar una biblioteca de un sistema de archivos con noexec
el núcleo se negaría a hacer el mmap
llamar.
Cuando invocaste /lib64/ld-linux-x86-64.so.2 hello_world
el execve
la llamada al sistema solo creará una asignación de memoria para el enlazador y el enlazador abrirá el hello_world
ejecutable e intente crear un mapeo de memoria de la misma manera que lo habría hecho para una biblioteca. Y este es el punto en el que el núcleo se niega a realizar el mmap
llama y te sale el error:
./hello_world: error while loading shared libraries: ./hello_world: failed to map segment from shared object: Operation not permitted
El noexec
la configuración aún permite asignaciones de memoria sin permiso de ejecución (como se usa a veces para archivos de datos) y también permite la lectura normal de archivos, razón por la cual bash hello_world
funcionó para usted.
Ejecutando el comando de esta manera:
bash hello_world
haces bash
leer del archivo hello_world
(que no está prohibido).
En otros casos, el sistema operativo intenta ejecutar este archivo hello_world
y falla debido a noexec
bandera