<feed xmlns='http://www.w3.org/2005/Atom'>
<title>kernel/git/stable/linux.git/security/apparmor/policy.c, branch master</title>
<subtitle>Linux kernel stable tree</subtitle>
<id>https://git.landau.one/pub/scm/linux/kernel/git/stable/linux.git/atom?h=master</id>
<link rel='self' href='https://git.landau.one/pub/scm/linux/kernel/git/stable/linux.git/atom?h=master'/>
<link rel='alternate' type='text/html' href='https://git.landau.one/pub/scm/linux/kernel/git/stable/linux.git/'/>
<updated>2026-08-16T06:39:38+00:00</updated>
<entry>
<title>apparmor: fix deadlock in complain-mode change_hat</title>
<updated>2026-08-16T06:39:38+00:00</updated>
<author>
<name>John Johansen</name>
<email>john.johansen@canonical.com</email>
</author>
<published>2026-08-12T09:27:15+00:00</published>
<link rel='alternate' type='text/html' href='https://git.landau.one/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=4ec11f14d1d6fdda787d991b142537be7841d395'/>
<id>urn:sha1:4ec11f14d1d6fdda787d991b142537be7841d395</id>
<content type='text'>
The use of change_hat when in complain mode can cause a deadlock
when the hat doesn't exist and a new learning profile is created
for the missing profile. This is because change_hat() has taken
the lock to search the hat list and creating the new learning
profile needs to take the lock to add it to the list.

From the bug report:

Originally found in 7.0.0 in LTS ubuntu 26.04 with pam_apparmor + su
in complain mode set to change hats.  Then verified in newest
available vanilla kernel I've compiled to see if still present:

7.2-rc7 vanilla -&gt; affected

checked also some other kernels:
6.18.44 vanilla -&gt; affected
6.12.95 with debian patches -&gt; unaffected

On systems without bug (for example 6.12.95 debian) it just prints:

aa_change_hat rc=0

On systems with bug, the executable always hangs, prints nothing and
becomes unkillable.  (And once stuck this way, it will cause any
further hat changes to also cause the changing process to get stuck)

Then in syslog you can find hint about cause:

kernel: INFO: task hat:3409 blocked for more than 483 seconds.
kernel:       Not tainted 7.2.0-rc7 #1
kernel: "echo 0 &gt; /proc/sys/kernel/hung_task_timeout_secs" disables this message.
kernel: task:hat             state:D stack:0     pid:3409  tgid:3409  ppid:2605   task_flags:0x400000 flags:0x00080800
kernel: Call Trace:
kernel:  &lt;TASK&gt;
kernel:  __schedule+0x48f/0xfe0
kernel:  schedule+0x27/0xa0
kernel:  schedule_preempt_disabled+0x15/0x30
kernel:  __mutex_lock.constprop.0+0x569/0xa10
kernel:  aa_new_learning_profile+0x15f/0x210
kernel:  build_change_hat+0x19f/0x3b0
kernel:  change_hat.isra.0+0x5dd/0xd60
kernel:  aa_change_hat+0x2f3/0x710
kernel:  aa_setprocattr_changehat+0x121/0x1f0
kernel:  do_setattr+0x28c/0x340
kernel:  apparmor_setselfattr+0x20/0x50
kernel:  security_setselfattr+0xf6/0x110
kernel:  __x64_sys_lsm_set_self_attr+0x53/0x90
kernel:  do_syscall_64+0xdd/0x5e0
kernel:  ? __mod_memcg_lruvec_state+0xfd/0x260
kernel:  ? lruvec_stat_mod_folio+0x8d/0xd0
kernel:  ? __folio_mod_stat+0x2d/0x90
kernel:  ? map_anon_folio_pte_nopf+0xd1/0x1f0
kernel:  ? do_anonymous_page+0x184/0xa10
kernel:  ? __handle_mm_fault+0x805/0x870
kernel:  ? count_memcg_events+0xef/0x230
kernel:  ? handle_mm_fault+0x1f0/0x2f0
kernel:  ? do_user_addr_fault+0x2bb/0x7b0
kernel:  ? do_syscall_64+0x94/0x5e0
kernel:  ? exc_page_fault+0x75/0x160
kernel:  entry_SYSCALL_64_after_hwframe+0x76/0x7e
kernel: RIP: 0033:0x7f815e134c8d
kernel: RSP: 002b:00007fff6df94ea8 EFLAGS: 00000246 ORIG_RAX: 00000000000001cc
kernel: RAX: ffffffffffffffda RBX: 0000556d8c81d040 RCX: 00007f815e134c8d
kernel: RDX: 0000000000000046 RSI: 0000556d8c81d040 RDI: 0000000000000064
kernel: RBP: 00007fff6df94ef0 R08: 00007f815e212ac8 R09: 000000000000000c
kernel: R10: 0000000000000000 R11: 0000000000000246 R12: 0000556d8c81d010
kernel: R13: 0000000000000026 R14: 0000000000000046 R15: 0000000000000064
kernel:  &lt;/TASK&gt;
kernel: INFO: task hat:3409 is blocked on a mutex likely owned by task hat:3409.

