[BUG] apparmor: AA_BUG aa_policy_destroy on aa_alloc_profile error path

From: Farhad Alemi

Date: Thu May 28 2026 - 23:32:30 EST


Hello John and the AppArmor team,

I am reporting an AppArmor AA_BUG WARN in aa_policy_destroy() found
by syzkaller as part of research at the SEFCOM Lab at ASU.

Summary:
A write(2) to /proc/<pid>/attr/<lsm>/current that drives the
aa_change_hat() -> aa_new_learning_profile() -> aa_alloc_null() ->
aa_alloc_profile() chain takes the error-rollback path at
security/apparmor/policy.c:409 (aa_alloc_profile()'s `fail:` label
calling aa_free_profile(profile)). aa_free_profile() then calls
aa_policy_destroy(&profile->base) at security/apparmor/policy.c:327,
which trips its first AA_BUG at security/apparmor/lib.c:509:

void aa_policy_destroy(struct aa_policy *policy)
{
AA_BUG(on_list_rcu(&policy->profiles)); <-- :509
AA_BUG(on_list_rcu(&policy->list));
...
}

/* security/apparmor/include/policy.h:60 */
#define on_list_rcu(X) (!list_empty(X) && (X)->prev != LIST_POISON2)

The WARN reproduces the macro's condition verbatim (the kernel prints
the full stringified expression including the LIST_POISON2 numeric
0x122 + 0xdead000000000000UL); see crash-report.txt for the full
header.

Observed on:
- Linux v7.1-rc3-200-g70eda68668d1-dirty (the only local dirty file
is drivers/tty/serial/serial_core.c, a console guard our fuzzing
harness uses, unrelated to security/apparmor/), x86_64, QEMU Q35
- AA_BUG asserts enabled + panic_on_warn (the crash tail prints
"Kernel panic - not syncing: kernel: panic_on_warn set")
- Source inspection of linus/master at commit e8c2f9fdadee
(v7.1-rc4-754-ge8c2f9fdadee) shows the buggy structure is
unchanged: security/apparmor/lib.c:509 still does
AA_BUG(on_list_rcu(&policy->profiles)); aa_alloc_profile()'s fail
path at security/apparmor/policy.c:409 still calls
aa_free_profile(profile); aa_free_profile() at policy.c:327 still
calls aa_policy_destroy(&profile->base). As no reproducer is available
for this seed, I have not re-triggered the crash against e8c2f9fdadee.

