Look up another CVE · open CVE-2026-90231 in the interactive tracker
CVE-2026-90231
apparmor: fix unconfined user namespace restriction forced stack
Published 2026-09-17 (31 days ago) by the Linux kernel CNA. Subsystem security/apparmor. Debian urgency: unimportant.
What to do, per Debian release
Debian's own status for CVE-2026-90231 in every release this site tracks, and what each one means in practice. Every status below is the one the Debian Security Team publishes for this CVE. source
| Release | Status | Version | What this means |
|---|---|---|---|
| Debian 12bookworm | not affected | 6.1.190-1 | Nothing to do. bookworm never shipped the vulnerable code. |
| Debian 13trixie | vulnerable | 6.12.113-1 | No fix published anywhere yet, neither in Debian nor upstream for the series trixie tracks. Watch the Debian tracker page for this CVE. Advisories for trixie have historically landed a median of 11 days after publication. |
| Debian 14forky | fixed | 7.2.6-1 | Update the kernel and reboot. Fixed in 7.2.6-1. A running kernel keeps the old code until the machine restarts. |
| Debian unstablesid | fixed | 7.2.6-1 | Update the kernel and reboot. Fixed in 7.2.6-1. A running kernel keeps the old code until the machine restarts. |
The vulnerability
What the bug is
If a task is already confined by a stack the unprivileged transition restriction on unconfined is not correctly, applied. This results in an escape if two transitions through an unconfined profile can be executed. Fix this by pushing the check into the per profile label build. The check will always be done against unconfined and result in a stack of just the unconfined component when necessary.
Where it lives
The fix touches these files. If the subsystem is one you do not use, the practical exposure is lower, though the package is still the vulnerable one.
security/apparmor/domain.c
- What this is
- APPARMOR SECURITY MODULEMAINTAINERS section matched on security/apparmor/ · apparmor@lists.ubuntu.com · Supported
Check it on the machine
grep -w CONFIG_SECURITY_APPARMOR /boot/config-$(uname -r)Reads the booted kernel's own configuration, on the machine and nowhere else. =y is built in, =m is a module, and an is not set line means the code is not there.
Show whether Debian builds this, per release
Debian builds this code. Every release below compiles the affected file into the kernels it ships.
- bookworm, trixie, forky, sidy
- y
- built into the kernel image on every flavour - only a patch removes it
- Build switch
- CONFIG_SECURITY_APPARMOR
From the configuration Debian publishes for every kernel flavour it builds. It covers only the architectures Debian ships a linux-config package for, and nothing about a kernel you built yourself. Debian's own status above stays authoritative about the source package.MAINTAINERS kbuild Makefiles Debian linux-config packages
Signals
- Published
- 2026-09-17 (31 days ago)source
- CVSS
- 8.4 high
CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:Nsource recompute it - Attack vector
- local (AV:L)source
- EPSS
- 0.17%, higher than 5.9% of all CVEssource
- CISA KEV
- not listedthe KEV catalogue
- Debian urgency
- unimportantsource
- Subsystem
- security/apparmor
Upstream fixes
The versions the CNA records as introducing and fixing this, and the commit for each. source
| Introduced | Fixed in | Commit |
|---|---|---|
| 6.7 | 6.18.52 | 7d1099b86356 |
| 6.7 | 7.2.6 | 7da0bdf0610f |
| 6.7 | 7.3 | 08c2f7c8d4b1 |
Why the CNA scored it this way
Quoted from the kernel CNA's own scoring file, word for word. A highlighted metric carries the most severe value CVSS v3.1 defines for it, which is what pushes the score up. source
- AV:LAttack vector, local
- The attacker reaches aa_change_profile() by writing a changeprofile or exec command to /proc/self/attr/current or /proc/self/attr/exec (proc_pid_attr_write → apparmor_setprocattr → do_setattr) or via lsm_set_self_attr(2); the profile name is local process input, not a remote protocol message.
- AC:LAttack complexity, low
- Success is two attacker-driven writes plus execve. The vulnerable gate is the pointer test label == &labels_ns(label)->unconfined->label in aa_change_profile(), so the first transition off the ns unconfined sentinel makes the second skip forced stacking; change_profile_perms() allows any target from a profile_unconfined() component, with no race.
- PR:LPrivileges required, low
- Writing /proc/self/attr/current or /proc/self/attr/exec requires only that the opener is current (proc_pid_attr_write); there is no capable() check. The intended victims are tasks that fail cap_capable(current_cred(), &init_user_ns, CAP_MAC_OVERRIDE), so a plain unprivileged local user, including one with caps only in a user namespace, suffices.
- UI:NUser interaction, none
- The attacker opens and writes their own /proc/self/attr/current or /proc/self/attr/exec, then execve()s to apply AA_CHANGE_ONEXEC; no other user must mount media, open a file, or confirm the transition.
- S:CScope, changed
- fn_label_build_in_scope() then aa_replace_current_label() drop the stacked ns unconfined profile that AppArmor was using as the MAC authority on the task, so later hooks (apparmor_userns_create, file mediation) run outside the policy that stack was required to keep applied—an AppArmor policy/sandbox escape.
- C:HConfidentiality impact, high
- After the second aa_change_profile()/handle_onexec() build, the task’s label no longer includes ns unconfined, so AppArmor no longer denies reads a stacked or confined profile would have blocked, and a remaining FLAG_UNCONFINED label skips apparmor_userns_create() mediation, exposing userns-gated kernel interfaces the restriction was meant to hide.
- I:HIntegrity impact, high
- The same aa_replace_current_label() replacement lets the task perform writes and capability-using operations AppArmor was mediating, including unshare(CLONE_NEWUSER) from a FLAG_UNCONFINED profile, yielding CAP_SYS_ADMIN/CAP_NET_ADMIN in that namespace—the integrity of the MAC policy the forced stack was supposed to preserve.
- A:NAvailability impact, none
- The flaw only skips the forced-stack conversion in aa_change_profile()/handle_onexec(); it does not dereference invalid pointers, corrupt memory, or trigger BUG_ON, oops, panic, or deadlock.