CVE-2026-45884
Description
In the Linux kernel, the following vulnerability has been resolved:
apparmor: avoid per-cpu hold underflow in aa_get_buffer
When aa_get_buffer() pulls from the per-cpu list it unconditionally decrements cache->hold. If hold reaches 0 while count is still non-zero, the unsigned decrement wraps to UINT_MAX. This keeps hold non-zero for a very long time, so aa_put_buffer() never returns buffers to the global list, which can starve other CPUs and force repeated kmalloc(aa_g_path_max) allocations.
Guard the decrement so hold never underflows.
Affected products
1Patches
8202824a1f89aapparmor: avoid per-cpu hold underflow in aa_get_buffer
1 file changed · +2 −2
security/apparmor/lsm.c+2 −2 modifieddiff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index 9a78fd36542d62..8855fb4b883428 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -1863,7 +1863,8 @@ char *aa_get_buffer(bool in_atomic) if (!list_empty(&cache->head)) { aa_buf = list_first_entry(&cache->head, union aa_buffer, list); list_del(&aa_buf->list); - cache->hold--; + if (cache->hold) + cache->hold--; cache->count--; put_cpu_ptr(&aa_local_buffers); return &aa_buf->buffer[0]; -- cgit 1.3-korg
80c334acc6d0apparmor: avoid per-cpu hold underflow in aa_get_buffer
1 file changed · +2 −2
security/apparmor/lsm.c+2 −2 modifieddiff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index be3678d08ed23c..13c9bfdf65ff57 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -2136,7 +2136,8 @@ char *aa_get_buffer(bool in_atomic) if (!list_empty(&cache->head)) { aa_buf = list_first_entry(&cache->head, union aa_buffer, list); list_del(&aa_buf->list); - cache->hold--; + if (cache->hold) + cache->hold--; cache->count--; put_cpu_ptr(&aa_local_buffers); return &aa_buf->buffer[0]; -- cgit 1.3-korg
640cf2f09575apparmor: avoid per-cpu hold underflow in aa_get_buffer
1 file changed · +2 −2
security/apparmor/lsm.c+2 −2 modifieddiff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index 8d5d9a966b719e..9175fd677ef3db 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -2137,7 +2137,8 @@ char *aa_get_buffer(bool in_atomic) if (!list_empty(&cache->head)) { aa_buf = list_first_entry(&cache->head, union aa_buffer, list); list_del(&aa_buf->list); - cache->hold--; + if (cache->hold) + cache->hold--; cache->count--; put_cpu_ptr(&aa_local_buffers); return &aa_buf->buffer[0]; -- cgit 1.3-korg
4bcddd0f6b2eapparmor: avoid per-cpu hold underflow in aa_get_buffer
1 file changed · +2 −2
security/apparmor/lsm.c+2 −2 modifieddiff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index 8d5d9a966b719e..9175fd677ef3db 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -2137,7 +2137,8 @@ char *aa_get_buffer(bool in_atomic) if (!list_empty(&cache->head)) { aa_buf = list_first_entry(&cache->head, union aa_buffer, list); list_del(&aa_buf->list); - cache->hold--; + if (cache->hold) + cache->hold--; cache->count--; put_cpu_ptr(&aa_local_buffers); return &aa_buf->buffer[0]; -- cgit 1.3-korg
202824a1f89aapparmor: avoid per-cpu hold underflow in aa_get_buffer
1 file changed · +2 −2
security/apparmor/lsm.c+2 −2 modifieddiff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index 9a78fd36542d62..8855fb4b883428 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -1863,7 +1863,8 @@ char *aa_get_buffer(bool in_atomic) if (!list_empty(&cache->head)) { aa_buf = list_first_entry(&cache->head, union aa_buffer, list); list_del(&aa_buf->list); - cache->hold--; + if (cache->hold) + cache->hold--; cache->count--; put_cpu_ptr(&aa_local_buffers); return &aa_buf->buffer[0]; -- cgit 1.3-korg
80c334acc6d0apparmor: avoid per-cpu hold underflow in aa_get_buffer
1 file changed · +2 −2
security/apparmor/lsm.c+2 −2 modifieddiff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index be3678d08ed23c..13c9bfdf65ff57 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -2136,7 +2136,8 @@ char *aa_get_buffer(bool in_atomic) if (!list_empty(&cache->head)) { aa_buf = list_first_entry(&cache->head, union aa_buffer, list); list_del(&aa_buf->list); - cache->hold--; + if (cache->hold) + cache->hold--; cache->count--; put_cpu_ptr(&aa_local_buffers); return &aa_buf->buffer[0]; -- cgit 1.3-korg
640cf2f09575apparmor: avoid per-cpu hold underflow in aa_get_buffer
1 file changed · +2 −2
security/apparmor/lsm.c+2 −2 modifieddiff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index 8d5d9a966b719e..9175fd677ef3db 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -2137,7 +2137,8 @@ char *aa_get_buffer(bool in_atomic) if (!list_empty(&cache->head)) { aa_buf = list_first_entry(&cache->head, union aa_buffer, list); list_del(&aa_buf->list); - cache->hold--; + if (cache->hold) + cache->hold--; cache->count--; put_cpu_ptr(&aa_local_buffers); return &aa_buf->buffer[0]; -- cgit 1.3-korg
4bcddd0f6b2eapparmor: avoid per-cpu hold underflow in aa_get_buffer
1 file changed · +2 −2
security/apparmor/lsm.c+2 −2 modifieddiff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index 8d5d9a966b719e..9175fd677ef3db 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -2137,7 +2137,8 @@ char *aa_get_buffer(bool in_atomic) if (!list_empty(&cache->head)) { aa_buf = list_first_entry(&cache->head, union aa_buffer, list); list_del(&aa_buf->list); - cache->hold--; + if (cache->hold) + cache->hold--; cache->count--; put_cpu_ptr(&aa_local_buffers); return &aa_buf->buffer[0]; -- cgit 1.3-korg
Vulnerability mechanics
Root cause
"Missing guard on unsigned integer decrement in aa_get_buffer allows cache->hold to underflow when it reaches 0 while count is still non-zero."
Attack vector
An attacker on the same system can trigger AppArmor path operations that call aa_get_buffer() repeatedly on a given CPU. When the per-CPU buffer cache's hold counter reaches 0 while count is still non-zero, the unconditional decrement wraps the unsigned hold to UINT_MAX [patch_id=2661697]. This prevents aa_put_buffer() from returning buffers to the global list, starving other CPUs and forcing repeated kmalloc(aa_g_path_max) allocations, leading to performance degradation or denial of service.
Affected code
The vulnerable code is in the aa_get_buffer() function in security/apparmor/lsm.c. The unconditional `cache->hold--` on line 2137 (or 1863 in some backport versions) is the specific fault [patch_id=2661697].
What the fix does
The patch adds a guard (`if (cache->hold) cache->hold--`) before the decrement in aa_get_buffer() inside security/apparmor/lsm.c [patch_id=2661697]. This ensures the unsigned hold counter never underflows when it is already 0. By preventing the wrap to UINT_MAX, the fix restores the correct behavior where aa_put_buffer() can eventually return buffers to the global list when hold reaches 0.
Preconditions
- inputAttacker must be able to trigger AppArmor path operations on the same CPU that invoke aa_get_buffer()
- configThe per-CPU buffer cache's hold counter must reach 0 while count is still non-zero
Generated on May 27, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
4News mentions
0No linked articles in our index yet.