Why does Bash's source not need the execution bit?
source
or the equivalent but standard dot .
do not execute the script, but read the commands from script file, then execute them, line by line, in current shell environment.
There's nothing against the use of execution bit, because the shell only need read permission to read the content of file.
The execution bit is only required when you run the script. Here the shell will fork()
new process then using execve()
function to create new process image from the script, which is required to be regular, executable file.
Bash is an interpreter; it accepts input and does whatever it wants to. It doesn't need to heed the executable bit. In fact, Bash is portable, and can run on operating systems and filesystems that don't have any concept of an executable bit.
What does care about the executable bit is the operating system kernel. When the Linux kernel performs an exec
, for example, it checks that the filesystem is not mounted with a noexec
option, it checks the executable bit of the program file, and enforces any requirements imposed by security modules (such as SELinux or AppArmor).
Note that the executable bit is a rather discretionary kind of control. On a Linux x86-64 system, for example, you can bypass the kernel's verification of the executable bit by explicitly invoking /lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
as the interpreter:
cp /bin/ls /tmp/
chmod -x /tmp/ls
/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 /tmp/ls
This is somewhat analogous to sourcing Bash source code in Bash, except that ld.so
is the interpreter, and the code that it executes is machine code in ELF format.
The executable bit (unlike the rest) on nonsetuid and nonsetguid files isn't much of a security mechanism. Anything you can read, you can run indirectly, and Linux will let you indirectly read anything you can run but not directly read (that should be enough to punch a hole in the concept of non-set(g)uid x-bit being a security measure).
It's more of a convenience thing: Let the system run it for me directly if the the bit is set, otherwise I need to do it indirectly (bash the_script;
or some hacking to get the memory image of a no-read-permission executable).
You can set it for convenience if you intend to both in-source and execute your insourcable.
Apparently, however, many shared library implementers share your thinking and consequently, many systems do require that shared libraries, which are essentially the native equivalent of shell insourcables, be marked executable in order to be usable. See Why are shared libraries executable?.