To fix the issue, lift the locking out of the core of
aa_new_learning_profile(), introduce a wrapper function that takes the
lock where needed, and have build_change_hat() call the core function
that no longer takes the lock.

In addition fix 4 other issues introduced by commit
32e92764d6f8d ("apparmor: grab ns lock and refresh when looking up changehat child profiles")
- aa_get_profile_rcu() was replaced-by: aa_get_profile without the
  accompanying rcu_dereference_protected()
- an extra aa_get_label(label) was introduced at the start of
  change_hat() without an accompanying aa_put_label() causing a
  reference count leak.
- a reference count leak was introduced in the label_is_stale(label)
  case, where the newest profile would be leaked instead of the
  label passed to the function.
- a potential UAF when the lookup walks up the tree with new_ns != ns
  the new label reference is put, and then used for the next lookup.
  The mutex_lock, will block replacement, and removal in the locked
  ns. However there are two cases where putting the reference can
  result in the label being freed even with the lock held.

  1. the label does not have a list reference (possible for temporary
     or special profiles) in which case the put can trigger the
     cleanup.
  2. the new label reference is in a different namespace, which does
     not have a lock held on it. This extends case 1 to also include
     replacement, and removal that could be occurring in the namespace
     new is in.

Reported-by: Martin Petricek &lt;mp@petricek.net&gt;
Link: https://lists.ubuntu.com/archives/apparmor/2026-August/014907.html
Fixes: 32e92764d6f8d ("apparmor: grab ns lock and refresh when looking up changehat child profiles")
Signed-off-by: John Johansen &lt;john.johansen@canonical.com&gt;
</content>
</entry>
<entry>
<title>apparmor: Initial support for compressed policies</title>
<updated>2026-06-29T17:27:02+00:00</updated>
<author>
<name>Maxime Bélair</name>
<email>maxime.belair@canonical.com</email>
</author>
<published>2024-02-01T08:09:50+00:00</published>
<link rel='alternate' type='text/html' href='https://git.landau.one/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=17b5758bf35c7a113363cd7a350b7e6a251b80f4'/>
<id>urn:sha1:17b5758bf35c7a113363cd7a350b7e6a251b80f4</id>
<content type='text'>
This patch allows policies to be compressed in userspace and be sent to
the kernel through the existing ".load" and ".replace" kernel interfaces.

The benefits of this approach are:
 - Save kernel time when loading policies
 - Allow userspace to provide a higher level of compression than the one
   provided by the kernel (ZSTD_CLEVEL_DEFAULT), thus saving space.
 - Allow small embedded systems to only store the compressed version of
   policies in userspace, saving memory.

Userspace-compressed policies improve system time by up to ~30% for big
profiles.

Signed-off-by: Maxime Bélair &lt;maxime.belair@canonical.com&gt;
Signed-off-by: John Johansen &lt;john.johansen@canonical.com&gt;
</content>
</entry>
<entry>
<title>apparmor: fix net.h and policy.h circular include pattern</title>
<updated>2026-06-29T17:26:21+00:00</updated>
<author>
<name>Ryan Lee</name>
<email>ryan.lee@canonical.com</email>
</author>
<published>2026-02-12T21:16:03+00:00</published>
<link rel='alternate' type='text/html' href='https://git.landau.one/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=622ec01756ee9d483662655ff7315cb0e23afd46'/>
<id>urn:sha1:622ec01756ee9d483662655ff7315cb0e23afd46</id>
<content type='text'>
While the #ifdef guards prevent the circular include from blowing up,
policy.h does not actually need anything from net.h. Remove, that include
and instead include net.h in the other files that need it.

Signed-off-by: Ryan Lee &lt;ryan.lee@canonical.com&gt;
Signed-off-by: John Johansen &lt;john.johansen@canonical.com&gt;
</content>
</entry>
<entry>
<title>apparmor: fix label can not be immediately before a declaration</title>
<updated>2026-06-15T01:22:35+00:00</updated>
<author>
<name>John Johansen</name>
<email>john.johansen@canonical.com</email>
</author>
<published>2026-06-14T23:16:59+00:00</published>
<link rel='alternate' type='text/html' href='https://git.landau.one/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=1ed40bd525c00d22af666016af9aef7167f8085f'/>
<id>urn:sha1:1ed40bd525c00d22af666016af9aef7167f8085f</id>
<content type='text'>
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 &gt;&gt;):

   security/apparmor/policy.c: In function 'aa_replace_profiles':
&gt;&gt; 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-&gt;size;
     ^~~~~

