From 1cee0f715b2ecf6a81168c990c44cf8fa8a7be6b Mon Sep 17 00:00:00 2001
From: "Chia-Lin Kao (AceLan)" <acelan.kao@canonical.com>
Date: Tue, 6 Oct 2026 15:26:48 +0800
Subject: [PATCH 1/2] UBUNTU: SAUCE: apparmor: only arm the temporal cache
 timer on the cached node

When userspace replies to a prompt with URESPONSE_NO_CACHE and
aa_cache_timeout is set, knotif_update_from_uresp_perm() inserts the
notification's audit node into the profile learning cache and schedules
a delayed work to drop it again after the timeout.

The return value of insert_in_cache() is ignored. If an equivalent
entry is already cached, the existing entry is updated instead and the
new node is never added to the cache, so the cache holds no reference to
it. The delayed work is still armed on that node. Once the notification
completes the last reference is dropped and the node is freed through
call_rcu(), whose rcu_head shares storage with the delayed_work. The
pending timer then fires on freed memory:

  WARNING: kernel/workqueue.c:2351 at __queue_work+0x190/0x390
  Oops: general protection fault, probably for non-canonical address 0xdead00000000012a
  RIP: __run_timers+0x1e0/0x2c0
  Kernel panic - not syncing: Fatal exception in interrupt

Only schedule the expiry work when the node was actually inserted and is
owned by the cache.

BugLink: https://bugs.launchpad.net/bugs/2168310
Fixes: be9179d97169 ("UBUNTU: SAUCE: apparmor5.0.0 [48/57]: apparmor: add temporal caching to audit responses.")
---
 security/apparmor/notify.c | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/security/apparmor/notify.c b/security/apparmor/notify.c
index 2e665ee4da0bd..b4d01c7f3dafa 100644
--- a/security/apparmor/notify.c
+++ b/security/apparmor/notify.c
@@ -904,10 +904,11 @@ static void knotif_update_from_uresp_perm(struct aa_knotif *knotif,
 							  struct aa_audit_node,
 							  knotif);
 
-		insert_in_cache(knotif);
-		INIT_DELAYED_WORK(&node->work, audit_cache_work_function);
-		schedule_delayed_work(&node->work,
-				      secs_to_jiffies(aa_cache_timeout));
+		if (insert_in_cache(knotif)) {
+			INIT_DELAYED_WORK(&node->work, audit_cache_work_function);
+			schedule_delayed_work(&node->work,
+					      secs_to_jiffies(aa_cache_timeout));
+		}
 	} /* cache_response */
 }
 
-- 
2.53.0

