AppArmor controls for suid binaries can be bypassed by the caller
Affects | Status | Importance | Assigned to | Milestone | |
---|---|---|---|---|---|
AppArmor |
New
|
Undecided
|
Unassigned |
Bug Description
Marking this as a security bug for now, since I'm not sure whether this violates an intended security boundary, or whether this is just something you're not supposed to do; feel free to mark it as public+invalid or whatever if this is outside the intended security model.
Normally, when an AppArmor transition from context A to context B occurs on exec, the idea is that context B might be malicious while context A is benign - so context A cooperates with the transition, and context B can't interfere with it because it only runs after the transition.
But a system owner might also attempt to apply AppArmor transitions to the execution of set-user-ID binaries, with the goal of limiting the damage that a malicious context A can do if it escalates its privileges into the more privileged context B. It seems that at least some people believe that AppArmor would be usable in such a context:
https:/
"For example, the ping command requires root privileges in order to send the special packet formats that it needs. But it is theoretically possible for the process to misuse its root privileges to cause all kinds of trouble. Although ping is a well-behaved program, an attacker capable of hijacking the tool would have unrestricted access to the rest of the system.
AppArmor [1] changes this."
https:/
"Two types of applications are particularly important to protect: programs that run setuid root (that is, run with root's privileges) and network applications. AppArmor comes preconfigured with profiles for a variety of setuid-root programs and network applications, including Apache, ping, Firefox, Opera, Evolution, sshd, ld, Postfix, Squid and Ethereal."
AppArmor's bprm_set_creds hook only mutates state on its first invocation, meaning that when a script is invoked, it only looks at the script and not at its interpreter:
if (bprm->
return 0;
In contrast, the set-user-ID bit is taken from the interpreter. This means that by creating a script that uses a set-user-ID binary as interpreter, it is possible to execute the interpreter with set-user-ID semantics without triggering a profile transition. Repro:
On Ubuntu 18.04, install the apparmor-profiles package.
Verify that when you run "ping 127.0.0.1", "ping" runs with saved-user-ID 0 and with the ping profile (in complain mode - so for ping on Ubuntu, this actually has no security impact).
Now:
user@ubuntu-
#include <err.h>
#include <unistd.h>
int main(int argc, char **argv) {
execv(argv[1], argv+2);
err(1, "execv");
}
user@ubuntu-
user@ubuntu-
user@ubuntu-
user@ubuntu-
PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.034 ms
64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.043 ms
[...]
Then, in a second terminal, you can see that ping is running unconfined:
user@ubuntu-
unconfined user 12969 0.0 0.0 23500 1108 pts/6 S+ 16:56 0:00 /bin/ping 127.0.0.1
unconfined user 12999 0.0 0.0 21536 1084 pts/7 R+ 16:58 0:00 grep --color=auto /bin/ping
user@ubuntu-
Uid: 1000 1000 0 1000
yep thats a problem if they are expecting that to work. That being said people are using it this way so we are going to have to request a CVE.
I am still coordinating with suse and debian but I at the moment I expect we will make this bug public next week.