Reported-by: kernel test robot &lt;lkp@intel.com&gt;
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 &lt;john.johansen@canonical.com&gt;
</content>
</entry>
<entry>
<title>apparmor: fix use-after-free in rawdata dedup loop</title>
<updated>2026-06-14T03:20:13+00:00</updated>
<author>
<name>Ruslan Valiyev</name>
<email>linuxoid@gmail.com</email>
</author>
<published>2026-05-25T22:04:46+00:00</published>
<link rel='alternate' type='text/html' href='https://git.landau.one/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=6f060496d03e4dc560a40f73770bd08335cb7a27'/>
<id>urn:sha1:6f060496d03e4dc560a40f73770bd08335cb7a27</id>
<content type='text'>
aa_replace_profiles() walks ns-&gt;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-&gt;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 &lt;colin.i.king@gmail.com&gt;
Closes: https://bugzilla.kernel.org/show_bug.cgi?id=221513
Cc: stable@vger.kernel.org
Signed-off-by: Ruslan Valiyev &lt;linuxoid@gmail.com&gt;
Signed-off-by: John Johansen &lt;john.johansen@canonical.com&gt;
</content>
</entry>
<entry>
<title>apparmor: remove or add symlinks to rawdata according to export_binary</title>
<updated>2026-06-14T03:14:07+00:00</updated>
<author>
<name>Georgia Garcia</name>
<email>georgia.garcia@canonical.com</email>
</author>
<published>2026-01-29T18:39:42+00:00</published>
<link rel='alternate' type='text/html' href='https://git.landau.one/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=59fe6fbc4cd45582bc8893de0a382a36562317b3'/>
<id>urn:sha1:59fe6fbc4cd45582bc8893de0a382a36562317b3</id>
<content type='text'>
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 &lt;georgia.garcia@canonical.com&gt;
Signed-off-by: John Johansen &lt;john.johansen@canonical.com&gt;
</content>
</entry>
<entry>
<title>apparmor: fix potential UAF in aa_replace_profiles</title>
<updated>2026-06-14T03:14:07+00:00</updated>
<author>
<name>Maxime Bélair</name>
<email>maxime.belair@canonical.com</email>
</author>
<published>2026-02-18T09:27:34+00:00</published>
<link rel='alternate' type='text/html' href='https://git.landau.one/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=7b42f95813dc9ceb6bda35afcf914630909a19f9'/>
<id>urn:sha1:7b42f95813dc9ceb6bda35afcf914630909a19f9</id>
<content type='text'>
The function aa_replace_profiles was accessing udata-&gt;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 &lt;georgia.garcia@canonical.com&gt;
Signed-off-by: Maxime Bélair &lt;maxime.belair@canonical.com&gt;
Signed-off-by: John Johansen &lt;john.johansen@canonical.com&gt;
</content>
</entry>
<entry>
<title>apparmor: free rawdata as soon as possible</title>
<updated>2026-06-14T03:14:07+00:00</updated>
<author>
<name>John Johansen</name>
<email>john.johansen@canonical.com</email>
</author>
<published>2026-03-01T20:29:06+00:00</published>
<link rel='alternate' type='text/html' href='https://git.landau.one/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=b9b864fc72367ffdbe79b7952518573e9d209844'/>
<id>urn:sha1:b9b864fc72367ffdbe79b7952518573e9d209844</id>
<content type='text'>
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 &lt;georgia.garcia@canonical.com&gt;
Signed-off-by: John Johansen &lt;john.johansen@canonical.com&gt;
</content>
</entry>
<entry>
<title>apparmor: fix race on rawdata dereference</title>
<updated>2026-03-09T23:05:44+00:00</updated>
<author>
<name>John Johansen</name>
<email>john.johansen@canonical.com</email>
</author>
<published>2026-02-24T18:20:02+00:00</published>
<link rel='alternate' type='text/html' href='https://git.landau.one/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=a0b7091c4de45a7325c8780e6934a894f92ac86b'/>
<id>urn:sha1:a0b7091c4de45a7325c8780e6934a894f92ac86b</id>
<content type='text'>
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 &lt;qsa@qualys.com&gt;
Reviewed-by: Georgia Garcia &lt;georgia.garcia@canonical.com&gt;
Reviewed-by: Maxime Bélair &lt;maxime.belair@canonical.com&gt;
Reviewed-by: Cengiz Can &lt;cengiz.can@canonical.com&gt;
Tested-by: Salvatore Bonaccorso &lt;carnil@debian.org&gt;
Signed-off-by: John Johansen &lt;john.johansen@canonical.com&gt;
</content>
</entry>
<entry>
<title>apparmor: fix unprivileged local user can do privileged policy management</title>
<updated>2026-03-09T23:05:43+00:00</updated>
<author>
<name>John Johansen</name>
<email>john.johansen@canonical.com</email>
</author>
<published>2025-11-07T16:36:04+00:00</published>
<link rel='alternate' type='text/html' href='https://git.landau.one/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=6601e13e82841879406bf9f369032656f441a425'/>
<id>urn:sha1:6601e13e82841879406bf9f369032656f441a425</id>
<content type='text'>
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 &lt;qsa@qualys.com&gt;
Tested-by: Salvatore Bonaccorso &lt;carnil@debian.org&gt;
Reviewed-by: Georgia Garcia &lt;georgia.garcia@canonical.com&gt;
Reviewed-by: Cengiz Can &lt;cengiz.can@canonical.com&gt;
Signed-off-by: John Johansen &lt;john.johansen@canonical.com&gt;
</content>
</entry>
</feed>
