Using noexec option in fstab
This link explains the benefits of using noexec
option when using mount
. However it lists one limitation - if I have a Perl/Python/shell script or a file that starts with #!
and will try to execute it - I will be able to do so whether I supplied the option or not.
Is there a way to prevent such execution? I.e. is there an additional option to noexec
which I can give and the execution of the scripts will not be possible?
There's a major misunderstanding here. Let's make these things clear.
First of all, the limitation you refer to, as it is stated, is not true:
However, when a script (a text file that begins with she-bang line; i.e., a line that begins with
#!
) is given to some shells (bash), it will run the executable named on that line (e.g.,/usr/bin/perl
) and connect the content of the script file to the stdin of that executable, which may not be on that drive.
Surprisingly it seems to explain the ability to execute, despite noexec
. I think the asker there got it all wrong in the first place and it wasn't his or her fault! One wrong assumption in the question caused another wrong assumption in the answer.
What's wrong then?
1. Bind mount is specific
To get some context let's see what happens when you try to bind mount as read-only. There's this question: Why doesn't mount respect the read only option for bind mounts? The conclusion is:
To achieve the desired result one needs to run two commands:
mount SRC DST -o bind mount DST -o remount,ro,bind
Newer versions of mount (util-linux >=2.27) do this automatically when one runs
mount SRC DST -o bind,ro
But when you try to use noexec
instead of ro
, you still need two commands! In my Kubuntu I have util-linux 2.27.1-6ubuntu3.3
and this command:
mount SRC DST -o bind,noexec
ignores noexec
, I need to remount. It's the same if mounting is via /etc/fstab
. You can experiment. At any time check with plain mount
command what the actual options are.
I bet the asker thought the mount was with noexec
option, but actually it was not. He or she was able to execute a script from within allegedly noexec
mountpoint. It was strange, hence the question.
Then the answer author interpreted this, as if it was the shell what reads shebang, calls another executable and doesn't worry about noexec
for the script. If the mountpoint was really noexec
then this would be a reasonable speculation.
But…
2. It's a common myth that shells read shebangs; kernel does
Read How does the #! shebang work? and notice one of the answers there had originally followed the myth, then it was corrected.
So if you have:
- a mountpoint
/mnt/foo/
withnoexec
option, - a script
/mnt/foo/script.py
which is otherwise executable (e.g.chmod -x …
was invoked), - a shebang like
#!/usr/bin/python
as the first line in the script
and you run it like this
/mnt/foo/script.py
then your Linux kernel won't let you because of noexec
. It would have happened in this other question if the mounting was actually noexec
there; but I believe it was not.
3. Still, there are two ways to "execute" a script
From comments:
"and will try to execute it" How? By running it directly or by passing it to the interpreter?
Running it directly means:
/mnt/foo/script.py
This will honor noexec
as elaborated above. The executable is script.py
.
Passing it to the interpreter means:
python /mnt/foo/script.py
In this case the executable is python
. It doesn't matter if foo/
is mounted with noexec
; it doesn't matter if script.py
is executable at all; it doesn't matter what the shebang is. The point is script.py
is not executed, it's read.
As long as user can read a file and run proper interpreter, there's no way to prevent passing the file to the interpreter; but it's not the file that is executed.