Expected behavior:
Either aa_alloc_profile()'s rollback path must guarantee
profile->base.profiles is empty (or list_del'd so prev == LIST_POISON2)
before calling aa_free_profile(), or aa_policy_destroy()'s AA_BUG
should be softened to a WARN_ON-and-drain so it does not panic on an
alloc-rollback path. The maintainers are best placed to choose which
side of the contract owns this.

Reproducer:
A standalone .syz or C reproducer was not produced for this seed;
the crash fired during automated /proc/<pid>/attr/* fuzzing. The
console report is attached as crash-report.txt.

Novelty check:
I searched the syzbot dashboard's upstream open, fixed, stable, and
invalid (per-subsystem apparmor) namespaces; the Android dashboard;
the marc.info linux-security-module archive; and the complete
apparmor@xxxxxxxxxxxxxxxx list archive (2010 through 2026, full
message bodies), for "aa_policy_destroy", "on_list_rcu(&policy->
profiles)", "aa_alloc_profile" + "WARNING", and "AA_BUG" +
"policy->profiles". I did not find a prior report of this crash. The
three apparmor-titled entries in the syzbot invalid namespace are in
different functions (apparmor_sk_free_security UAF, aa_label_sk_perm
UAF, apparmor_file_open data-race). The only aa_policy_destroy
mentions on the AppArmor list are a 2022 "Fix memleak in alloc_ns()"
patch (a different aa_policy_destroy(&ns->base) call site), and there
is no occurrence of on_list_rcu(&policy->profiles) anywhere in the
list history.

I appreciate your time and consideration, and I'm grateful for your
work on this subsystem. I'd be glad to test any candidate patches.

Regards,
</TASK>
------------[ cut here ]------------
AppArmor WARN aa_policy_destroy: (((!list_empty(&policy->profiles) && (&policy->profiles)->prev != ((void *) 0x122 + (0xdead000000000000UL))))):
WARNING: security/apparmor/lib.c:509 at aa_policy_destroy+0x169/0x1c0 security/apparmor/lib.c:509, CPU#0: syz.3.739/13898
Modules linked in:
CPU: 0 UID: 0 PID: 13898 Comm: syz.3.739 Not tainted 7.1.0-rc3-00200-g70eda68668d1-dirty #1 PREEMPT(full)
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2 04/01/2014
RIP: 0010:aa_policy_destroy+0x170/0x1c0 security/apparmor/lib.c:509
Code: 85 ed 7e 4d e8 c1 9a dc fd 5b 41 5c 41 5e 41 5f 5d c3 cc cc cc cc cc e8 ae 9a dc fd 48 8d 3d 87 1c 0b 05 48 c7 c6 b8 a7 82 87 <67> 48 0f b9 3a e9 04 ff ff ff e8 91 9a dc fd 48 8d 3d 7a 1c 0b 05
RSP: 0018:ffffc9000141f500 EFLAGS: 00010293
RAX: ffffffff83a572b2 RBX: ffff88811907a400 RCX: ffff88812f778000
RDX: 0000000000000000 RSI: ffffffff8782a7b8 RDI: ffffffff88b08f40
RBP: 0000000000000cc0 R08: 0000000000000cc0 R09: 00000000ffffffff
R10: dffffc0000000000 R11: fffffbfff100a27f R12: dead000000000122
R13: ffff88811907a400 R14: ffff88811907a428 R15: dffffc0000000000
FS: 00007f51fd2d76c0(0000) GS:ffff8882ab6b6000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 00007f51fe8cfe10 CR3: 000000011b6ea000 CR4: 0000000000750ef0
PKRU: 80000000
Call Trace:
<TASK>
aa_free_profile+0xa2/0x9f0 security/apparmor/policy.c:327
aa_alloc_profile+0x1f1/0x3f0 security/apparmor/policy.c:409
aa_alloc_null+0x2d/0x530 security/apparmor/policy.c:690
aa_new_learning_profile+0x226/0x4e0 security/apparmor/policy.c:767
build_change_hat+0x292/0x400 security/apparmor/domain.c:1079
change_hat security/apparmor/domain.c:1193 [inline]
aa_change_hat+0x1177/0x2fb0 security/apparmor/domain.c:1269
aa_setprocattr_changehat+0x4a6/0x5b0 security/apparmor/procattr.c:138
do_setattr+0x548/0x6a0
proc_pid_attr_write+0x5d1/0x630 fs/proc/base.c:2844
vfs_write+0x29f/0xb90 fs/read_write.c:686
ksys_write+0x155/0x270 fs/read_write.c:740
do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
do_syscall_64+0x15f/0x560 arch/x86/entry/syscall_64.c:94
entry_SYSCALL_64_after_hwframe+0x77/0x7f
RIP: 0033:0x7f51fe88778d
Code: ff c3 66 2e 0f 1f 84 00 00 00 00 00 90 f3 0f 1e fa 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 b0 ff ff ff f7 d8 64 89 01 48
RSP: 002b:00007f51fd2d7018 EFLAGS: 00000246 ORIG_RAX: 0000000000000001
RAX: ffffffffffffffda RBX: 00007f51feb15fa0 RCX: 00007f51fe88778d
RDX: 0000000000000022 RSI: 00002000000000c0 RDI: 0000000000000003
RBP: 00007f51fd2d7080 R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000001
R13: 00007f51feb16038 R14: 00007f51feb15fa0 R15: 00007ffc4916b870
</TASK>
----------------
Code disassembly (best guess):
0: 85 ed test %ebp,%ebp
2: 7e 4d jle 0x51
4: e8 c1 9a dc fd call 0xfddc9aca
9: 5b pop %rbx
a: 41 5c pop %r12
c: 41 5e pop %r14
e: 41 5f pop %r15
10: 5d pop %rbp
11: c3 ret
12: cc int3
13: cc int3
14: cc int3
15: cc int3
16: cc int3
17: e8 ae 9a dc fd call 0xfddc9aca
1c: 48 8d 3d 87 1c 0b 05 lea 0x50b1c87(%rip),%rdi # 0x50b1caa
23: 48 c7 c6 b8 a7 82 87 mov $0xffffffff8782a7b8,%rsi
* 2a: 67 48 0f b9 3a ud1 (%edx),%rdi <-- trapping instruction
2f: e9 04 ff ff ff jmp 0xffffff38
34: e8 91 9a dc fd call 0xfddc9aca
39: 48 8d 3d 7a 1c 0b 05 lea 0x50b1c7a(%rip),%rdi # 0x50b1cba

<<<<<<<<<<<<<<< tail report >>>>>>>>>>>>>>>

Modules linked in:
CPU: 0 UID: 0 PID: 13898 Comm: syz.3.739 Not tainted 7.1.0-rc3-00200-g70eda68668d1-dirty #1 PREEMPT(full)
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2 04/01/2014
RIP: 0010:aa_policy_destroy+0x170/0x1c0
Code: 85 ed 7e 4d e8 c1 9a dc fd 5b 41 5c 41 5e 41 5f 5d c3 cc cc cc cc cc e8 ae 9a dc fd 48 8d 3d 87 1c 0b 05 48 c7 c6 b8 a7 82 87 <67> 48 0f b9 3a e9 04 ff ff ff e8 91 9a dc fd 48 8d 3d 7a 1c 0b 05
RSP: 0018:ffffc9000141f500 EFLAGS: 00010293
RAX: ffffffff83a572b2 RBX: ffff88811907a400 RCX: ffff88812f778000
RDX: 0000000000000000 RSI: ffffffff8782a7b8 RDI: ffffffff88b08f40
RBP: 0000000000000cc0 R08: 0000000000000cc0 R09: 00000000ffffffff
R10: dffffc0000000000 R11: fffffbfff100a27f R12: dead000000000122
R13: ffff88811907a400 R14: ffff88811907a428 R15: dffffc0000000000
FS: 00007f51fd2d76c0(0000) GS:ffff8882ab6b6000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 00007f51fe8cfe10 CR3: 000000011b6ea000 CR4: 0000000000750ef0
PKRU: 80000000
Call Trace:
<TASK>
aa_free_profile+0xa2/0x9f0
aa_alloc_profile+0x1f1/0x3f0
aa_alloc_null+0x2d/0x530
aa_new_learning_profile+0x226/0x4e0
build_change_hat+0x292/0x400
aa_change_hat+0x1177/0x2fb0
aa_setprocattr_changehat+0x4a6/0x5b0
do_setattr+0x548/0x6a0
proc_pid_attr_write+0x5d1/0x630
vfs_write+0x29f/0xb90
ksys_write+0x155/0x270
do_syscall_64+0x15f/0x560
entry_SYSCALL_64_after_hwframe+0x77/0x7f
RIP: 0033:0x7f51fe88778d
Code: ff c3 66 2e 0f 1f 84 00 00 00 00 00 90 f3 0f 1e fa 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 b0 ff ff ff f7 d8 64 89 01 48
RSP: 002b:00007f51fd2d7018 EFLAGS: 00000246 ORIG_RAX: 0000000000000001
RAX: ffffffffffffffda RBX: 00007f51feb15fa0 RCX: 00007f51fe88778d
RDX: 0000000000000022 RSI: 00002000000000c0 RDI: 0000000000000003
RBP: 00007f51fd2d7080 R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000001
R13: 00007f51feb16038 R14: 00007f51feb15fa0 R15: 00007ffc4916b870
</TASK>
Kernel panic - not syncing: kernel: panic_on_warn set ...
CPU: 0 UID: 0 PID: 13898 Comm: syz.3.739 Not tainted 7.1.0-rc3-00200-g70eda68668d1-dirty #1 PREEMPT(full)
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2 04/01/2014
Call Trace:
<TASK>
vpanic+0x571/0xa60
panic+0xca/0xd0
__warn+0x31a/0x4d0
__report_bug+0x29a/0x540
report_bug_entry+0x19a/0x290
handle_bug+0xce/0x200
exc_invalid_op+0x1a/0x50
asm_exc_invalid_op+0x1a/0x20
RIP: 0010:aa_policy_destroy+0x170/0x1c0
Code: 85 ed 7e 4d e8 c1 9a dc fd 5b 41 5c 41 5e 41 5f 5d c3 cc cc cc cc cc e8 ae 9a dc fd 48 8d 3d 87 1c 0b 05 48 c7 c6 b8 a7 82 87 <67> 48 0f b9 3a e9 04 ff ff ff e8 91 9a dc fd 48 8d 3d 7a 1c 0b 05
RSP: 0018:ffffc9000141f500 EFLAGS: 00010293
RAX: ffffffff83a572b2 RBX: ffff88811907a400 RCX: ffff88812f778000
RDX: 0000000000000000 RSI: ffffffff8782a7b8 RDI: ffffffff88b08f40
RBP: 0000000000000cc0 R08: 0000000000000cc0 R09: 00000000ffffffff
R10: dffffc0000000000 R11: fffffbfff100a27f R12: dead000000000122
R13: ffff88811907a400 R14: ffff88811907a428 R15: dffffc0000000000
aa_free_profile+0xa2/0x9f0
aa_alloc_profile+0x1f1/0x3f0
aa_alloc_null+0x2d/0x530
aa_new_learning_profile+0x226/0x4e0
build_change_hat+0x292/0x400
aa_change_hat+0x1177/0x2fb0
aa_setprocattr_changehat+0x4a6/0x5b0
do_setattr+0x548/0x6a0
proc_pid_attr_write+0x5d1/0x630
vfs_write+0x29f/0xb90
ksys_write+0x155/0x270
do_syscall_64+0x15f/0x560
entry_SYSCALL_64_after_hwframe+0x77/0x7f
RIP: 0033:0x7f51fe88778d
Code: ff c3 66 2e 0f 1f 84 00 00 00 00 00 90 f3 0f 1e fa 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 b0 ff ff ff f7 d8 64 89 01 48
RSP: 002b:00007f51fd2d7018 EFLAGS: 00000246 ORIG_RAX: 0000000000000001
RAX: ffffffffffffffda RBX: 00007f51feb15fa0 RCX: 00007f51fe88778d
RDX: 0000000000000022 RSI: 00002000000000c0 RDI: 0000000000000003
RBP: 00007f51fd2d7080 R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000001
R13: 00007f51feb16038 R14: 00007f51feb15fa0 R15: 00007ffc4916b870
</TASK>
Kernel Offset: disabled
Rebooting in 86400 seconds..

<<<<<<<<<<<<<<< tail report >>>>>>>>>>>>>>>