Skip to main content
Vulnerability Database/CVE-2026-89761

CVE-2026-89761: Linux Kernel AppArmor Privilege Escalation

CVE-2026-89761 is a privilege escalation flaw in Linux kernel AppArmor caused by an out-of-bounds write during label vector null termination. This post explains the technical details, affected versions, and mitigation steps.

Published:

CVE-2026-89761 Overview

CVE-2026-89761 is an out-of-bounds write vulnerability in the Linux kernel's AppArmor label security module (LSM). The flaw resides in aa_vec_unique(), which null-terminates a vector at vec[n - dups] when the VEC_FLAG_TERMINATE flag is passed. When components are all distinct, dups is zero and the terminator is written to vec[n], one entry past the allocated buffer. The caller path aa_label_strn_parse() allocates the vector via vec_setup(), which does not reserve the terminator slot, producing an out-of-bounds write on both the local stack array and the kzalloc() heap allocation.

Critical Impact

An unprivileged local user on a system with loaded AppArmor policy can trigger a kernel memory corruption by writing a crafted label to /proc/self/attr/apparmor/current or via lsm_set_self_attr(2).

Affected Products

  • Linux kernel (upstream) versions containing the vulnerable aa_vec_unique() and vec_setup() code paths in the AppArmor LSM
  • Distributions shipping affected mainline and stable Linux kernel branches
  • Systems with AppArmor enabled and policy loaded

Discovery Timeline

  • 2026-09-11 - CVE-2026-89761 published to the National Vulnerability Database (NVD)
  • 2026-09-13 - Last updated in NVD database

Technical Details for CVE-2026-89761

Vulnerability Analysis

The vulnerability is an out-of-bounds write [CWE-787] in the AppArmor label parser. aa_vec_unique() is designed to deduplicate a vector of profile pointers and, when VEC_FLAG_TERMINATE is set, append a NULL terminator at index n - dups. The function's contract requires the caller to provide space for n + 1 entries so that the terminator has a valid slot when dups == 0.

aa_label_strn_parse() violates that contract. It initializes its vector using vec_setup(profile, vec, len, gfp), which allocates exactly len entries. Below the LOCAL_VEC_ENTRIES threshold, vec_setup() uses a local stack array of LOCAL_VEC_ENTRIES pointers; above it, it calls kzalloc() for len pointers. Neither path reserves the terminator slot.

When a parsed label contains all-distinct components, aa_vec_unique() writes NULL at vec[len]. This corrupts an adjacent stack frame when len == LOCAL_VEC_ENTRIES, or an adjacent heap object when len > LOCAL_VEC_ENTRIES.

Root Cause

The root cause is a mismatch between the buffer sizing contract of aa_vec_unique() and the actual allocation performed by vec_setup() and DEFINE_VEC(). Two other VEC_FLAG_TERMINATE call sites operate on vectors sized by aa_label_alloc(), which explicitly reserves an extra slot with the comment "+ 1 for null terminator entry on vec". The parse path was missing that reservation. Additionally, label_count_strn_entries() does not bound the number of //&-separated components, so an attacker controls len.

Attack Vector

An unprivileged local task can reach the vulnerable parser through several interfaces. Writing to /proc/self/attr/apparmor/current and calling lsm_set_self_attr(2) both route through do_setattr(), which parses the label name before the change_profile permission check runs. The query_label() path exposed via the securityfs .access file is mode 0666 and performs no permission check. Every component in the label must resolve to a loaded profile, so exploitation requires a system with AppArmor policy loaded. Successful exploitation can lead to kernel memory corruption, denial of service, or local privilege escalation depending on adjacent object layout.

No public proof-of-concept exploit is currently available for CVE-2026-89761.

Detection Methods for CVE-2026-89761

Indicators of Compromise

  • Unexpected kernel oops, slab-out-of-bounds reports from KASAN, or stack corruption warnings referencing aa_vec_unique, aa_label_strn_parse, or vec_setup in dmesg.
  • Unprivileged processes writing unusually long or highly segmented //&-delimited strings to /proc/self/attr/apparmor/current.
  • Anomalous access patterns against the securityfs .access file (/sys/kernel/security/apparmor/.access) from non-administrative accounts.

Detection Strategies

  • Enable KASAN on test and staging kernels to catch the out-of-bounds write at the moment aa_vec_unique() writes the terminator.
  • Instrument the LSM audit subsystem to record AA_AUDIT events tied to change_profile and label parsing failures, then baseline normal application behavior.
  • Correlate lsm_set_self_attr(2) syscall telemetry with process lineage to flag unprivileged binaries attempting profile changes.

Monitoring Recommendations

  • Ship auditd and kernel ring buffer logs to a central analytics tier for search on AppArmor parser errors and kernel warnings.
  • Alert on repeated EINVAL or ENOMEM returns from do_setattr() originating from the same PID or user session.
  • Track kernel version and AppArmor policy load state across the fleet to identify hosts eligible for exploitation.

How to Mitigate CVE-2026-89761

Immediate Actions Required

  • Apply the upstream Linux kernel fix that reserves the terminator slot in vec_setup() and DEFINE_VEC() and rebuild affected kernels.
  • On systems where patching is delayed, evaluate temporarily unloading AppArmor policy or disabling the AppArmor LSM if operational risk allows.
  • Restrict access to the securityfs .access file by remounting securityfs with tighter permissions or applying host hardening baselines.
  • Inventory all hosts running affected kernel versions with AppArmor policy loaded and prioritize multi-tenant and shared systems.

Patch Information

The fix reserves the additional entry in vec_setup() and DEFINE_VEC() so the terminator write in aa_vec_unique() stays within the allocation. Upstream commits addressing CVE-2026-89761 are available in the stable tree: Linux Kernel Commit 28069434aef6, Linux Kernel Commit 36bdd0b45ec3, Linux Kernel Commit 9124e078ea22, and Linux Kernel Commit 9f1e40193eef. Consume the fix through your distribution's kernel update channel.

Workarounds

  • Restrict local shell access on multi-tenant Linux hosts until patched kernels are deployed.
  • Consider disabling AppArmor at boot via apparmor=0 on the kernel command line where the security tradeoff is acceptable and other LSMs remain enforced.
  • Deploy stricter seccomp filters on untrusted workloads to block the lsm_set_self_attr(2) syscall and writes to /proc/self/attr/apparmor/current.
bash
# Verify AppArmor status and kernel version, then plan patch rollout
uname -r
aa-status || cat /sys/kernel/security/apparmor/profiles | wc -l

# Optional: disable AppArmor at next boot on hosts where policy is not required
# Edit /etc/default/grub and append apparmor=0 to GRUB_CMDLINE_LINUX, then:
sudo update-grub

Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

Experience the Most Advanced Cybersecurity Platform

See how the world’s most intelligent, autonomous cybersecurity platform can protect your organization today and into the future.