summaryrefslogtreecommitdiff
path: root/security/apparmor
AgeCommit message (Collapse)Author
2026-06-23apparmor: advertise the tcp fast open fix is appliedJohn Johansen
The fix for tcp-fast-open ensures that the connect permission is being mediated correctly but it didn't add an artifact to the feature set to advertise the fix is available. Add an artifact so that the test suite can identify if the fix has not been properly applied or a new unexpected regression has occurred. Fixes: 4d587cd8a7215 ("apparmor: mediate the implicit connect of TCP fast open sendmsg") Signed-off-by: John Johansen <john.johansen@canonical.com>
2026-06-23apparmor: mediate the implicit connect of TCP fast open sendmsgBryam Vargas
sendmsg()/sendto() with MSG_FASTOPEN is a combination of connect(2) and write(2): it opens the connection in the SYN. apparmor_socket_sendmsg() only checks AA_MAY_SEND, so a profile that grants send but denies connect lets a confined task open an outbound TCP/MPTCP connection that connect(2) would have refused, bypassing connect mediation. Mediate the implicit connect when MSG_FASTOPEN is set and a destination is supplied. Add it to apparmor_socket_sendmsg() (not the shared aa_sock_msg_perm() helper, which recvmsg also uses) and call aa_sk_perm() directly, mirroring the selinux and tomoyo fixes. sk_is_tcp() does not cover MPTCP fast open, so the SOCK_STREAM/IPPROTO_MPTCP arm is explicit. Fixes: cf60af03ca4e ("net-tcp: Fast Open client - sendmsg(MSG_FASTOPEN)") Cc: stable@vger.kernel.org Signed-off-by: Bryam Vargas <hexlabsecurity@proton.me> Signed-off-by: John Johansen <john.johansen@canonical.com>
2026-06-14apparmor: fix label can not be immediately before a declarationJohn Johansen
Fix error reported by kernel test robot security/apparmor/policy.c:1381:2: error: a label can only be part of a statement and a declaration is not a statement All errors (new ones prefixed by >>): security/apparmor/policy.c: In function 'aa_replace_profiles': >> security/apparmor/policy.c:1381:2: error: a label can only be part of a statement and a declaration is not a statement ssize_t udata_sz = udata->size; ^~~~~ Reported-by: kernel test robot <lkp@intel.com> Closes: https://lore.kernel.org/oe-kbuild-all/202606150525.npax8WiH-lkp@intel.com/ Fixes: 7b42f95813dc9 ("apparmor: fix potential UAF in aa_replace_profiles") Signed-off-by: John Johansen <john.johansen@canonical.com>
2026-06-13apparmor: fix kernel-doc warningsRodrigo Zaiden
Fix two kernel-doc warnings: - non-kernel-doc comment marked with '/**' in af_unix.c - documented symbol name mismatch for aa_get_i_loaddata() in policy_unpack.h No functional changes. Signed-off-by: Rodrigo Zaiden <rodrigoffzz@gmail.com> Signed-off-by: John Johansen <john.johansen@canonical.com>
2026-06-13apparmor: replace get_zeroed_page() with kzalloc()Mike Rapoport (Microsoft)
multi_transaction_new() allocates memory with get_zeroed_page() and uses it as struct multi_transaction. The usage of that structure does not require struct page access and it is better to allocate multi_transaction objects with kzalloc() that provides better scalability and more debugging possibilities. Replace use of get_zeroed_page() with kzalloc(). Link: https://lore.kernel.org/all/635405e4-9423-4a25-a6e7-e03c8ea0bcbe@redhat.com Reviewed-by: Paul Moore <paul@paul-moore.com> Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org> Signed-off-by: John Johansen <john.johansen@canonical.com>
2026-06-13security: apparmor: fix two spelling mistakesQingshuang Fu
Fix two spelling errors in comment: - interated → interacted - dont → don't Signed-off-by: Qingshuang Fu <fuqingshuang@kylinos.cn> Signed-off-by: John Johansen <john.johansen@canonical.com>
2026-06-13apparmor: fix use-after-free in rawdata dedup loopRuslan Valiyev
aa_replace_profiles() walks ns->rawdata_list to dedup the incoming policy blob against entries already attached to existing profiles. Per the kernel-doc on struct aa_loaddata, list membership does not hold a reference: profiles hold pcount, and when the last pcount drops, do_ploaddata_rmfs() is queued on a workqueue that takes ns->lock and removes the entry. Between dropping the last pcount and the workqueue running, an entry remains on the list with pcount == 0. aa_get_profile_loaddata() is an unconditional kref_get() on pcount, so when the dedup loop hits such an entry, refcount hardening reports refcount_t: addition on 0; use-after-free. inside aa_replace_profiles(), and the poisoned counter then trips "saturated" and "underflow" warnings on the subsequent uses of the same loaddata. Before commit a0b7091c4de4 ("apparmor: fix race on rawdata dereference") the dedup path used a get_unless_zero-style helper on a single counter, so the existing "if (tmp)" guard was meaningful. The split-refcount refactor introduced aa_get_profile_loaddata(), which has plain kref_get() semantics, and the guard quietly became a no-op. Introduce aa_get_profile_loaddata_not0(), matching the existing _not0 convention used by aa_get_profile_not0(), and use it for the rawdata_list dedup lookup so dying entries are skipped. Reproduced on x86_64 with v7.1-rc5 in QEMU+KVM running Ubuntu 24.04 + stress-ng 0.17.06: stress-ng --apparmor 1 --klog-check --timeout 60s Without this patch the three refcount_t warnings fire within a few seconds. With it the same 60 s run is clean. Coverage is a smoke-test only; a longer soak with CONFIG_KASAN, CONFIG_KCSAN and CONFIG_PROVE_LOCKING would be welcome from anyone with the cycles. Fixes: a0b7091c4de4 ("apparmor: fix race on rawdata dereference") Reported-by: Colin Ian King <colin.i.king@gmail.com> Closes: https://bugzilla.kernel.org/show_bug.cgi?id=221513 Cc: stable@vger.kernel.org Signed-off-by: Ruslan Valiyev <linuxoid@gmail.com> Signed-off-by: John Johansen <john.johansen@canonical.com>
2026-06-13apparmor: Fix inverted comparison in cache_hold_inc()Eduardo Vasconcelos
cache_hold_inc() prevents the per-CPU cache hold counter from rising above MAX_HOLD_COUNT, but the comparison is inverted (> MAX_HOLD_COUNT instead of <), so the counter never rises above 0. This breaks the cache mechanism because since the hold counter is always 0, the global pool is always attempted first before falling back to the local cache. The decrement also never occurs, thus the hold counter is effectively dead. Fix by changing > to < in cache_hold_inc(). Fixes: 0b6a6b72b329 ("apparmor: document the buffer hold, add an overflow guard") Signed-off-by: Eduardo Vasconcelos <eduardo@eduardovasconcelos.com> Signed-off-by: John Johansen <john.johansen@canonical.com>
2026-06-13apparmor: fix uninitialised pointer passed to audit_log_untrustedstring()Maciek Borzecki
Commit 4a134723f9f1 ("apparmor: move check for aa_null file to cover all cases") intrdouced a small bug, where path_name() may pass a potentially uninitialized *name to aa_audit_file() if the path->dentry had been replaced with aa_null.dentry earlier on. This can lead to page fault like one observed on 7.0.2 openSUSE Tumbleweed kernel: [51692.242756] [ T24690] BUG: unable to handle page fault for address: 0000000f00000003 [51692.242762] [ T24690] #PF: supervisor read access in kernel mode [51692.242763] [ T24690] #PF: error_code(0x0000) - not-present page [51692.242765] [ T24690] PGD 0 P4D 0 [51692.242768] [ T24690] Oops: Oops: 0000 [#1] SMP NOPTI [51692.242772] [ T24690] CPU: 3 UID: 1020 PID: 24690 Comm: snap-confine Tainted: G O 7.0.2-1-default #1 PREEMPT(full) openSUSE Tumbleweed ab90b4c9940707f9cafa19bdad80b2cec52dbe51 [51692.242775] [ T24690] Tainted: [O]=OOT_MODULE [51692.242777] [ T24690] Hardware name: Framework Laptop 13 (AMD Ryzen 7040Series)/FRANMDCP05, BIOS 03.18 01/08/2026 [51692.242778] [ T24690] RIP: 0010:strlen+0x4/0x30 [51692.242783] [ T24690] Code: f7 75 ec 31 c0 e9 17 9f 00 ff 48 89 f8 e9 0f 9f 00 ff 0f 1f 40 00 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 f3 0f 1e fa <80> 3f 00 74 18 48 89 f8 0f 1f 40 00 48 83 c0 01 80 38 00 75 f7 48 [51692.242785] [ T24690] RSP: 0018:ffffd015eb1e3608 EFLAGS: 00010282 [51692.242787] [ T24690] RAX: 0000000000000000 RBX: ffff89796198a360 RCX: 0000000000000000 [51692.242788] [ T24690] RDX: 00000000000000d1 RSI: 0000000f00000003 RDI: 0000000f00000003 [51692.242790] [ T24690] RBP: ffffffffb7ede090 R08: 00000000000005f5 R09: 0000000000000000 [51692.242791] [ T24690] R10: 0000000000000000 R11: 0000000000000000 R12: ffffd015eb1e3700 [51692.242792] [ T24690] R13: ffff8977a22bc380 R14: ffffffffb7ec5190 R15: ffff8977a0c8aa80 [51692.242794] [ T24690] FS: 0000000000000000(0000) GS:ffff897f640d8000(0000) knlGS:0000000000000000 [51692.242796] [ T24690] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [51692.242797] [ T24690] CR2: 0000000f00000003 CR3: 00000006ad15f000 CR4: 0000000000f50ef0 [51692.242799] [ T24690] PKRU: 55555554 [51692.242800] [ T24690] Call Trace: [51692.242802] [ T24690] <TASK> [51692.242804] [ T24690] audit_log_untrustedstring+0x1d/0x40 [51692.242811] [ T24690] common_lsm_audit+0x71/0x1d0 [51692.242816] [ T24690] aa_audit+0x5a/0x170 [51692.242819] [ T24690] aa_audit_file+0x18a/0x1b0 [51692.242825] [ T24690] path_name+0xd2/0x100 [51692.242829] [ T24690] profile_path_perm.part.0+0x58/0xb0 [51692.242832] [ T24690] aa_path_perm+0xef/0x150 [51692.242837] [ T24690] apparmor_file_open+0x153/0x2e0 [51692.242840] [ T24690] security_file_open+0x46/0xd0 [51692.242844] [ T24690] do_dentry_open+0xe9/0x4d0 [51692.242848] [ T24690] vfs_open+0x30/0x100 While here, initialise variables which are passed down to path_name(). Fixes: 4a134723f9f1 ("apparmor: move check for aa_null file to cover all cases") Signed-off-by: Maciek Borzecki <maciek.borzecki@gmail.com> Signed-off-by: John Johansen <john.johansen@canonical.com>
2026-06-13apparmor: don't audit files pointing to aa_null.dentryGeorgia Garcia
In commit 4a134723f9f1 ("apparmor: move check for aa_null file to cover all cases") there was a change to not audit files pointing to aa_null.dentry because they provide no value, but setting the error variable instead of returning -EACCES was still causing them to be audited. Fixes: 4a134723f9f1 ("apparmor: move check for aa_null file to cover all cases") Acked-by: David Disseldorp <ddiss@suse.de> Signed-off-by: Georgia Garcia <georgia.garcia@canonical.com> Signed-off-by: John Johansen <john.johansen@canonical.com>
2026-06-13apparmor: put secmark label after secid lookupZygmunt Krynicki
apparmor_secmark_init() parses a configured secmark label to obtain its secid. aa_label_strn_parse() returns a refcounted label, but the success path kept that reference after copying the secid. Fixes: ab9f2115081a ("apparmor: Allow filtering based on secmark policy") Signed-off-by: Zygmunt Krynicki <me@zygoon.pl> Signed-off-by: John Johansen <john.johansen@canonical.com>
2026-06-13apparmor: aa_getprocattr free procattr leak on format failureZygmunt Krynicki
aa_getprocattr() allocates the output string before rendering the label into it. If the second aa_label_snxprint() call fails, the function returned without freeing that allocation. Free and clear the output pointer on the uncommon formatting failure path before dropping the namespace reference. Fixes: 76a1d263aba3 ("apparmor: switch getprocattr to using label_print fns()") Reviewed-by: Tyler Hicks <code@thicks.com> Reviewed-by: Ryan Lee <ryan.lee@canonical.com> Signed-off-by: Zygmunt Krynicki <me@zygoon.pl> Signed-off-by: John Johansen <john.johansen@canonical.com>
2026-06-13apparmor: remove unnecessary goto and associated labelJohn Johansen
There is no need for a goto a label immediately following the conditional block when the jump is the last statement in the block. Fixes: 7306c41672487 ("apparmor: release exe file resources on path failure") Signed-off-by: John Johansen <john.johansen@canonical.com>
2026-06-13apparmor: release exe file resources on path failureZygmunt Krynicki
get_current_exe_path() takes both an exe_file reference and a path reference before resolving the path name. If aa_path_name() failed, it returned immediately and leaked both references. Route the failure through the common cleanup path so fput() and path_put() always run after the references are acquired. Fixes: 8d34e16f7f2b ("apparmor: userns: Add support for execpath in userns") Reviewed-by: Ryan Lee <ryan.lee@canonical.com> Signed-off-by: Zygmunt Krynicki <me@zygoon.pl> Signed-off-by: John Johansen <john.johansen@canonical.com>
2026-06-13apparmor: fail policy unpack on accept2 allocation failureZygmunt Krynicki
unpack_pdb() may need to allocate a missing ACCEPT2 table for older policy data. If that allocation failed, it set an error message but jumped to the success path, returning a policydb with the required table missing. Return -ENOMEM through the normal failure path when the ACCEPT2 allocation fails. Remove the now-unused out label. Fixes: 2e12c5f06017 ("apparmor: add additional flags to extended permission.") Reviewed-by: Ryan Lee <ryan.lee@canonical.com> Signed-off-by: Zygmunt Krynicki <me@zygoon.pl> Signed-off-by: John Johansen <john.johansen@canonical.com>
2026-06-13apparmor: Fix return in ns_mkdir_opHongling Zeng
Return NULL instead of passing to ERR_PTR while error is zero. Fixes smatch warning: - security/apparmor/apparmorfs.c:1846 ns_mkdir_op() warn: passing zero to 'ERR_PTR' Fixes: 88d5baf69082 ("Change inode_operations.mkdir to return struct dentry *") Reviewed-by: Ryan Lee <ryan.lee@canonical.com> Signed-off-by: Hongling Zeng <zenghongling@kylinos.cn> Signed-off-by: John Johansen <john.johansen@canonical.com>
2026-06-13apparmor: remove or add symlinks to rawdata according to export_binaryGeorgia Garcia
When the export_binary parameter is set, then rawdata is available and there should be a symbolic link for the rawdata in the profile directory in apparmorfs. If the parameter is unset, then the symlinks should not exist. The issue arises when changing the value of export_binary on runtime and replacing profiles. If export_binary was set when the profile was originally loaded, then changed to 0 and the profile was reloaded, then the symbolic links would still exist but would return ENOENT because the rawdata no longer exists. On the opposite side, if export_binary was unset when the profile was originally loaded, then changed to 1 and the profile was reloaded, then the symbolic links would not exist, even though the rawdata does. Fixes: d61c57fde8191 ("apparmor: make export of raw binary profile to userspace optional") Signed-off-by: Georgia Garcia <georgia.garcia@canonical.com> Signed-off-by: John Johansen <john.johansen@canonical.com>
2026-06-13apparmor: fix NULL pointer dereference in unpack_pdbGeorgia Garcia
pdb->dfa could be NULL if unpack_dfa fails, causing a NULL pointer dereference. Fixes: 2e12c5f06017 ("apparmor: add additional flags to extended permission.") Signed-off-by: Georgia Garcia <georgia.garcia@canonical.com> Signed-off-by: Manuel Diewald <manuel.diewald@canonical.com> Signed-off-by: John Johansen <john.johansen@canonical.com>
2026-06-13apparmor: make fn_label_build() capable of handling not supportedJohn Johansen
Currently fn_label_build() callback fns must provide a transition or failure. Change this so that a callback can indicate it should be skipped/not be involved in the label being built. This will be useful when building object labels based on mediation flags, as to whether the label should be set. Existing callers can keep treating NULL return as an error because none of those callback fns support skipping, but instead of the old error handling replace with AA_BUG. Reviewed-by: Georgia Garcia <georgia.garcia@canonical.com> Signed-off-by: John Johansen <john.johansen@canonical.com>
2026-06-13apparmor: change fn_label_build() call to not return NULLJohn Johansen
Previously fn_label_build() was accepting a NULL which represented ENOMEM return and ERR_PTR for errors. Clean this up by requiring the cb fn to return an ERR_PTR or valid value. Reviewed-by: Georgia Garcia <georgia.garcia@canonical.com> Signed-off-by: John Johansen <john.johansen@canonical.com>
2026-06-13apparmor: fix potential UAF in aa_replace_profilesMaxime Bélair
The function aa_replace_profiles was accessing udata->size after calling aa_put_loaddata(udata), causing a potential UAF. Fixed this by saving the size to a local variable before dropping the reference. Fixes: 5ac8c355ae001 ("apparmor: allow introspecting the loaded policy pre internal transform") Reviewed-by: Georgia Garcia <georgia.garcia@canonical.com> Signed-off-by: Maxime Bélair <maxime.belair@canonical.com> Signed-off-by: John Johansen <john.johansen@canonical.com>
2026-06-13apparmor: free rawdata as soon as possibleJohn Johansen
profiles can be pinned by file and other references, and can live long after they have been replaced/removed. The rawdata however is no longer needed, and can be freed earlier than the rest of the profile. Reviewed-by: Georgia Garcia <georgia.garcia@canonical.com> Signed-off-by: John Johansen <john.johansen@canonical.com>
2026-06-13apparmor: grab ns lock and refresh when looking up changehat child profilesRyan Lee
There was a race condition involving change_hat and profile replacement in which replacement of the parent profile during a changehat operation could result in the list of children becoming empty and the changehat operation failing. To prevent this: - grab the namespace lock until we've built the hat transition, and - use aa_get_newest_profile to avoid using stale profile objects. Link: https://bugs.launchpad.net/bugs/2139664 Fixes: 89dbf1962aa63 ("apparmor: move change_hat mediation to using labels") Reviewed-by: Georgia Garcia <georgia.garcia@canonical.com> Signed-off-by: Ryan Lee <ryan.lee@canonical.com> Signed-off-by: John Johansen <john.johansen@canonical.com>
2026-06-13apparmor: fix rawdata_f_data implicit flex arrayJohn Johansen
rawdata_f_data has a blob of data that is allocated at its end but not explicitly declared. Makes sure it is correctly declared as a flex_rray. Fixes: 63c16c3a76085 ("apparmor: Initial implementation of raw policy blob compression") Reviewed-by: Georgia Garcia <georgia.garcia@canonical.com> Signed-off-by: John Johansen <john.johansen@canonical.com>
2026-06-13apparmor: use __label_make_stale in __aa_proxy_redirectRyan Lee
The macro is equivalent to OR-ing in the bitflag manually, but using the macro consistently makes grepping for these occurrences easier. Reviewed-by: Georgia Garcia <georgia.garcia@canonical.com> Signed-off-by: Ryan Lee <ryan.lee@canonical.com> Signed-off-by: John Johansen <john.johansen@canonical.com>
2026-06-13apparmor: propagate -ENOMEM correctly in unpack_tableMaxime Bélair
Currently, if the `kvzalloc` in `unpack_table` fails, it returns NULL. This is masked by `aa_dfa_unpack` which interprets NULL as a -EPROTO, leading to confusing error messages in `apparmor_parser` [1]. The fixed behavior correctly propagates -ENOMEM on allocation failure. Link: https://gitlab.com/apparmor/apparmor/-/issues/592 Reviewed-by: Georgia Garcia <georgia.garcia@canonical.com> Signed-off-by: Maxime Bélair <maxime.belair@canonical.com> Signed-off-by: John Johansen <john.johansen@canonical.com>
2026-06-13apparmor: enable differential encodingJohn Johansen
Differential encoding while present has not been made broadly available, pending further review and testing. Now that has happened advertise its availability to user space. Reviewed-by: Georgia Garcia <georgia.garcia@canonical.com> Signed-off-by: John Johansen <john.johansen@canonical.com>
2026-06-13apparmor: aa_label_alloc use aa_label_free on alloc failureZygmunt Krynicki
aa_label_alloc() allocates a secid before allocating or taking the label proxy. If the later proxy step fails, the error path only freed the label memory, leaking any resources initialized by aa_label_init(). Use aa_label_free() on the failure path so partially initialized labels release their secid and other label resources before the backing memory is freed. Fixes: f1bd904175e81 ("apparmor: add the base fns() for domain labels") Signed-off-by: Zygmunt Krynicki <me@zygoon.pl> Signed-off-by: John Johansen <john.johansen@canonical.com>
2026-06-13apparmor: check label build before no_new_privs testRuoyu Wang
aa_change_profile() builds a replacement label with fn_label_build_in_scope() before the no_new_privs subset check. The build helper can fail and return NULL or an ERR_PTR, but the result was passed to aa_label_is_unconfined_subset() before the existing IS_ERR_OR_NULL() check. Reuse the existing target-label build failure handling immediately after the build. This preserves the current audit handling while preventing the subset helper from dereferencing an invalid label. Fixes: e00b02bb6ac2a ("apparmor: move change_profile mediation to using labels") Signed-off-by: Ruoyu Wang <ruoyuw560@gmail.com> Signed-off-by: John Johansen <john.johansen@canonical.com>
2026-06-13security/apparmor/apparmorfs.c: conditionally compile get_loaddata_common_ref()Andrew Morton
Some config did this: security/apparmor/apparmorfs.c:177:28: warning: 'get_loaddata_common_ref' defined but not used [-Wunused-function] 177 | static struct aa_loaddata *get_loaddata_common_ref(struct aa_common_ref *ref) get_loaddata_common_ref() is only used if CONFIG_SECURITY_APPARMOR_EXPORT_BINARY=y. (Or of course move the function into that block if maintainers perfer) Fixes: 8e135b8aee5a0 ("apparmor: fix race between freeing data and fs accessing it") Cc: John Johansen <john.johansen@canonical.com> Cc: Paul Moore <paul@paul-moore.com> Cc: James Morris <jmorris@namei.org> Cc: "Serge E. Hallyn" <serge@hallyn.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: John Johansen <john.johansen@canonical.com>
2026-06-13apparmor: add a conditional version of get_newest_labelJohn Johansen
get_newest_label() will always return a refcount, on the profile it returns. However there are cases where we only need the refcount if the label is stale and get_newest_label() will return a different label. Optimize this by making the get/put happen conditionally, by keeping a flag indicating if the get was performed and a put is needed. Signed-off-by: John Johansen <john.johansen@canonical.com>
2026-06-13apparmor: fix refcount leak when updating the sk_ctxJohn Johansen
Currently update_sk_ctx() transfers the plabel reference, unfortunately it is also unconditionally put in the caller. Ideally we would make the caller conditionally put the reference based on whether it was transferred but for now just fix the bug by getting a reference. Fixes: 88fec3526e841 ("apparmor: make sure unix socket labeling is correctly updated.") Signed-off-by: John Johansen <john.johansen@canonical.com>
2026-06-13apparmor: fix race in unix socket mediation when peer_path is usedJohn Johansen
The holding a reference to the peer_sk is not enough to ensure access to the peer sk path. Accessing the path outside of the state lock allows for a race with unix_release_sock(). Fix this by taking the state lock and getting a reference to the path under lock. Ideally for connected sockets we would cache this information so we don't have to take the lock here. But for now just fix the race. Fixes: bc6e5f6933b8e ("apparmor: Remove use of the double lock") Signed-off-by: John Johansen <john.johansen@canonical.com>
2026-06-13apparmor: fix shadowing of plabel that prevents cache from being updatedJohn Johansen
Unfortunately the plabel was being shadowed by an unused local var. This didn't affect the mediation check but did cauase the cache to not correctly be updated resulting in extra mediation checks. Fixes: 88fec3526e841 ("apparmor: make sure unix socket labeling is correctly updated.") Signed-off-by: John Johansen <john.johansen@canonical.com>
2026-04-24Merge tag 'apparmor-pr-2026-04-23' of ↵Linus Torvalds
git://git.kernel.org/pub/scm/linux/kernel/git/jj/linux-apparmor Pull apparmor updates from John Johansen: "Cleanups - Use sysfs_emit in param_get_{audit,mode} - Remove redundant if check in sk_peer_get_label - Replace memcpy + NUL termination with kmemdup_nul in do_setattr Bug Fixes: - Fix aa_dfa_unpack's error handling in aa_setup_dfa_engine - Fix string overrun due to missing termination - Fix wrong dentry in RENAME_EXCHANGE uid check - fix unpack_tags to properly return error in failure cases - fix dfa size check - return error on namespace mismatch in verify_header - use target task's context in apparmor_getprocattr()" * tag 'apparmor-pr-2026-04-23' of git://git.kernel.org/pub/scm/linux/kernel/git/jj/linux-apparmor: apparmor/lsm: Fix aa_dfa_unpack's error handling in aa_setup_dfa_engine apparmor: Fix string overrun due to missing termination apparmor: Fix wrong dentry in RENAME_EXCHANGE uid check apparmor: fix unpack_tags to properly return error in failure cases apparmor: fix dfa size check apparmor: Use sysfs_emit in param_get_{audit,mode} apparmor: Remove redundant if check in sk_peer_get_label apparmor: Replace memcpy + NUL termination with kmemdup_nul in do_setattr apparmor: return error on namespace mismatch in verify_header apparmor: use target task's context in apparmor_getprocattr()
2026-04-22apparmor/lsm: Fix aa_dfa_unpack's error handling in aa_setup_dfa_engineGONG Ruiqi
aa_dfa_unpack returns ERR_PTR not NULL when it fails, but aa_put_dfa only checks NULL for its input, which would cause invalid memory access in aa_put_dfa. Set nulldfa to NULL explicitly to fix that. Fixes: 98b824ff8984 ("apparmor: refcount the pdb") Signed-off-by: GONG Ruiqi <gongruiqi1@huawei.com> Signed-off-by: John Johansen <john.johansen@canonical.com>
2026-04-22apparmor: Fix string overrun due to missing terminationDaniel J Blueman
When booting Ubuntu 26.04 with Linux 7.0-rc4 on an ARM64 Qualcomm Snapdragon X1 we see a string buffer overrun: BUG: KASAN: slab-out-of-bounds in aa_dfa_match (security/apparmor/match.c:535) Read of size 1 at addr ffff0008901cc000 by task snap-update-ns/2120 CPU: 5 UID: 60578 PID: 2120 Comm: snap-update-ns Not tainted 7.0.0-rc4+ #22 PREEMPTLAZY Hardware name: LENOVO 83ED/LNVNB161216, BIOS NHCN60WW 09/11/2025 Call trace: show_stack (arch/arm64/kernel/stacktrace.c:501) (C) dump_stack_lvl (lib/dump_stack.c:122) print_report (mm/kasan/report.c:379 mm/kasan/report.c:482) kasan_report (mm/kasan/report.c:597) __asan_report_load1_noabort (mm/kasan/report_generic.c:378) aa_dfa_match (security/apparmor/match.c:535) match_mnt_path_str (security/apparmor/mount.c:244 security/apparmor/mount.c:336) match_mnt (security/apparmor/mount.c:371) aa_bind_mount (security/apparmor/mount.c:447 (discriminator 4)) apparmor_sb_mount (security/apparmor/lsm.c:719 (discriminator 1)) security_sb_mount (security/security.c:1062 (discriminator 31)) path_mount (fs/namespace.c:4101) __arm64_sys_mount (fs/namespace.c:4172 fs/namespace.c:4361 fs/namespace.c:4338 fs/namespace.c:4338) invoke_syscall.constprop.0 (arch/arm64/kernel/syscall.c:35 arch/arm64/kernel/syscall.c:49) el0_svc_common.constprop.0 (./include/linux/thread_info.h:142 (discriminator 2) arch/arm64/kernel/syscall.c:140 (discriminator 2)) do_el0_svc (arch/arm64/kernel/syscall.c:152) el0_svc (arch/arm64/kernel/entry-common.c:80 arch/arm64/kernel/entry-common.c:725) el0t_64_sync_handler (arch/arm64/kernel/entry-common.c:744) el0t_64_sync (arch/arm64/kernel/entry.S:596) Allocated by task 2120: kasan_save_stack (mm/kasan/common.c:58) kasan_save_track (./arch/arm64/include/asm/current.h:19 mm/kasan/common.c:70 mm/kasan/common.c:79) kasan_save_alloc_info (mm/kasan/generic.c:571) __kasan_kmalloc (mm/kasan/common.c:419) __kmalloc_noprof (./include/linux/kasan.h:263 mm/slub.c:5260 mm/slub.c:5272) aa_get_buffer (security/apparmor/lsm.c:2201) aa_bind_mount (security/apparmor/mount.c:442) apparmor_sb_mount (security/apparmor/lsm.c:719 (discriminator 1)) security_sb_mount (security/security.c:1062 (discriminator 31)) path_mount (fs/namespace.c:4101) __arm64_sys_mount (fs/namespace.c:4172 fs/namespace.c:4361 fs/namespace.c:4338 fs/namespace.c:4338) invoke_syscall.constprop.0 (arch/arm64/kernel/syscall.c:35 arch/arm64/kernel/syscall.c:49) el0_svc_common.constprop.0 (./include/linux/thread_info.h:142 (discriminator 2) arch/arm64/kernel/syscall.c:140 (discriminator 2)) do_el0_svc (arch/arm64/kernel/syscall.c:152) el0_svc (arch/arm64/kernel/entry-common.c:80 arch/arm64/kernel/entry-common.c:725) el0t_64_sync_handler (arch/arm64/kernel/entry-common.c:744) el0t_64_sync (arch/arm64/kernel/entry.S:596) The buggy address belongs to the object at ffff0008901ca000 which belongs to the cache kmalloc-rnd-06-8k of size 8192 The buggy address is located 0 bytes to the right of allocated 8192-byte region [ffff0008901ca000, ffff0008901cc000) The buggy address belongs to the physical page: page: refcount:0 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x9101c8 head: order:3 mapcount:0 entire_mapcount:0 nr_pages_mapped:-1 pincount:0 flags: 0x8000000000000040(head|zone=2) page_type: f5(slab) raw: 8000000000000040 ffff000800016c40 fffffdffe2d14e10 ffff000800015c70 raw: 0000000000000000 0000000800010001 00000000f5000000 0000000000000000 head: 8000000000000040 ffff000800016c40 fffffdffe2d14e10 ffff000800015c70 head: 0000000000000000 0000000800010001 00000000f5000000 0000000000000000 head: 8000000000000003 fffffdffe2407201 fffffdffffffffff 00000000ffffffff head: ffffffffffffffff 0000000000000000 00000000ffffffff 0000000000000008 page dumped because: kasan: bad access detected Memory state around the buggy address: ffff0008901cbf00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ffff0008901cbf80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 >ffff0008901cc000: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc ^ ffff0008901cc080: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc ffff0008901cc100: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc This was introduced by previous incorrect conversion from strcpy(). Fix it by adding the missing terminator. Cc: stable@vger.kernel.org Reviewed-by: Georgia Garcia <georgia.garcia@canonical.com> Signed-off-by: Daniel J Blueman <daniel@quora.org> Fixes: 93d4dbdc8da0 ("apparmor: Replace deprecated strcpy in d_namespace_path") Signed-off-by: John Johansen <john.johansen@canonical.com>
2026-04-22apparmor: Fix wrong dentry in RENAME_EXCHANGE uid checkDudu Lu
In apparmor_path_rename(), when handling RENAME_EXCHANGE, the cond_exchange structure is supposed to carry the attributes of the *new* dentry (since it is used to authorize moving new_dentry to the old location). However, line 412 reads: vfsuid = i_uid_into_vfsuid(idmap, d_backing_inode(old_dentry)); This fetches the uid of old_dentry instead of new_dentry. As a result, the RENAME_EXCHANGE permission check uses the wrong file owner, which can allow a rename that should be denied (if old_dentry's owner has more privileges) or deny one that should be allowed. Note that cond_exchange.mode on the line above correctly uses new_dentry. Only the uid lookup is wrong. Fix by changing old_dentry to new_dentry in the i_uid_into_vfsuid call. Fixes: 5e26a01e56fd ("apparmor: use type safe idmapping helpers") Reviewed-by: Georgia Garcia <georgia.garcia@canonical.com> Signed-off-by: Dudu Lu <phx0fer@gmail.com> Signed-off-by: John Johansen <john.johansen@canonical.com>
2026-04-22apparmor: fix unpack_tags to properly return error in failure casesJohn Johansen
error is initialized to -EPROTO but set by some of the internal functions, unfortunately the last two checks assume error is set to -EPROTO already for the failure case. Ensure it is by setting it before these checks. Fixes: 3d28e2397af7a ("apparmor: add support loading per permission tagging") Reported-by: Dan Carpenter <error27@gmail.com> Signed-off-by: John Johansen <john.johansen@canonical.com>
2026-04-22apparmor: fix dfa size checkJohn Johansen
AppArmor dfas need a minimum of two states to be valid. State 0 is the default trap state, and State 1 the default start state. When verifying the dfa ensure that this is the case. Fixes: c27c6bd2c4d6b ("apparmor: ensure that dfa state tables have entries") Signed-off-by: John Johansen <john.johansen@canonical.com>
2026-04-22apparmor: Use sysfs_emit in param_get_{audit,mode}Thorsten Blum
Replace sprintf() with sysfs_emit() in param_get_audit() and param_get_mode(). sysfs_emit() is preferred for formatting sysfs output because it provides safer bounds checking. Add terminating newlines as suggested by checkpatch. Signed-off-by: Thorsten Blum <thorsten.blum@linux.dev> Signed-off-by: John Johansen <john.johansen@canonical.com>
2026-04-22apparmor: Remove redundant if check in sk_peer_get_labelThorsten Blum
Remove the redundant if check in sk_peer_get_label() and return ERR_PTR(-ENOPROTOOPT) directly. Signed-off-by: Thorsten Blum <thorsten.blum@linux.dev> Signed-off-by: John Johansen <john.johansen@canonical.com>
2026-04-22apparmor: Replace memcpy + NUL termination with kmemdup_nul in do_setattrThorsten Blum
Use kmemdup_nul() to copy 'value' instead of using memcpy() followed by a manual NUL termination. No functional changes. Reviewed-by: Serge Hallyn <serge@hallyn.com> Signed-off-by: Thorsten Blum <thorsten.blum@linux.dev> Signed-off-by: John Johansen <john.johansen@canonical.com>
2026-04-13Merge tag 'vfs-7.1-rc1.kino' of ↵Linus Torvalds
git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs Pull vfs i_ino updates from Christian Brauner: "For historical reasons, the inode->i_ino field is an unsigned long, which means that it's 32 bits on 32 bit architectures. This has caused a number of filesystems to implement hacks to hash a 64-bit identifier into a 32-bit field, and deprives us of a universal identifier field for an inode. This changes the inode->i_ino field from an unsigned long to a u64. This shouldn't make any material difference on 64-bit hosts, but 32-bit hosts will see struct inode grow by at least 4 bytes. This could have effects on slabcache sizes and field alignment. The bulk of the changes are to format strings and tracepoints, since the kernel itself doesn't care that much about the i_ino field. The first patch changes some vfs function arguments, so check that one out carefully. With this change, we may be able to shrink some inode structures. For instance, struct nfs_inode has a fileid field that holds the 64-bit inode number. With this set of changes, that field could be eliminated. I'd rather leave that sort of cleanups for later just to keep this simple" * tag 'vfs-7.1-rc1.kino' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs: nilfs2: fix 64-bit division operations in nilfs_bmap_find_target_in_group() EVM: add comment describing why ino field is still unsigned long vfs: remove externs from fs.h on functions modified by i_ino widening treewide: fix missed i_ino format specifier conversions ext4: fix signed format specifier in ext4_load_inode trace event treewide: change inode->i_ino from unsigned long to u64 nilfs2: widen trace event i_ino fields to u64 f2fs: widen trace event i_ino fields to u64 ext4: widen trace event i_ino fields to u64 zonefs: widen trace event i_ino fields to u64 hugetlbfs: widen trace event i_ino fields to u64 ext2: widen trace event i_ino fields to u64 cachefiles: widen trace event i_ino fields to u64 vfs: widen trace event i_ino fields to u64 net: change sock.sk_ino and sock_i_ino() to u64 audit: widen ino fields to u64 vfs: widen inode hash/lookup functions to u64
2026-04-13Merge tag 'vfs-7.1-rc1.directory' of ↵Linus Torvalds
git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs Pull vfs directory updates from Christian Brauner: "Recently 'start_creating', 'start_removing', 'start_renaming' and related interfaces were added which combine the locking and the lookup. At that time many callers were changed to use the new interfaces. However there are still an assortment of places out side of the core vfs where the directory is locked explictly, whether with inode_lock() or lock_rename() or similar. These were missed in the first pass for an assortment of uninteresting reasons. This addresses the remaining places where explicit locking is used, and changes them to use the new interfaces, or otherwise removes the explicit locking. The biggest changes are in overlayfs. The other changes are quite simple, though maybe the cachefiles changes is the least simple of those" * tag 'vfs-7.1-rc1.directory' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs: VFS: unexport lock_rename(), lock_rename_child(), unlock_rename() ovl: remove ovl_lock_rename_workdir() ovl: use is_subdir() for testing if one thing is a subdir of another ovl: change ovl_create_real() to get a new lock when re-opening created file. ovl: pass name buffer to ovl_start_creating_temp() cachefiles: change cachefiles_bury_object to use start_renaming_dentry() ovl: Simplify ovl_lookup_real_one() VFS: make lookup_one_qstr_excl() static. nfsd: switch purge_old() to use start_removing_noperm() selinux: Use simple_start_creating() / simple_done_creating() Apparmor: Use simple_start_creating() / simple_done_creating() libfs: change simple_done_creating() to use end_creating() VFS: move the start_dirop() kerndoc comment to before start_dirop() fs/proc: Don't lock root inode when creating "self" and "thread-self" VFS: note error returns in documentation for various lookup functions
2026-03-09apparmor: fix race between freeing data and fs accessing itJohn Johansen
AppArmor was putting the reference to i_private data on its end after removing the original entry from the file system. However the inode can aand does live beyond that point and it is possible that some of the fs call back functions will be invoked after the reference has been put, which results in a race between freeing the data and accessing it through the fs. While the rawdata/loaddata is the most likely candidate to fail the race, as it has the fewest references. If properly crafted it might be possible to trigger a race for the other types stored in i_private. Fix this by moving the put of i_private referenced data to the correct place which is during inode eviction. Fixes: c961ee5f21b20 ("apparmor: convert from securityfs to apparmorfs for policy ns files") Reported-by: Qualys Security Advisory <qsa@qualys.com> Reviewed-by: Georgia Garcia <georgia.garcia@canonical.com> Reviewed-by: Maxime Bélair <maxime.belair@canonical.com> Reviewed-by: Cengiz Can <cengiz.can@canonical.com> Signed-off-by: John Johansen <john.johansen@canonical.com>
2026-03-09apparmor: fix race on rawdata dereferenceJohn Johansen
There is a race condition that leads to a use-after-free situation: because the rawdata inodes are not refcounted, an attacker can start open()ing one of the rawdata files, and at the same time remove the last reference to this rawdata (by removing the corresponding profile, for example), which frees its struct aa_loaddata; as a result, when seq_rawdata_open() is reached, i_private is a dangling pointer and freed memory is accessed. The rawdata inodes weren't refcounted to avoid a circular refcount and were supposed to be held by the profile rawdata reference. However during profile removal there is a window where the vfs and profile destruction race, resulting in the use after free. Fix this by moving to a double refcount scheme. Where the profile refcount on rawdata is used to break the circular dependency. Allowing for freeing of the rawdata once all inode references to the rawdata are put. Fixes: 5d5182cae401 ("apparmor: move to per loaddata files, instead of replicating in profiles") Reported-by: Qualys Security Advisory <qsa@qualys.com> Reviewed-by: Georgia Garcia <georgia.garcia@canonical.com> Reviewed-by: Maxime Bélair <maxime.belair@canonical.com> Reviewed-by: Cengiz Can <cengiz.can@canonical.com> Tested-by: Salvatore Bonaccorso <carnil@debian.org> Signed-off-by: John Johansen <john.johansen@canonical.com>
2026-03-09apparmor: fix differential encoding verificationJohn Johansen
Differential encoding allows loops to be created if it is abused. To prevent this the unpack should verify that a diff-encode chain terminates. Unfortunately the differential encode verification had two bugs. 1. it conflated states that had gone through check and already been marked, with states that were currently being checked and marked. This means that loops in the current chain being verified are treated as a chain that has already been verified. 2. the order bailout on already checked states compared current chain check iterators j,k instead of using the outer loop iterator i. Meaning a step backwards in states in the current chain verification was being mistaken for moving to an already verified state. Move to a double mark scheme where already verified states get a different mark, than the current chain being kept. This enables us to also drop the backwards verification check that was the cause of the second error as any already verified state is already marked. Fixes: 031dcc8f4e84 ("apparmor: dfa add support for state differential encoding") Reported-by: Qualys Security Advisory <qsa@qualys.com> Tested-by: Salvatore Bonaccorso <carnil@debian.org> Reviewed-by: Georgia Garcia <georgia.garcia@canonical.com> Reviewed-by: Cengiz Can <cengiz.can@canonical.com> Signed-off-by: John Johansen <john.johansen@canonical.com>
2026-03-09apparmor: fix unprivileged local user can do privileged policy managementJohn Johansen
An unprivileged local user can load, replace, and remove profiles by opening the apparmorfs interfaces, via a confused deputy attack, by passing the opened fd to a privileged process, and getting the privileged process to write to the interface. This does require a privileged target that can be manipulated to do the write for the unprivileged process, but once such access is achieved full policy management is possible and all the possible implications that implies: removing confinement, DoS of system or target applications by denying all execution, by-passing the unprivileged user namespace restriction, to exploiting kernel bugs for a local privilege escalation. The policy management interface can not have its permissions simply changed from 0666 to 0600 because non-root processes need to be able to load policy to different policy namespaces. Instead ensure the task writing the interface has privileges that are a subset of the task that opened the interface. This is already done via policy for confined processes, but unconfined can delegate access to the opened fd, by-passing the usual policy check. Fixes: b7fd2c0340eac ("apparmor: add per policy ns .load, .replace, .remove interface files") Reported-by: Qualys Security Advisory <qsa@qualys.com> Tested-by: Salvatore Bonaccorso <carnil@debian.org> Reviewed-by: Georgia Garcia <georgia.garcia@canonical.com> Reviewed-by: Cengiz Can <cengiz.can@canonical.com> Signed-off-by: John Johansen <john.johansen@canonical.com>
2026-03-09apparmor: Fix double free of ns_name in aa_replace_profiles()John Johansen
if ns_name is NULL after 1071 error = aa_unpack(udata, &lh, &ns_name); and if ent->ns_name contains an ns_name in 1089 } else if (ent->ns_name) { then ns_name is assigned the ent->ns_name 1095 ns_name = ent->ns_name; however ent->ns_name is freed at 1262 aa_load_ent_free(ent); and then again when freeing ns_name at 1270 kfree(ns_name); Fix this by NULLing out ent->ns_name after it is transferred to ns_name Fixes: 145a0ef21c8e9 ("apparmor: fix blob compression when ns is forced on a policy load ") Reported-by: Qualys Security Advisory <qsa@qualys.com> Tested-by: Salvatore Bonaccorso <carnil@debian.org> Reviewed-by: Georgia Garcia <georgia.garcia@canonical.com> Reviewed-by: Cengiz Can <cengiz.can@canonical.com> Signed-off-by: John Johansen <john.johansen@canonical.com>