Unable to prevent execution of shebang lines

Bug #1911431 reported by Jay D.R.
6
This bug affects 1 person
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/$pid/attr/current.

From what I've understood reading the kernel sources this happens because the bprm_creds_for_exec hook fires before search_binary_handler rewrites the bprm to swap out the executable for the shebang one.

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.

Tags: aa-kernel
Revision history for this message
John Johansen (jjohansen) wrote :

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.

Revision history for this message
Jay D.R. (vtsj) wrote :

Ok, that's clear. Thanks for clarifying.

To post a comment you must log in.
This report contains Public information  
Everyone can see this information.

Other bug subscribers

Remote bug watches

Bug watches keep track of this bug in other bug trackers.