Cloudanix VulnDB

CVE-2026-90246

High · 7.1

CVSS

7.1

EPSS

0.2%

Published

Sep 17, 2026

CISA due date

—

Cloudanix analysis

Schedule a fix SSVC: Track

A bug in the Linux kernel's security policy handler could let a logged-in user peek at protected memory or crash the computer by feeding it a specially made rules file.

Exploitation
Local Privilege
Attacker needs
Low Privilege
Complexity
Low
Impact
Data Exposure
Component
OS kernel
Class
Improper Input Validation
Remediation
Patch
Effort
Medium
Patch risk
Low

What it actually does

Integer overflow in verify_tags() bounds check allows out-of-bounds read of the tagset table during AppArmor policy unpacking from a crafted blob.

Why it matters to the business

Local attackers on affected Linux systems can disclose kernel memory or trigger crashes, undermining mandatory access controls and potentially exposing sensitive data or disrupting services.

How an attack unfolds

An attacker creates a nested user namespace, crafts a policy blob containing a tagset count near U32_MAX to bypass the modular wrap check in verify_tags(), then loads it via aa_replace_profiles to reach the out-of-bounds read in unpack_tags.

How to fix it

Apply the upstream kernel fix that casts the addition to u64 before comparison in verify_tags(). Rebuild, test, and deploy the patched kernel across all affected systems.

How to confirm the fix worked

Confirm the source change performs the i + cnt comparison in u64. Attempt to load a test policy containing the previously overflowing count values and verify no out-of-bounds access occurs.

Typical attack path

  1. Create a matched-level nested user namespace
  2. Craft malicious policy blob with overflowing u32 count in tagsets table
  3. Invoke policy load path through aa_replace_profiles
  4. Bypass bounds check in verify_tags due to u32 wrap
  5. Perform out-of-bounds read while walking sets.table

How to detect it

Review kernel audit logs and dmesg for AppArmor unpack failures or crashes originating from verify_tags or unpack_tags. Correlate with unprivileged policy management syscalls.

What your security team should do

  • Prioritize kernel updates on all systems using AppArmor
  • Audit and restrict unprivileged user namespace creation where possible
  • Enable kernel hardening features such as lockdown mode
  • Monitor AppArmor policy load events from non-init namespaces

The record

In the Linux kernel, the following vulnerability has been resolved: apparmor: fix integer overflow in verify_tags() bounds check verify_tags() validates the tagset table unpacked from a policy blob. For each set it reads a count and checks that advancing the index by that count stays inside sets.table[]: u32 cnt = tags->sets.table[i]; if (i+cnt >= tags->sets.size) { i, cnt and sets.size are all u32, so i+cnt is evaluated modulo 2^32. sets.table[] is filled by unpack_tagsets() with aa_unpack_u32(), so every entry is a raw unbounded 32-bit word taken from the policy blob, and verify_tags() is the function that is supposed to validate it. A count close to U32_MAX makes the sum wrap to a small value, the guard passes, and the inner loop then walks sets.table[++i] past the end of the kcalloc(size, sizeof(u32)) allocation. Note that sets.size is bounded by 65535, because unpack_tagsets() reads it with aa_unpack_array() as a u16, so the wrap cannot be reached by growing the table; it is reached purely through the attacker-supplied count. With sets.size = 2 and sets.table = { 0, 0xffffffff }: i = 0: cnt = 0, guard 0 + 0 >= 2 is false, inner loop does not run i = 1: cnt = 0xffffffff, guard (1 + 0xffffffff) mod 2^32 == 0 >= 2 is false, so the guard is bypassed and the inner loop reads sets.table[2] -- one element past a two element allocation The walk continues until an out-of-bounds value happens to be >= hdrs.size or the access faults, so a crafted policy yields an out-of-bounds read on the policy load path (aa_replace_profiles -> aa_unpack -> unpack_policydb -> unpack_tags -> verify_tags). unpack_tags() runs before the perms and DFA tables are unpacked, so no other table needs to be well formed to reach it. Policy load is gated by aa_may_manage_policy(), which checks CAP_MAC_ADMIN relative to the subject's own user namespace rather than the init user namespace, so with the default unprivileged_userns_apparmor_policy=1 the path is reachable from an unprivileged task in a matched-level nested namespace, not only by a globally privileged one. Perform the addition in u64 so that it cannot wrap, restoring the intended i + cnt < sets.size guarantee.

Affected packages

Ecosystem Package Introduced Fixed