Cloudanix VulnDB

CVE-2026-89762

High · 7.8

CVSS

7.8

EPSS

0.1%

Published

Sep 11, 2026

CISA due date

—

Cloudanix analysis

Schedule a fix SSVC: Track

A bug in the Linux kernel's security software can let an attacker on the same machine take over the whole system by messing up how credentials are handled in memory.

Exploitation
Local Privilege
Attacker needs
Low Privilege
Complexity
Moderate
Impact
Full Compromise
Component
OS kernel
Class
Use After Free
Remediation
Upgrade
Effort
Medium
Patch risk
Low

What it actually does

Use-after-free on struct cred objects triggered when AppArmor replaces credentials inside LSM hooks while tasks hold overridden credentials or external references to current_cred, allowing later dereferences to freed memory.

Why it matters to the business

Linux systems using AppArmor may experience kernel crashes, memory corruption, or local privilege escalation, potentially leading to full system compromise, service outages, or data breaches; urgency is moderate given low EPSS and no known exploitation campaigns.

How an attack unfolds

An attacker triggers AppArmor label replacement (for example by disabling a profile) while a process is blocked in a VFS operation such as splice from FUSE, manipulates credential references via override_creds, forces the replacement path, then reverts, leaving task->real_cred pointing at freed memory that subsequent syscalls dereference.

How to fix it

Apply the upstream kernel patch that moves credential replacement to task_work instead of direct replacement inside LSM hooks; rebuild and reboot to the fixed kernel. Continue monitoring for any remaining direct cred replacements noted in sb_pivotroot and proc_pid_attr_write paths.

How to confirm the fix worked

Confirm the kernel source contains the task_work-based replacement logic for begin_current_label_crit_section; run the provided test case (aa-disable during splice from FUSE) under KASAN and verify absence of UAF splats; check that aa_task_ctx copy logic manually copies members rather than using structure assignment.

Typical attack path

  1. Obtain local execution on a Linux system enforcing AppArmor profiles
  2. Arrange for a process to block inside a VFS hook (e.g., splice on FUSE passthrough) while holding a reference to its current credentials
  3. Trigger profile update or label change that marks the label stale
  4. AppArmor LSM hook calls begin_current_label_crit_section and performs direct cred replacement
  5. Process resumes and reverts credentials, leaving real_cred pointing to freed struct cred
  6. Subsequent credential access (getuid, etc.) triggers UAF

How to detect it

Look for KASAN use-after-free reports referencing struct cred or current_cred during or immediately after AppArmor profile changes; inspect audit logs for aa-disable or profile load events coinciding with processes blocked on splice or other VFS operations; examine task_struct credential pointers after revert_creds calls in crash dumps.

What your security team should do

  • Prioritize patching all Linux kernels that include AppArmor within the next 30 days
  • Enable KASAN or similar memory debugging on test systems to validate the fix
  • Review any custom AppArmor profiles or FUSE-based workloads that could trigger the race
  • Monitor upstream stable branches for additional hardening around credential replacement

The record

In the Linux kernel, the following vulnerability has been resolved: apparmor: fix cred UAF caused by begin_current_label_crit_section() AppArmor's begin_current_label_crit_section() is a scary function called from lots of LSM hooks (in particular VFS/socket-related ones) that checks if the label referenced by the current creds is marked FLAG_STALE, and if so, attempts to use aa_replace_current_label() to replace the creds with an updated version that uses a new label. The first problem with this is that it would directly lead to UAF of `struct cred` if anything in the kernel takes a pointer to the current creds and accesses these past a security hook invocation that replaces creds, like so: ``` const struct cred *cred = current_cred(); alloc_file_pseudo(...); uid_t uid = cred->euid; ``` I don't know if anything in the kernel actually does this, but I think it is very surprising that this pattern could lead to UAF. The second problem is that things go wrong when aa_replace_current_label() runs with overridden credentials. aa_replace_current_label() bails out if `current_cred() != current_real_cred()` (mirroring the check in proc_pid_attr_write()), but this check can't actually reliably detect overridden credentials because the overridden creds can be the same as the objective creds. So in approximately the following scenario, things go wrong: 1. task begins with <creds A> (as both objective and subjective creds), with refcount=2 2. task grabs an extra reference on <creds A> for overriding 3. task calls override_creds(<creds A>), which returns a pointer to the old subjective creds (<creds A>) 4. task enters AppArmor LSM hook 5. AppArmor checks that objective/subjective creds are equal 6. AppArmor replaces both cred pointers with <creds B> and drops 2 refs on <creds A> 7. task leaves AppArmor LSM hook 8. task calls revert_creds(<creds A>) 9. now task->cred is <creds A> while task->real_cred is <creds B>, but the task_struct logically holds two references to <creds B> 10. another task drops the extra reference on <creds A> that was used for overriding, refcount drops to 0 11. now task->real_cred points to freed creds At this point, any access to current_cred() will be UAF. I have a test case where I run aa-disable on a profile while a process using that profile is blocked on splice() from a FUSE passthrough file into a full pipe; after the profile update, the pipe becomes empty, splice() resumes, the credentials go out of sync, and a subsequent getuid() syscall results in a KASAN UAF splat. To fix this, instead of directly replacing creds, do it via task_work that will run at the end of the current syscall. (The point in time at which the cred replacement happens should have no correctness impact; it is just a performance optimization to avoid unnecessarily touching the refcount of the new label.) Note that AppArmor still performs direct cred replacements in the sb_pivotroot LSM hook after this change, and that direct cred replacements can still happen in VFS ->write() callbacks via proc_pid_attr_write(). There are two options for what to do with aa_dup_task_ctx(): Either explicitly reset new->label_replacement_pending after the entire aa_task_ctx has been copied, or switch to manually copying members over. I am switching to manually copying members over because that should make bugs more obvious.

Affected packages

Ecosystem Package Introduced Fixed