Unable to prevent execution of shebang lines
Affects | Status | Importance | Assigned to | Milestone | |
---|---|---|---|---|---|
AppArmor |
New
|
Undecided
|
Unassigned |
Bug Description
Let's say I want to write a profile to disallow execution of one particular binary (e.g. perl), but otherwise allow everything:
_______
profile testprofile {
file,
capability,
network,
unix,
signal,
/** ix, # launch any executable under this same profile
audit deny /usr/bin/perl rwxmlk,
}
_______
Under this profile, it seems like I cannot prevent scripts with a #!/usr/bin/perl shebang line from executing anyway. On vanilla Debian 10 and Ubuntu 20.10 Groovy boxes, I get the following result:
_______
# cat /root/script.sh
#!/usr/bin/perl
print "hi\n";
_______
_______
# aa-exec -i -p testprofile perl -e 'print "hi\n";'
[7660] aa-exec: ERROR: Failed to execute "perl": Permission denied
# aa-exec -i -p testprofile /root/script.sh
hi
_______
I've confirmed that the launched /root/script.sh process inherits the same profile by inspecting /proc/$
From what I've understood reading the kernel sources this happens because the bprm_creds_for_exec hook fires before search_
I suppose this raises conceptual questions about whether scripts should be considered their own proper executable as opposed to being merely an invocation of another program, but from a user perspective it's certainly unexpected to not be able to prevent execution of the shebang line.
This could arguably present a security vulnerability as well, since you now cannot prevent a malicious user from editing the shebang line of a whitelisted script and successfully execve()'ing a non-whitelisted binary.
Correct, scripts are treated as their own executable. Eg.
Profile some_script /usr/bin/script {
...
}
will attach to a script as if it is its own executable instead of the interpreter (say perl). This same script can be run directly from the interpreter and NOT be confined by the defined profile. ie.
$ perl /usr/bin/script
will launch the script with what ever confinement perl will run under instead of what the profile for the script.
This does mean that that users can launch applications that by-pass a script profile for the interpreter profile OR as you have noticed use a script profile to by-pass the interpreter profile.
Currently it is expected that if user should not be able to change what confinement a script will run under they should not be given write access to the script file, and ideally denied running the interpreter directly. Interpreters if they support AppArmor's API can execute switch into the scripts profile but unfortunately no interpreters are doing this atm.
This is less than ideal and the AppArmor project is working on improving this with some extensions.
- script profiles will be able to identify what their interpreter should be, causing script execution to fail if the interpreter is different than what has been defined.
- scipts can be defined to pickup/use the interpreter profile
- scripts can be allowed/blocked based on the interpreter
And further out
- interpreters will be able to be tagged as such and parse out the script file that is to be run, and pickup the script profile even when started by the interpreter.