]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
6.12-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 21 Jul 2026 13:14:47 +0000 (15:14 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 21 Jul 2026 13:14:47 +0000 (15:14 +0200)
added patches:
add-default_gfp-helper-macro-and-use-it-in-the-new-alloc_obj-helpers.patch
bpf-reject-bpf_map_type_inode_storage-creation-if-bpf-lsm-is-uninitialized.patch
default_gfp-avoid-using-the-newfangled-__va_opt__-trick.patch
fscrypt-fix-key-setup-in-edge-case-with-multiple-data-unit-sizes.patch
fscrypt-replace-mk_users-keyring-with-simple-list.patch
kvm-arm64-ensure-level-is-always-initialized-when-relaxing-perms.patch
kvm-arm64-fix-propagation-of-tlbi-level-in-kvm_pgtable_stage2_relax_perms.patch
kvm-move-kvm_io_bus_get_dev-locking-responsibilities-to-callers.patch
mm-damon-core-always-put-unsuccessfully-committed-target-pids.patch
perf-x86-amd-brs-fix-kernel-address-leakage.patch
selftests-fs-statmount-build-with-tools-include-dir.patch
slab-introduce-kmalloc_flex-and-family.patch
slab-introduce-kmalloc_obj-and-family.patch
slab-recognize-gfp-parameter-as-optional-in-kernel-doc.patch

15 files changed:
queue-6.12/add-default_gfp-helper-macro-and-use-it-in-the-new-alloc_obj-helpers.patch [new file with mode: 0644]
queue-6.12/bpf-reject-bpf_map_type_inode_storage-creation-if-bpf-lsm-is-uninitialized.patch [new file with mode: 0644]
queue-6.12/default_gfp-avoid-using-the-newfangled-__va_opt__-trick.patch [new file with mode: 0644]
queue-6.12/fscrypt-fix-key-setup-in-edge-case-with-multiple-data-unit-sizes.patch [new file with mode: 0644]
queue-6.12/fscrypt-replace-mk_users-keyring-with-simple-list.patch [new file with mode: 0644]
queue-6.12/kvm-arm64-ensure-level-is-always-initialized-when-relaxing-perms.patch [new file with mode: 0644]
queue-6.12/kvm-arm64-fix-propagation-of-tlbi-level-in-kvm_pgtable_stage2_relax_perms.patch [new file with mode: 0644]
queue-6.12/kvm-move-kvm_io_bus_get_dev-locking-responsibilities-to-callers.patch [new file with mode: 0644]
queue-6.12/mm-damon-core-always-put-unsuccessfully-committed-target-pids.patch [new file with mode: 0644]
queue-6.12/perf-x86-amd-brs-fix-kernel-address-leakage.patch [new file with mode: 0644]
queue-6.12/selftests-fs-statmount-build-with-tools-include-dir.patch [new file with mode: 0644]
queue-6.12/series
queue-6.12/slab-introduce-kmalloc_flex-and-family.patch [new file with mode: 0644]
queue-6.12/slab-introduce-kmalloc_obj-and-family.patch [new file with mode: 0644]
queue-6.12/slab-recognize-gfp-parameter-as-optional-in-kernel-doc.patch [new file with mode: 0644]

diff --git a/queue-6.12/add-default_gfp-helper-macro-and-use-it-in-the-new-alloc_obj-helpers.patch b/queue-6.12/add-default_gfp-helper-macro-and-use-it-in-the-new-alloc_obj-helpers.patch
new file mode 100644 (file)
index 0000000..629257d
--- /dev/null
@@ -0,0 +1,134 @@
+From stable+bounces-276926-greg=kroah.com@vger.kernel.org Fri Jul 17 06:47:26 2026
+From: Eric Biggers <ebiggers@kernel.org>
+Date: Thu, 16 Jul 2026 21:42:59 -0700
+Subject: add default_gfp() helper macro and use it in the new *alloc_obj() helpers
+To: stable@vger.kernel.org
+Cc: linux-hardening@vger.kernel.org, linux-fscrypt@vger.kernel.org, linux-kernel@vger.kernel.org, Linus Torvalds <torvalds@linux-foundation.org>, Eric Biggers <ebiggers@kernel.org>
+Message-ID: <20260717044303.425265-4-ebiggers@kernel.org>
+
+From: Linus Torvalds <torvalds@linux-foundation.org>
+
+commit e19e1b480ac73c3e62ffebbca1174f0f511f43e7 upstream.
+
+Most simple allocations use GFP_KERNEL, and with the new allocation
+helpers being introduced, let's just take advantage of that to simplify
+that default case.
+
+It's a numbers game:
+
+    git grep 'alloc_obj(' |
+       sed 's/.*\(GFP_[_A-Z]*\).*/\1/' |
+       sort | uniq -c | sort -n | tail
+
+shows that about 90% of all those new allocator instances just use that
+standard GFP_KERNEL.
+
+Those helpers are already macros, and we can easily just make it be the
+default case when the gfp argument is missing.
+
+And yes, we could do that for all the legacy interfaces too, but let's
+keep it to just the new ones at least for now, since those all got
+converted recently anyway, so this is not any "extra" noise outside of
+that limited conversion.
+
+And, in fact, I want to do this before doing the -rc1 release, exactly
+so that we don't get extra merge conflicts.
+
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Eric Biggers <ebiggers@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ include/linux/gfp.h  |    4 ++++
+ include/linux/slab.h |   48 ++++++++++++++++++++++++------------------------
+ 2 files changed, 28 insertions(+), 24 deletions(-)
+
+--- a/include/linux/gfp.h
++++ b/include/linux/gfp.h
+@@ -12,6 +12,10 @@
+ struct vm_area_struct;
+ struct mempolicy;
++/* Helper macro to avoid gfp flags if they are the default one */
++#define __default_gfp(a,...) a
++#define default_gfp(...) __default_gfp(__VA_ARGS__ __VA_OPT__(,) GFP_KERNEL)
++
+ /* Convert GFP flags to their corresponding migrate type */
+ #define GFP_MOVABLE_MASK (__GFP_RECLAIMABLE|__GFP_MOVABLE)
+ #define GFP_MOVABLE_SHIFT 3
+--- a/include/linux/slab.h
++++ b/include/linux/slab.h
+@@ -929,8 +929,8 @@ static __always_inline __alloc_size(1) v
+  * Returns: newly allocated pointer to a @VAR_OR_TYPE on success, or NULL
+  * on failure.
+  */
+-#define kmalloc_obj(VAR_OR_TYPE, GFP)                 \
+-      __alloc_objs(kmalloc, GFP, typeof(VAR_OR_TYPE), 1)
++#define kmalloc_obj(VAR_OR_TYPE, ...) \
++      __alloc_objs(kmalloc, default_gfp(__VA_ARGS__), typeof(VAR_OR_TYPE), 1)
+ /**
+  * kmalloc_objs - Allocate an array of the given type
+@@ -941,8 +941,8 @@ static __always_inline __alloc_size(1) v
+  * Returns: newly allocated pointer to array of @VAR_OR_TYPE on success,
+  * or NULL on failure.
+  */
+-#define kmalloc_objs(VAR_OR_TYPE, COUNT, GFP)         \
+-      __alloc_objs(kmalloc, GFP, typeof(VAR_OR_TYPE), COUNT)
++#define kmalloc_objs(VAR_OR_TYPE, COUNT, ...) \
++      __alloc_objs(kmalloc, default_gfp(__VA_ARGS__), typeof(VAR_OR_TYPE), COUNT)
+ /**
+  * kmalloc_flex - Allocate a single instance of the given flexible structure
+@@ -956,32 +956,32 @@ static __always_inline __alloc_size(1) v
+  * will immediately fail if @COUNT is larger than what the type of the
+  * struct's counter variable can represent.
+  */
+-#define kmalloc_flex(VAR_OR_TYPE, FAM, COUNT, GFP)    \
+-      __alloc_flex(kmalloc, GFP, typeof(VAR_OR_TYPE), FAM, COUNT)
++#define kmalloc_flex(VAR_OR_TYPE, FAM, COUNT, ...) \
++      __alloc_flex(kmalloc, default_gfp(__VA_ARGS__), typeof(VAR_OR_TYPE), FAM, COUNT)
+ /* All kzalloc aliases for kmalloc_(obj|objs|flex). */
+-#define kzalloc_obj(P, GFP)                           \
+-      __alloc_objs(kzalloc, GFP, typeof(P), 1)
+-#define kzalloc_objs(P, COUNT, GFP)                   \
+-      __alloc_objs(kzalloc, GFP, typeof(P), COUNT)
+-#define kzalloc_flex(P, FAM, COUNT, GFP)              \
+-      __alloc_flex(kzalloc, GFP, typeof(P), FAM, COUNT)
++#define kzalloc_obj(P, ...) \
++      __alloc_objs(kzalloc, default_gfp(__VA_ARGS__), typeof(P), 1)
++#define kzalloc_objs(P, COUNT, ...) \
++      __alloc_objs(kzalloc, default_gfp(__VA_ARGS__), typeof(P), COUNT)
++#define kzalloc_flex(P, FAM, COUNT, ...)              \
++      __alloc_flex(kzalloc, default_gfp(__VA_ARGS__), typeof(P), FAM, COUNT)
+ /* All kvmalloc aliases for kmalloc_(obj|objs|flex). */
+-#define kvmalloc_obj(P, GFP)                          \
+-      __alloc_objs(kvmalloc, GFP, typeof(P), 1)
+-#define kvmalloc_objs(P, COUNT, GFP)                  \
+-      __alloc_objs(kvmalloc, GFP, typeof(P), COUNT)
+-#define kvmalloc_flex(P, FAM, COUNT, GFP)             \
+-      __alloc_flex(kvmalloc, GFP, typeof(P), FAM, COUNT)
++#define kvmalloc_obj(P, ...) \
++      __alloc_objs(kvmalloc, default_gfp(__VA_ARGS__), typeof(P), 1)
++#define kvmalloc_objs(P, COUNT, ...) \
++      __alloc_objs(kvmalloc, default_gfp(__VA_ARGS__), typeof(P), COUNT)
++#define kvmalloc_flex(P, FAM, COUNT, ...) \
++      __alloc_flex(kvmalloc, default_gfp(__VA_ARGS__), typeof(P), FAM, COUNT)
+ /* All kvzalloc aliases for kmalloc_(obj|objs|flex). */
+-#define kvzalloc_obj(P, GFP)                          \
+-      __alloc_objs(kvzalloc, GFP, typeof(P), 1)
+-#define kvzalloc_objs(P, COUNT, GFP)                  \
+-      __alloc_objs(kvzalloc, GFP, typeof(P), COUNT)
+-#define kvzalloc_flex(P, FAM, COUNT, GFP)             \
+-      __alloc_flex(kvzalloc, GFP, typeof(P), FAM, COUNT)
++#define kvzalloc_obj(P, ...) \
++      __alloc_objs(kvzalloc, default_gfp(__VA_ARGS__), typeof(P), 1)
++#define kvzalloc_objs(P, COUNT, ...) \
++      __alloc_objs(kvzalloc, default_gfp(__VA_ARGS__), typeof(P), COUNT)
++#define kvzalloc_flex(P, FAM, COUNT, ...) \
++      __alloc_flex(kvzalloc, default_gfp(__VA_ARGS__), typeof(P), FAM, COUNT)
+ #define kmem_buckets_alloc(_b, _size, _flags) \
+       alloc_hooks(__kmalloc_node_noprof(PASS_BUCKET_PARAMS(_size, _b), _flags, NUMA_NO_NODE))
diff --git a/queue-6.12/bpf-reject-bpf_map_type_inode_storage-creation-if-bpf-lsm-is-uninitialized.patch b/queue-6.12/bpf-reject-bpf_map_type_inode_storage-creation-if-bpf-lsm-is-uninitialized.patch
new file mode 100644 (file)
index 0000000..343fef6
--- /dev/null
@@ -0,0 +1,112 @@
+From a6f0643e4f63cfaa0d5d4a69de4f132eac4b8fe4 Mon Sep 17 00:00:00 2001
+From: Matt Bobrowski <mattbobrowski@google.com>
+Date: Sun, 28 Jun 2026 20:11:03 +0000
+Subject: bpf: Reject BPF_MAP_TYPE_INODE_STORAGE creation if BPF LSM is uninitialized
+
+From: Matt Bobrowski <mattbobrowski@google.com>
+
+commit a6f0643e4f63cfaa0d5d4a69de4f132eac4b8fe4 upstream.
+
+When CONFIG_BPF_LSM=y is set, BPF inode storage maps
+(BPF_MAP_TYPE_INODE_STORAGE) are compiled into the kernel. However,
+if the BPF LSM is not explicitly enabled at boot time (e.g. omitted
+from the "lsm=" boot parameter), lsm_prepare() is never executed for
+the BPF LSM.
+
+Consequently, the BPF inode security blob offset
+(bpf_lsm_blob_sizes.lbs_inode) is never initialized and remains at
+its default compiled size of 8 bytes instead of being updated to a
+valid offset past the reserved struct rcu_head (typically 16 bytes
+or more).
+
+When a privileged user creates and updates a BPF_MAP_TYPE_INODE_STORAGE
+map, bpf_inode() evaluates inode->i_security + 8. This erroneously
+aliases the struct rcu_head.func callback pointer at the beginning
+of the inode->i_security blob. During subsequent map element cleanup
+or inode destruction, writing NULL to owner_storage clears the queued
+RCU callback pointer. When rcu_do_batch() later executes the queued
+callback, it attempts an instruction fetch at address 0x0, triggering
+an immediate kernel panic.
+
+Fix this by introducing a global bpf_lsm_initialized boolean flag
+marked with __ro_after_init. Set this flag to true inside bpf_lsm_init()
+when the LSM framework successfully registers the BPF LSM. Gate map
+allocation in inode_storage_map_alloc() on this flag, returning
+-EOPNOTSUPP if the BPF LSM is in turn uninitialized.
+
+This fail-fast approach prevents userspace from allocating inode
+storage maps when the supporting BPF LSM infrastructure is absent,
+avoiding zombie map states.
+
+Fixes: 8ea636848aca ("bpf: Implement bpf_local_storage for inodes")
+Reported-by: oxsignal <awo@kakao.com>
+Signed-off-by: Matt Bobrowski <mattbobrowski@google.com>
+Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
+Reviewed-by: Emil Tsalapatis <emil@etsalapatis.com>
+Reviewed-by: Amery Hung <ameryhung@gmail.com>
+Link: https://lore.kernel.org/bpf/20260628201103.3624525-1-mattbobrowski@google.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ include/linux/bpf_lsm.h        |    4 ++++
+ kernel/bpf/bpf_inode_storage.c |    9 +++++++++
+ security/bpf/hooks.c           |    3 +++
+ 3 files changed, 16 insertions(+)
+
+--- a/include/linux/bpf_lsm.h
++++ b/include/linux/bpf_lsm.h
+@@ -14,6 +14,8 @@
+ #ifdef CONFIG_BPF_LSM
++extern bool bpf_lsm_initialized __ro_after_init;
++
+ #define LSM_HOOK(RET, DEFAULT, NAME, ...) \
+       RET bpf_lsm_##NAME(__VA_ARGS__);
+ #include <linux/lsm_hook_defs.h>
+@@ -50,6 +52,8 @@ int bpf_lsm_get_retval_range(const struc
+                            struct bpf_retval_range *range);
+ #else /* !CONFIG_BPF_LSM */
++#define bpf_lsm_initialized false
++
+ static inline bool bpf_lsm_is_sleepable_hook(u32 btf_id)
+ {
+       return false;
+--- a/kernel/bpf/bpf_inode_storage.c
++++ b/kernel/bpf/bpf_inode_storage.c
+@@ -182,6 +182,15 @@ static int notsupp_get_next_key(struct b
+ static struct bpf_map *inode_storage_map_alloc(union bpf_attr *attr)
+ {
++      /*
++       * Do not allow allocation of BPF_MAP_TYPE_INODE_STORAGE if the BPF LSM
++       * was not initialized by the LSM framework at boot. Without proper
++       * initialization, the BPF inode security blob offset remains unprepared,
++       * causing bpf_inode() to calculate an invalid memory offset and corrupt
++       * inode->i_security.
++       */
++      if (!bpf_lsm_initialized)
++              return ERR_PTR(-EOPNOTSUPP);
+       return bpf_local_storage_map_alloc(attr, &inode_cache, false);
+ }
+--- a/security/bpf/hooks.c
++++ b/security/bpf/hooks.c
+@@ -7,6 +7,8 @@
+ #include <linux/bpf_lsm.h>
+ #include <uapi/linux/lsm.h>
++bool bpf_lsm_initialized __ro_after_init;
++
+ static struct security_hook_list bpf_lsm_hooks[] __ro_after_init = {
+       #define LSM_HOOK(RET, DEFAULT, NAME, ...) \
+       LSM_HOOK_INIT(NAME, bpf_lsm_##NAME),
+@@ -25,6 +27,7 @@ static int __init bpf_lsm_init(void)
+ {
+       security_add_hooks(bpf_lsm_hooks, ARRAY_SIZE(bpf_lsm_hooks),
+                          &bpf_lsmid);
++      bpf_lsm_initialized = true;
+       pr_info("LSM support for eBPF active\n");
+       return 0;
+ }
diff --git a/queue-6.12/default_gfp-avoid-using-the-newfangled-__va_opt__-trick.patch b/queue-6.12/default_gfp-avoid-using-the-newfangled-__va_opt__-trick.patch
new file mode 100644 (file)
index 0000000..b3ecce5
--- /dev/null
@@ -0,0 +1,50 @@
+From stable+bounces-276927-greg=kroah.com@vger.kernel.org Fri Jul 17 06:47:05 2026
+From: Eric Biggers <ebiggers@kernel.org>
+Date: Thu, 16 Jul 2026 21:43:00 -0700
+Subject: default_gfp(): avoid using the "newfangled" __VA_OPT__ trick
+To: stable@vger.kernel.org
+Cc: linux-hardening@vger.kernel.org, linux-fscrypt@vger.kernel.org, linux-kernel@vger.kernel.org, Linus Torvalds <torvalds@linux-foundation.org>, Ricardo Ribalda <ribalda@chromium.org>, Richard Fitzgerald <rf@opensource.cirrus.com>, Ben Dooks <ben.dooks@codethink.co.uk>, Eric Biggers <ebiggers@kernel.org>
+Message-ID: <20260717044303.425265-5-ebiggers@kernel.org>
+
+From: Linus Torvalds <torvalds@linux-foundation.org>
+
+commit 551d44200152cb26f75d2ef990aeb6185b7e37fd upstream.
+
+The default_gfp() helper that I added is not wrong, but it turns out
+that it causes unnecessary headaches for 'sparse' which doesn't support
+the use of __VA_OPT__ (introduced in C++20 and C23, and supported by gcc
+and clang for a long time).
+
+We do already use __VA_OPT__ in some other cases in the kernel (drm/xe
+and btrfs), but it has been fairly limited.  Now it triggers for pretty
+much everything, and sparse ends up not working at all.
+
+We can use the traditional gcc ',##__VA_ARGS__' syntax instead: it may
+not be the "C standard" way and is slightly less natural in this
+context, but it is the traditional model for this and avoids the sparse
+problem.
+
+Reported-and-tested-by: Ricardo Ribalda <ribalda@chromium.org>
+Reported-and-tested-by: Richard Fitzgerald <rf@opensource.cirrus.com>
+Reported-by: Ben Dooks <ben.dooks@codethink.co.uk>
+Fixes: e19e1b480ac7 ("add default_gfp() helper macro and use it in the new *alloc_obj() helpers")
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Eric Biggers <ebiggers@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ include/linux/gfp.h |    4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/include/linux/gfp.h
++++ b/include/linux/gfp.h
+@@ -13,8 +13,8 @@ struct vm_area_struct;
+ struct mempolicy;
+ /* Helper macro to avoid gfp flags if they are the default one */
+-#define __default_gfp(a,...) a
+-#define default_gfp(...) __default_gfp(__VA_ARGS__ __VA_OPT__(,) GFP_KERNEL)
++#define __default_gfp(a,b,...) b
++#define default_gfp(...) __default_gfp(,##__VA_ARGS__,GFP_KERNEL)
+ /* Convert GFP flags to their corresponding migrate type */
+ #define GFP_MOVABLE_MASK (__GFP_RECLAIMABLE|__GFP_MOVABLE)
diff --git a/queue-6.12/fscrypt-fix-key-setup-in-edge-case-with-multiple-data-unit-sizes.patch b/queue-6.12/fscrypt-fix-key-setup-in-edge-case-with-multiple-data-unit-sizes.patch
new file mode 100644 (file)
index 0000000..fc45570
--- /dev/null
@@ -0,0 +1,427 @@
+From stable+bounces-276929-greg=kroah.com@vger.kernel.org Fri Jul 17 06:48:56 2026
+From: Eric Biggers <ebiggers@kernel.org>
+Date: Thu, 16 Jul 2026 21:43:02 -0700
+Subject: fscrypt: Fix key setup in edge case with multiple data unit sizes
+To: stable@vger.kernel.org
+Cc: linux-hardening@vger.kernel.org, linux-fscrypt@vger.kernel.org, linux-kernel@vger.kernel.org, Eric Biggers <ebiggers@kernel.org>
+Message-ID: <20260717044303.425265-7-ebiggers@kernel.org>
+
+From: Eric Biggers <ebiggers@kernel.org>
+
+commit dd015b566d505d698386103e9c80b739c7336eb8 upstream.
+
+The addition of support for customizable data unit sizes introduced an
+edge case where a file's contents can be en/decrypted with the wrong
+data unit size.  It occurs when there are multiple v2 policies that:
+
+- Have *different* data unit sizes, via the log2_data_unit_size field
+
+- Share the same master_key_identifier, contents_encryption_mode, and
+  either FSCRYPT_POLICY_FLAG_DIRECT_KEY,
+  FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32, or
+  FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64
+
+- Are being used on the same filesystem, which also must be mounted with
+  the "inlinecrypt" mount option.
+
+Fortunately this edge case doesn't actually occur in practice.  I just
+found it via code review.  But it needs to be fixed regardless.
+
+The bug is caused by the data unit size not being fully considered when
+blk_crypto_keys are cached in mk_direct_keys, mk_iv_ino_lblk_32_keys,
+and mk_iv_ino_lblk_64_keys.  They're differentiated only by master key,
+encryption mode, and flag.  However, each one actually has a data unit
+size too.  Only the first data unit size that is cached is used.
+
+To fix this, start using the data unit size to differentiate the cached
+keys.  For several reasons, including avoiding increasing the size of
+struct fscrypt_master_key, just replace all three arrays with a single
+linked list instead of changing them into two-dimensional arrays.  This
+works well when considering that in practice at most 2 entries are used
+across all three arrays, so it was already mostly wasted space.
+
+For simplicity, make the list also take over the publish/subscribe of
+the prepared key itself.  That is, create separate list nodes for
+blk_crypto_keys vs crypto_skciphers, and add nodes to the list only when
+their key is actually prepared.  (Note that the legacy
+fscrypt_direct_keys table in fs/crypto/keysetup_v1.c already works this
+way.)  This eliminates the need for the additional memory barriers when
+reading and writing the fields of struct fscrypt_prepared_key.
+
+Note that I technically should have included the data unit size in the
+HKDF info string as well.  But it's too late to change that.
+
+Fixes: 5b1188847180 ("fscrypt: support crypto data unit size less than filesystem block size")
+Cc: stable@vger.kernel.org
+Link: https://patch.msgid.link/20260618180652.52742-1-ebiggers@kernel.org
+Signed-off-by: Eric Biggers <ebiggers@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/crypto/fscrypt_private.h |   55 ++++++++++++--------
+ fs/crypto/inline_crypt.c    |    8 --
+ fs/crypto/keyring.c         |   23 +++++---
+ fs/crypto/keysetup.c        |  121 ++++++++++++++++++++++++++++----------------
+ 4 files changed, 126 insertions(+), 81 deletions(-)
+
+--- a/fs/crypto/fscrypt_private.h
++++ b/fs/crypto/fscrypt_private.h
+@@ -27,6 +27,9 @@
+  */
+ #define FSCRYPT_MIN_KEY_SIZE  16
++/* Maximum size of a raw fscrypt master key */
++#define FSCRYPT_MAX_RAW_KEY_SIZE      64
++
+ /*
+  * This mask is passed as the third argument to the crypto_alloc_*() functions
+  * to prevent fscrypt from using the Crypto API drivers for non-inline crypto
+@@ -217,7 +220,7 @@ struct fscrypt_symlink_data {
+  * @tfm: crypto API transform object
+  * @blk_key: key for blk-crypto
+  *
+- * Normally only one of the fields will be non-NULL.
++ * Only one of the fields is non-NULL.
+  */
+ struct fscrypt_prepared_key {
+       struct crypto_skcipher *tfm;
+@@ -226,6 +229,15 @@ struct fscrypt_prepared_key {
+ #endif
+ };
++/* An entry in the linked list ->mk_mode_keys */
++struct fscrypt_mode_key {
++      struct fscrypt_prepared_key key;
++      struct list_head link;
++      u8 hkdf_context;
++      u8 mode_num;
++      u8 data_unit_bits;
++};
++
+ /*
+  * fscrypt_inode_info - the "encryption key" for an inode
+  *
+@@ -413,20 +425,12 @@ void fscrypt_destroy_inline_crypt_key(st
+  * @prep_key, depending on which encryption implementation the file will use.
+  */
+ static inline bool
+-fscrypt_is_key_prepared(struct fscrypt_prepared_key *prep_key,
++fscrypt_is_key_prepared(const struct fscrypt_prepared_key *prep_key,
+                       const struct fscrypt_inode_info *ci)
+ {
+-      /*
+-       * The two smp_load_acquire()'s here pair with the smp_store_release()'s
+-       * in fscrypt_prepare_inline_crypt_key() and fscrypt_prepare_key().
+-       * I.e., in some cases (namely, if this prep_key is a per-mode
+-       * encryption key) another task can publish blk_key or tfm concurrently,
+-       * executing a RELEASE barrier.  We need to use smp_load_acquire() here
+-       * to safely ACQUIRE the memory the other task published.
+-       */
+       if (fscrypt_using_inline_encryption(ci))
+-              return smp_load_acquire(&prep_key->blk_key) != NULL;
+-      return smp_load_acquire(&prep_key->tfm) != NULL;
++              return prep_key->blk_key != NULL;
++      return prep_key->tfm != NULL;
+ }
+ #else /* CONFIG_FS_ENCRYPTION_INLINE_CRYPT */
+@@ -458,10 +462,10 @@ fscrypt_destroy_inline_crypt_key(struct
+ }
+ static inline bool
+-fscrypt_is_key_prepared(struct fscrypt_prepared_key *prep_key,
++fscrypt_is_key_prepared(const struct fscrypt_prepared_key *prep_key,
+                       const struct fscrypt_inode_info *ci)
+ {
+-      return smp_load_acquire(&prep_key->tfm) != NULL;
++      return prep_key->tfm != NULL;
+ }
+ #endif /* !CONFIG_FS_ENCRYPTION_INLINE_CRYPT */
+@@ -531,8 +535,8 @@ struct fscrypt_master_key {
+       /*
+        * Active and structural reference counts.  An active ref guarantees
+        * that the struct continues to exist, continues to be in the keyring
+-       * ->s_master_keys, and that any embedded subkeys (e.g.
+-       * ->mk_direct_keys) that have been prepared continue to exist.
++       * ->s_master_keys, and that any non-file-scoped subkeys (e.g.
++       * ->mk_mode_keys) that have been prepared continue to exist.
+        * A structural ref only guarantees that the struct continues to exist.
+        *
+        * There is one active ref associated with ->mk_present being true, and
+@@ -586,12 +590,21 @@ struct fscrypt_master_key {
+       spinlock_t              mk_decrypted_inodes_lock;
+       /*
+-       * Per-mode encryption keys for the various types of encryption policies
+-       * that use them.  Allocated and derived on-demand.
++       * A list of 'struct fscrypt_mode_key' for the (hkdf_context, mode_num,
++       * data_unit_bits, inlinecrypt) combinations that are in use for this
++       * master key, for hkdf_context in [HKDF_CONTEXT_DIRECT_KEY,
++       * HKDF_CONTEXT_IV_INO_LBLK_32_KEY, HKDF_CONTEXT_IV_INO_LBLK_64_KEY].
++       *
++       * This is a linked list and not a hash table because in practice
++       * there's just a single encryption policy per master key, using
++       * _at most_ 2 nodes in this list.  Per-file keys don't use this at all.
++       *
++       * This list is append-only until the master key is fully removed, at
++       * which time the list is cleared.  Before then,
++       * fscrypt_mode_key_setup_mutex synchronizes appends, and searches use
++       * the RCU read lock together with ->mk_sem held for read.
+        */
+-      struct fscrypt_prepared_key mk_direct_keys[FSCRYPT_MODE_MAX + 1];
+-      struct fscrypt_prepared_key mk_iv_ino_lblk_64_keys[FSCRYPT_MODE_MAX + 1];
+-      struct fscrypt_prepared_key mk_iv_ino_lblk_32_keys[FSCRYPT_MODE_MAX + 1];
++      struct list_head        mk_mode_keys;
+       /* Hash key for inode numbers.  Initialized only when needed. */
+       siphash_key_t           mk_ino_hash_key;
+--- a/fs/crypto/inline_crypt.c
++++ b/fs/crypto/inline_crypt.c
+@@ -191,13 +191,7 @@ int fscrypt_prepare_inline_crypt_key(str
+               goto fail;
+       }
+-      /*
+-       * Pairs with the smp_load_acquire() in fscrypt_is_key_prepared().
+-       * I.e., here we publish ->blk_key with a RELEASE barrier so that
+-       * concurrent tasks can ACQUIRE it.  Note that this concurrency is only
+-       * possible for per-mode keys, not for per-file keys.
+-       */
+-      smp_store_release(&prep_key->blk_key, blk_key);
++      prep_key->blk_key = blk_key;
+       return 0;
+ fail:
+--- a/fs/crypto/keyring.c
++++ b/fs/crypto/keyring.c
+@@ -86,14 +86,14 @@ void fscrypt_put_master_key(struct fscry
+ void fscrypt_put_master_key_activeref(struct super_block *sb,
+                                     struct fscrypt_master_key *mk)
+ {
+-      size_t i;
++      struct fscrypt_mode_key *node, *tmp;
+       if (!refcount_dec_and_test(&mk->mk_active_refs))
+               return;
+       /*
+        * No active references left, so complete the full removal of this
+        * fscrypt_master_key struct by removing it from the keyring and
+-       * destroying any subkeys embedded in it.
++       * destroying any non-file-scoped subkeys.
+        */
+       if (WARN_ON_ONCE(!sb->s_master_keys))
+@@ -109,13 +109,16 @@ void fscrypt_put_master_key_activeref(st
+       WARN_ON_ONCE(mk->mk_present);
+       WARN_ON_ONCE(!list_empty(&mk->mk_decrypted_inodes));
+-      for (i = 0; i <= FSCRYPT_MODE_MAX; i++) {
+-              fscrypt_destroy_prepared_key(
+-                              sb, &mk->mk_direct_keys[i]);
+-              fscrypt_destroy_prepared_key(
+-                              sb, &mk->mk_iv_ino_lblk_64_keys[i]);
+-              fscrypt_destroy_prepared_key(
+-                              sb, &mk->mk_iv_ino_lblk_32_keys[i]);
++      /*
++       * Destroy any non-file-scoped subkeys.  Since ->mk_active_refs == 0,
++       * they're no longer referenced by any inodes.  Nor can key setup run
++       * and use them again.  So they're no longer needed.  (This implies no
++       * concurrent readers, so we don't need list_del_rcu() for example.)
++       */
++      list_for_each_entry_safe(node, tmp, &mk->mk_mode_keys, link) {
++              fscrypt_destroy_prepared_key(sb, &node->key);
++              list_del(&node->link);
++              kfree(node);
+       }
+       memzero_explicit(&mk->mk_ino_hash_key,
+                        sizeof(mk->mk_ino_hash_key));
+@@ -444,6 +447,8 @@ static int add_new_master_key(struct sup
+       INIT_LIST_HEAD(&mk->mk_decrypted_inodes);
+       spin_lock_init(&mk->mk_decrypted_inodes_lock);
++      INIT_LIST_HEAD(&mk->mk_mode_keys);
++
+       if (mk_spec->type == FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER) {
+               err = allocate_master_key_users_keyring(mk);
+               if (err)
+--- a/fs/crypto/keysetup.c
++++ b/fs/crypto/keysetup.c
+@@ -159,13 +159,7 @@ int fscrypt_prepare_key(struct fscrypt_p
+       tfm = fscrypt_allocate_skcipher(ci->ci_mode, raw_key, ci->ci_inode);
+       if (IS_ERR(tfm))
+               return PTR_ERR(tfm);
+-      /*
+-       * Pairs with the smp_load_acquire() in fscrypt_is_key_prepared().
+-       * I.e., here we publish ->tfm with a RELEASE barrier so that
+-       * concurrent tasks can ACQUIRE it.  Note that this concurrency is only
+-       * possible for per-mode keys, not for per-file keys.
+-       */
+-      smp_store_release(&prep_key->tfm, tfm);
++      prep_key->tfm = tfm;
+       return 0;
+ }
+@@ -186,9 +180,37 @@ int fscrypt_set_per_file_enc_key(struct
+       return fscrypt_prepare_key(&ci->ci_enc_key, raw_key, ci);
+ }
++/*
++ * Find the fscrypt_prepared_key (if any) for a particular (mk, hkdf_context,
++ * mode_num, data_unit_bits, inlinecrypt) combination.
++ *
++ * The caller must hold ->mk_sem for reading and ->mk_present must be true,
++ * ensuring that ->mk_mode_keys is still append-only.
++ */
++static struct fscrypt_prepared_key *
++fscrypt_find_mode_key(struct fscrypt_master_key *mk, u8 hkdf_context,
++                    u8 mode_num, const struct fscrypt_inode_info *ci)
++{
++      struct fscrypt_mode_key *node;
++
++      /*
++       * The RCU read lock here is used only to synchronize with concurrent
++       * list_add_tail_rcu().  Concurrent deletions are impossible here, so
++       * returning a pointer to a node without taking any refcount is safe.
++       */
++      guard(rcu)();
++      list_for_each_entry_rcu(node, &mk->mk_mode_keys, link) {
++              if (node->hkdf_context == hkdf_context &&
++                  node->mode_num == mode_num &&
++                  node->data_unit_bits == ci->ci_data_unit_bits &&
++                  fscrypt_is_key_prepared(&node->key, ci))
++                      return &node->key;
++      }
++      return NULL;
++}
++
+ static int setup_per_mode_enc_key(struct fscrypt_inode_info *ci,
+                                 struct fscrypt_master_key *mk,
+-                                struct fscrypt_prepared_key *keys,
+                                 u8 hkdf_context, bool include_fs_uuid)
+ {
+       const struct inode *inode = ci->ci_inode;
+@@ -196,7 +218,8 @@ static int setup_per_mode_enc_key(struct
+       struct fscrypt_mode *mode = ci->ci_mode;
+       const u8 mode_num = mode - fscrypt_modes;
+       struct fscrypt_prepared_key *prep_key;
+-      u8 mode_key[FSCRYPT_MAX_KEY_SIZE];
++      struct fscrypt_mode_key *new_node;
++      u8 raw_mode_key[FSCRYPT_MAX_RAW_KEY_SIZE];
+       u8 hkdf_info[sizeof(mode_num) + sizeof(sb->s_uuid)];
+       unsigned int hkdf_infolen = 0;
+       int err;
+@@ -204,41 +227,52 @@ static int setup_per_mode_enc_key(struct
+       if (WARN_ON_ONCE(mode_num > FSCRYPT_MODE_MAX))
+               return -EINVAL;
+-      prep_key = &keys[mode_num];
+-      if (fscrypt_is_key_prepared(prep_key, ci)) {
++      prep_key = fscrypt_find_mode_key(mk, hkdf_context, mode_num, ci);
++      if (prep_key) {
+               ci->ci_enc_key = *prep_key;
+               return 0;
+       }
+-      mutex_lock(&fscrypt_mode_key_setup_mutex);
++      guard(mutex)(&fscrypt_mode_key_setup_mutex);
+-      if (fscrypt_is_key_prepared(prep_key, ci))
+-              goto done_unlock;
++      prep_key = fscrypt_find_mode_key(mk, hkdf_context, mode_num, ci);
++      if (prep_key) {
++              ci->ci_enc_key = *prep_key;
++              return 0;
++      }
+-      BUILD_BUG_ON(sizeof(mode_num) != 1);
+-      BUILD_BUG_ON(sizeof(sb->s_uuid) != 16);
+-      BUILD_BUG_ON(sizeof(hkdf_info) != 17);
+-      hkdf_info[hkdf_infolen++] = mode_num;
+-      if (include_fs_uuid) {
+-              memcpy(&hkdf_info[hkdf_infolen], &sb->s_uuid,
+-                     sizeof(sb->s_uuid));
+-              hkdf_infolen += sizeof(sb->s_uuid);
+-      }
+-      err = fscrypt_hkdf_expand(&mk->mk_secret.hkdf,
+-                                hkdf_context, hkdf_info, hkdf_infolen,
+-                                mode_key, mode->keysize);
+-      if (err)
+-              goto out_unlock;
+-      err = fscrypt_prepare_key(prep_key, mode_key, ci);
+-      memzero_explicit(mode_key, mode->keysize);
+-      if (err)
+-              goto out_unlock;
+-done_unlock:
++      new_node = kzalloc_obj(*new_node);
++      if (!new_node)
++              return -ENOMEM;
++      new_node->hkdf_context = hkdf_context;
++      new_node->mode_num = mode_num;
++      new_node->data_unit_bits = ci->ci_data_unit_bits;
++      prep_key = &new_node->key;
++
++      {
++              static_assert(sizeof(mode_num) == 1);
++              static_assert(sizeof(sb->s_uuid) == 16);
++              static_assert(sizeof(hkdf_info) == 17);
++              hkdf_info[hkdf_infolen++] = mode_num;
++              if (include_fs_uuid) {
++                      memcpy(&hkdf_info[hkdf_infolen], &sb->s_uuid,
++                             sizeof(sb->s_uuid));
++                      hkdf_infolen += sizeof(sb->s_uuid);
++              }
++              err = fscrypt_hkdf_expand(&mk->mk_secret.hkdf, hkdf_context,
++                                        hkdf_info, hkdf_infolen, raw_mode_key,
++                                        mode->keysize);
++              if (!err)
++                      err = fscrypt_prepare_key(prep_key, raw_mode_key, ci);
++              memzero_explicit(raw_mode_key, mode->keysize);
++      }
++      if (err) {
++              kfree(new_node);
++              return err;
++      }
++      list_add_tail_rcu(&new_node->link, &mk->mk_mode_keys);
+       ci->ci_enc_key = *prep_key;
+-      err = 0;
+-out_unlock:
+-      mutex_unlock(&fscrypt_mode_key_setup_mutex);
+-      return err;
++      return 0;
+ }
+ /*
+@@ -296,8 +330,8 @@ static int fscrypt_setup_iv_ino_lblk_32_
+ {
+       int err;
+-      err = setup_per_mode_enc_key(ci, mk, mk->mk_iv_ino_lblk_32_keys,
+-                                   HKDF_CONTEXT_IV_INO_LBLK_32_KEY, true);
++      err = setup_per_mode_enc_key(ci, mk, HKDF_CONTEXT_IV_INO_LBLK_32_KEY,
++                                   true);
+       if (err)
+               return err;
+@@ -346,8 +380,8 @@ static int fscrypt_setup_v2_file_key(str
+                * encryption key.  This ensures that the master key is
+                * consistently used only for HKDF, avoiding key reuse issues.
+                */
+-              err = setup_per_mode_enc_key(ci, mk, mk->mk_direct_keys,
+-                                           HKDF_CONTEXT_DIRECT_KEY, false);
++              err = setup_per_mode_enc_key(ci, mk, HKDF_CONTEXT_DIRECT_KEY,
++                                           false);
+       } else if (ci->ci_policy.v2.flags &
+                  FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64) {
+               /*
+@@ -356,9 +390,8 @@ static int fscrypt_setup_v2_file_key(str
+                * the IVs.  This format is optimized for use with inline
+                * encryption hardware compliant with the UFS standard.
+                */
+-              err = setup_per_mode_enc_key(ci, mk, mk->mk_iv_ino_lblk_64_keys,
+-                                           HKDF_CONTEXT_IV_INO_LBLK_64_KEY,
+-                                           true);
++              err = setup_per_mode_enc_key(
++                      ci, mk, HKDF_CONTEXT_IV_INO_LBLK_64_KEY, true);
+       } else if (ci->ci_policy.v2.flags &
+                  FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32) {
+               err = fscrypt_setup_iv_ino_lblk_32_key(ci, mk);
diff --git a/queue-6.12/fscrypt-replace-mk_users-keyring-with-simple-list.patch b/queue-6.12/fscrypt-replace-mk_users-keyring-with-simple-list.patch
new file mode 100644 (file)
index 0000000..6c98eb7
--- /dev/null
@@ -0,0 +1,454 @@
+From stable+bounces-276930-greg=kroah.com@vger.kernel.org Fri Jul 17 06:47:25 2026
+From: Eric Biggers <ebiggers@kernel.org>
+Date: Thu, 16 Jul 2026 21:43:03 -0700
+Subject: fscrypt: Replace mk_users keyring with simple list
+To: stable@vger.kernel.org
+Cc: linux-hardening@vger.kernel.org, linux-fscrypt@vger.kernel.org, linux-kernel@vger.kernel.org, Eric Biggers <ebiggers@kernel.org>, syzbot+f55b043dacf43776b50c@syzkaller.appspotmail.com, Mohammed EL Kadiri <med08elkadiri@gmail.com>
+Message-ID: <20260717044303.425265-8-ebiggers@kernel.org>
+
+From: Eric Biggers <ebiggers@kernel.org>
+
+commit 696c030e1e3438955aba443b308ee8b6faa3983e upstream.
+
+Change mk_users (the set of user claims to an fscrypt master key) from a
+'struct key' keyring to a simple linked list.
+
+It's still a collection of 'struct key' for quota tracking.  It was
+originally thought to be natural that a collection of 'struct key'
+should be held in a 'struct key' keyring.  In reality, it's just been
+causing problems, similar to how using 'struct key' for the filesystem
+keyring caused problems and was removed in commit d7e7b9af104c
+("fscrypt: stop using keyrings subsystem for fscrypt_master_key").
+
+Commit d3a7bd420076 ("fscrypt: clear keyring before calling key_put()")
+fixed mk_users cleanup to be synchronous.  But that apparently wasn't
+enough: the keyring subsystem's redundant locking is still generating
+lockdep false positives due to the interaction with filesystem reclaim.
+
+With the simple list, the redundant locking and lockdep issue goes away.
+
+Of course, searching a linked list is linear-time whereas the
+'struct key' keyring used a fancy constant-time associative array.  But
+that's fine here, since in practice there's just one entry in the list.
+In fact the new code is much faster in practice, since it's much smaller
+and doesn't have to convert the kuid_t into a string to search for it.
+
+Reported-by: syzbot+f55b043dacf43776b50c@syzkaller.appspotmail.com
+Closes: https://syzkaller.appspot.com/bug?extid=f55b043dacf43776b50c
+Reported-by: Mohammed EL Kadiri <med08elkadiri@gmail.com>
+Closes: https://lore.kernel.org/keyrings/20260614150041.21172-1-med08elkadiri@gmail.com/
+Fixes: 23c688b54016 ("fscrypt: allow unprivileged users to add/remove keys for v2 policies")
+Cc: stable@vger.kernel.org
+Link: https://patch.msgid.link/20260618221921.87896-1-ebiggers@kernel.org
+Signed-off-by: Eric Biggers <ebiggers@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/crypto/fscrypt_private.h |   36 ++++---
+ fs/crypto/keyring.c         |  220 ++++++++++++++++++--------------------------
+ 2 files changed, 117 insertions(+), 139 deletions(-)
+
+--- a/fs/crypto/fscrypt_private.h
++++ b/fs/crypto/fscrypt_private.h
+@@ -472,6 +472,19 @@ fscrypt_is_key_prepared(const struct fsc
+ /* keyring.c */
+ /*
++ * fscrypt_master_key_user - a user's claim to a master key
++ */
++struct fscrypt_master_key_user {
++      struct list_head link;
++      kuid_t uid;
++      /*
++       * This 'struct key' contains no secret.  It exists solely to charge the
++       * appropriate user's key quota.
++       */
++      struct key *quota_key;
++};
++
++/*
+  * fscrypt_master_key_secret - secret key material of an in-use master key
+  */
+ struct fscrypt_master_key_secret {
+@@ -568,19 +581,18 @@ struct fscrypt_master_key {
+       struct fscrypt_key_specifier            mk_spec;
+       /*
+-       * Keyring which contains a key of type 'key_type_fscrypt_user' for each
+-       * user who has added this key.  Normally each key will be added by just
+-       * one user, but it's possible that multiple users share a key, and in
+-       * that case we need to keep track of those users so that one user can't
+-       * remove the key before the others want it removed too.
+-       *
+-       * This is NULL for v1 policy keys; those can only be added by root.
+-       *
+-       * Locking: protected by ->mk_sem.  (We don't just rely on the keyrings
+-       * subsystem semaphore ->mk_users->sem, as we need support for atomic
+-       * search+insert along with proper synchronization with other fields.)
++       * List of user claims to this key (struct fscrypt_master_key_user).
++       * Normally each key will be added by just one user, but it's possible
++       * that multiple users share a key, and in that case we need to keep
++       * track of those users so that one user can't remove the key before the
++       * others want it removed too.
++       *
++       * Used only for v2 policy keys.  v1 policy keys can be added only by
++       * root, so user tracking doesn't apply to them.
++       *
++       * Locking: protected by ->mk_sem.
+        */
+-      struct key              *mk_users;
++      struct list_head        mk_users;
+       /*
+        * List of inodes that were unlocked using this key.  This allows the
+--- a/fs/crypto/keyring.c
++++ b/fs/crypto/keyring.c
+@@ -64,22 +64,19 @@ static void fscrypt_free_master_key(stru
+       kfree_sensitive(mk);
+ }
++static void clear_mk_users(struct fscrypt_master_key *mk);
++
+ void fscrypt_put_master_key(struct fscrypt_master_key *mk)
+ {
+       if (!refcount_dec_and_test(&mk->mk_struct_refs))
+               return;
+       /*
+-       * No structural references left, so free ->mk_users, and also free the
++       * No structural references left, so clear ->mk_users, and also free the
+        * fscrypt_master_key struct itself after an RCU grace period ensures
+        * that concurrent keyring lookups can no longer find it.
+        */
+       WARN_ON_ONCE(refcount_read(&mk->mk_active_refs) != 0);
+-      if (mk->mk_users) {
+-              /* Clear the keyring so the quota gets released right away. */
+-              keyring_clear(mk->mk_users);
+-              key_put(mk->mk_users);
+-              mk->mk_users = NULL;
+-      }
++      clear_mk_users(mk);
+       call_rcu(&mk->mk_rcu_head, fscrypt_free_master_key);
+ }
+@@ -164,8 +161,8 @@ static void fscrypt_user_key_describe(co
+ }
+ /*
+- * Type of key in ->mk_users.  Each key of this type represents a particular
+- * user who has added a particular master key.
++ * Type of fscrypt_master_key_user::quota_key.  This contains no secret; it
++ * exists solely to charge a user's key quota.
+  *
+  * Note that the name of this key type really should be something like
+  * ".fscrypt-user" instead of simply ".fscrypt".  But the shorter name is chosen
+@@ -179,30 +176,9 @@ static struct key_type key_type_fscrypt_
+       .describe               = fscrypt_user_key_describe,
+ };
+-#define FSCRYPT_MK_USERS_DESCRIPTION_SIZE     \
+-      (CONST_STRLEN("fscrypt-") + 2 * FSCRYPT_KEY_IDENTIFIER_SIZE + \
+-       CONST_STRLEN("-users") + 1)
+-
+ #define FSCRYPT_MK_USER_DESCRIPTION_SIZE      \
+       (2 * FSCRYPT_KEY_IDENTIFIER_SIZE + CONST_STRLEN(".uid.") + 10 + 1)
+-static void format_mk_users_keyring_description(
+-                      char description[FSCRYPT_MK_USERS_DESCRIPTION_SIZE],
+-                      const u8 mk_identifier[FSCRYPT_KEY_IDENTIFIER_SIZE])
+-{
+-      sprintf(description, "fscrypt-%*phN-users",
+-              FSCRYPT_KEY_IDENTIFIER_SIZE, mk_identifier);
+-}
+-
+-static void format_mk_user_description(
+-                      char description[FSCRYPT_MK_USER_DESCRIPTION_SIZE],
+-                      const u8 mk_identifier[FSCRYPT_KEY_IDENTIFIER_SIZE])
+-{
+-
+-      sprintf(description, "%*phN.uid.%u", FSCRYPT_KEY_IDENTIFIER_SIZE,
+-              mk_identifier, __kuid_val(current_fsuid()));
+-}
+-
+ /* Create ->s_master_keys if needed.  Synchronized by fscrypt_add_key_mutex. */
+ static int allocate_filesystem_keyring(struct super_block *sb)
+ {
+@@ -337,91 +313,94 @@ out:
+       return mk;
+ }
+-static int allocate_master_key_users_keyring(struct fscrypt_master_key *mk)
+-{
+-      char description[FSCRYPT_MK_USERS_DESCRIPTION_SIZE];
+-      struct key *keyring;
+-
+-      format_mk_users_keyring_description(description,
+-                                          mk->mk_spec.u.identifier);
+-      keyring = keyring_alloc(description, GLOBAL_ROOT_UID, GLOBAL_ROOT_GID,
+-                              current_cred(), KEY_POS_SEARCH |
+-                                KEY_USR_SEARCH | KEY_USR_READ | KEY_USR_VIEW,
+-                              KEY_ALLOC_NOT_IN_QUOTA, NULL, NULL);
+-      if (IS_ERR(keyring))
+-              return PTR_ERR(keyring);
+-
+-      mk->mk_users = keyring;
+-      return 0;
+-}
+-
+-/*
+- * Find the current user's "key" in the master key's ->mk_users.
+- * Returns ERR_PTR(-ENOKEY) if not found.
+- */
+-static struct key *find_master_key_user(struct fscrypt_master_key *mk)
+-{
+-      char description[FSCRYPT_MK_USER_DESCRIPTION_SIZE];
+-      key_ref_t keyref;
+-
+-      format_mk_user_description(description, mk->mk_spec.u.identifier);
+-
+-      /*
+-       * We need to mark the keyring reference as "possessed" so that we
+-       * acquire permission to search it, via the KEY_POS_SEARCH permission.
+-       */
+-      keyref = keyring_search(make_key_ref(mk->mk_users, true /*possessed*/),
+-                              &key_type_fscrypt_user, description, false);
+-      if (IS_ERR(keyref)) {
+-              if (PTR_ERR(keyref) == -EAGAIN || /* not found */
+-                  PTR_ERR(keyref) == -EKEYREVOKED) /* recently invalidated */
+-                      keyref = ERR_PTR(-ENOKEY);
+-              return ERR_CAST(keyref);
++/* Find the current user's claim in ->mk_users.  ->mk_sem must be held. */
++static struct fscrypt_master_key_user *
++find_master_key_user(struct fscrypt_master_key *mk)
++{
++      struct fscrypt_master_key_user *mk_user;
++      kuid_t uid = current_fsuid();
++
++      list_for_each_entry(mk_user, &mk->mk_users, link) {
++              if (uid_eq(mk_user->uid, uid))
++                      return mk_user;
+       }
+-      return key_ref_to_ptr(keyref);
++      return NULL;
+ }
+ /*
+- * Give the current user a "key" in ->mk_users.  This charges the user's quota
++ * Give the current user a claim in ->mk_users.  This charges the user's quota
+  * and marks the master key as added by the current user, so that it cannot be
+  * removed by another user with the key.  Either ->mk_sem must be held for
+  * write, or the master key must be still undergoing initialization.
+  */
+ static int add_master_key_user(struct fscrypt_master_key *mk)
+ {
++      kuid_t uid = current_fsuid();
+       char description[FSCRYPT_MK_USER_DESCRIPTION_SIZE];
+-      struct key *mk_user;
++      struct key *quota_key;
++      struct fscrypt_master_key_user *mk_user;
+       int err;
+-      format_mk_user_description(description, mk->mk_spec.u.identifier);
+-      mk_user = key_alloc(&key_type_fscrypt_user, description,
+-                          current_fsuid(), current_gid(), current_cred(),
+-                          KEY_POS_SEARCH | KEY_USR_VIEW, 0, NULL);
+-      if (IS_ERR(mk_user))
+-              return PTR_ERR(mk_user);
++      snprintf(description, sizeof(description), "%*phN.uid.%u",
++               FSCRYPT_KEY_IDENTIFIER_SIZE, mk->mk_spec.u.identifier,
++               __kuid_val(uid));
++      quota_key = key_alloc(&key_type_fscrypt_user, description, uid,
++                            current_gid(), current_cred(),
++                            KEY_POS_SEARCH | KEY_USR_VIEW, 0, NULL);
++      if (IS_ERR(quota_key))
++              return PTR_ERR(quota_key);
++
++      err = key_instantiate_and_link(quota_key, NULL, 0, NULL, NULL);
++      if (err) {
++              key_put(quota_key);
++              return err;
++      }
++
++      mk_user = kzalloc_obj(*mk_user);
++      if (!mk_user) {
++              key_put(quota_key);
++              return -ENOMEM;
++      }
++      mk_user->uid = uid;
++      mk_user->quota_key = quota_key;
++      list_add(&mk_user->link, &mk->mk_users);
++      return 0;
++}
+-      err = key_instantiate_and_link(mk_user, NULL, 0, mk->mk_users, NULL);
+-      key_put(mk_user);
+-      return err;
++static void unlink_and_free_mk_user(struct fscrypt_master_key_user *mk_user)
++{
++      list_del(&mk_user->link);
++      key_put(mk_user->quota_key);
++      kfree(mk_user);
+ }
+ /*
+- * Remove the current user's "key" from ->mk_users.
++ * Remove the current user's claim from ->mk_users.
+  * ->mk_sem must be held for write.
+  *
+- * Returns 0 if removed, -ENOKEY if not found, or another -errno code.
++ * Returns 0 if removed or -ENOKEY if not found.
+  */
+ static int remove_master_key_user(struct fscrypt_master_key *mk)
+ {
+-      struct key *mk_user;
+-      int err;
++      struct fscrypt_master_key_user *mk_user;
+       mk_user = find_master_key_user(mk);
+-      if (IS_ERR(mk_user))
+-              return PTR_ERR(mk_user);
+-      err = key_unlink(mk->mk_users, mk_user);
+-      key_put(mk_user);
+-      return err;
++      if (!mk_user)
++              return -ENOKEY;
++      unlink_and_free_mk_user(mk_user);
++      return 0;
++}
++
++/*
++ * Clear ->mk_users.  Either ->mk_sem must be held for write, or 'mk' must have
++ * no structural references left.
++ */
++static void clear_mk_users(struct fscrypt_master_key *mk)
++{
++      struct fscrypt_master_key_user *mk_user, *tmp;
++
++      list_for_each_entry_safe(mk_user, tmp, &mk->mk_users, link)
++              unlink_and_free_mk_user(mk_user);
+ }
+ /*
+@@ -444,15 +423,14 @@ static int add_new_master_key(struct sup
+       refcount_set(&mk->mk_struct_refs, 1);
+       mk->mk_spec = *mk_spec;
++      INIT_LIST_HEAD(&mk->mk_users);
++
+       INIT_LIST_HEAD(&mk->mk_decrypted_inodes);
+       spin_lock_init(&mk->mk_decrypted_inodes_lock);
+       INIT_LIST_HEAD(&mk->mk_mode_keys);
+       if (mk_spec->type == FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER) {
+-              err = allocate_master_key_users_keyring(mk);
+-              if (err)
+-                      goto out_put;
+               err = add_master_key_user(mk);
+               if (err)
+                       goto out_put;
+@@ -481,19 +459,13 @@ static int add_existing_master_key(struc
+       int err;
+       /*
+-       * If the current user is already in ->mk_users, then there's nothing to
+-       * do.  Otherwise, we need to add the user to ->mk_users.  (Neither is
+-       * applicable for v1 policy keys, which have NULL ->mk_users.)
++       * For v2 policy keys (FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER): If the current
++       * user is already in ->mk_users, then there's nothing to do.
++       * Otherwise, add the user to ->mk_users.
+        */
+-      if (mk->mk_users) {
+-              struct key *mk_user = find_master_key_user(mk);
+-
+-              if (mk_user != ERR_PTR(-ENOKEY)) {
+-                      if (IS_ERR(mk_user))
+-                              return PTR_ERR(mk_user);
+-                      key_put(mk_user);
++      if (mk->mk_spec.type == FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER) {
++              if (find_master_key_user(mk) != NULL)
+                       return 0;
+-              }
+               err = add_master_key_user(mk);
+               if (err)
+                       return err;
+@@ -847,7 +819,6 @@ int fscrypt_verify_key_added(struct supe
+ {
+       struct fscrypt_key_specifier mk_spec;
+       struct fscrypt_master_key *mk;
+-      struct key *mk_user;
+       int err;
+       mk_spec.type = FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER;
+@@ -859,13 +830,10 @@ int fscrypt_verify_key_added(struct supe
+               goto out;
+       }
+       down_read(&mk->mk_sem);
+-      mk_user = find_master_key_user(mk);
+-      if (IS_ERR(mk_user)) {
+-              err = PTR_ERR(mk_user);
+-      } else {
+-              key_put(mk_user);
++      if (find_master_key_user(mk) != NULL)
+               err = 0;
+-      }
++      else
++              err = -ENOKEY;
+       up_read(&mk->mk_sem);
+       fscrypt_put_master_key(mk);
+ out:
+@@ -1057,16 +1025,18 @@ static int do_remove_key(struct file *fi
+       down_write(&mk->mk_sem);
+       /* If relevant, remove current user's (or all users) claim to the key */
+-      if (mk->mk_users && mk->mk_users->keys.nr_leaves_on_tree != 0) {
+-              if (all_users)
+-                      err = keyring_clear(mk->mk_users);
+-              else
++      if (!list_empty(&mk->mk_users)) {
++              if (all_users) {
++                      clear_mk_users(mk);
++                      err = 0;
++              } else {
+                       err = remove_master_key_user(mk);
++              }
+               if (err) {
+                       up_write(&mk->mk_sem);
+                       goto out_put_key;
+               }
+-              if (mk->mk_users->keys.nr_leaves_on_tree != 0) {
++              if (!list_empty(&mk->mk_users)) {
+                       /*
+                        * Other users have still added the key too.  We removed
+                        * the current user's claim to the key, but we still
+@@ -1152,6 +1122,8 @@ int fscrypt_ioctl_get_key_status(struct
+       struct super_block *sb = file_inode(filp)->i_sb;
+       struct fscrypt_get_key_status_arg arg;
+       struct fscrypt_master_key *mk;
++      kuid_t uid;
++      const struct fscrypt_master_key_user *mk_user;
+       int err;
+       if (copy_from_user(&arg, uarg, sizeof(arg)))
+@@ -1184,19 +1156,13 @@ int fscrypt_ioctl_get_key_status(struct
+       }
+       arg.status = FSCRYPT_KEY_STATUS_PRESENT;
+-      if (mk->mk_users) {
+-              struct key *mk_user;
+-              arg.user_count = mk->mk_users->keys.nr_leaves_on_tree;
+-              mk_user = find_master_key_user(mk);
+-              if (!IS_ERR(mk_user)) {
++      uid = current_fsuid();
++      list_for_each_entry(mk_user, &mk->mk_users, link) {
++              arg.user_count++;
++              if (uid_eq(mk_user->uid, uid))
+                       arg.status_flags |=
+                               FSCRYPT_KEY_STATUS_FLAG_ADDED_BY_SELF;
+-                      key_put(mk_user);
+-              } else if (mk_user != ERR_PTR(-ENOKEY)) {
+-                      err = PTR_ERR(mk_user);
+-                      goto out_release_key;
+-              }
+       }
+       err = 0;
+ out_release_key:
diff --git a/queue-6.12/kvm-arm64-ensure-level-is-always-initialized-when-relaxing-perms.patch b/queue-6.12/kvm-arm64-ensure-level-is-always-initialized-when-relaxing-perms.patch
new file mode 100644 (file)
index 0000000..30b43ac
--- /dev/null
@@ -0,0 +1,39 @@
+From 100baf0184896f859290a684f864b8200d8ac872 Mon Sep 17 00:00:00 2001
+From: Oliver Upton <oupton@kernel.org>
+Date: Wed, 1 Jul 2026 16:16:19 -0700
+Subject: KVM: arm64: Ensure level is always initialized when relaxing perms
+
+From: Oliver Upton <oupton@kernel.org>
+
+commit 100baf0184896f859290a684f864b8200d8ac872 upstream.
+
+stage2_update_leaf_attrs() returns early before writing to @level if the
+table walker returned an error. At the same time,
+kvm_pgtable_stage2_relax_perms() uses the level as a TLBI TTL hint when the
+error was EAGAIN, indicating the vCPU raced with a table update and the TLB
+entry it hit is now stale.
+
+Fall back to an unknown TTL if none was provided by the walk.
+
+Cc: stable@vger.kernel.org
+Fixes: be097997a273 ("KVM: arm64: Always invalidate TLB for stage-2 permission faults")
+Signed-off-by: Oliver Upton <oupton@kernel.org>
+Reviewed-by: Wei-Lin Chang <weilin.chang@arm.com>
+Link: https://patch.msgid.link/20260701231620.3300204-2-oupton@kernel.org
+Signed-off-by: Marc Zyngier <maz@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/arm64/kvm/hyp/pgtable.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/arch/arm64/kvm/hyp/pgtable.c
++++ b/arch/arm64/kvm/hyp/pgtable.c
+@@ -1314,7 +1314,7 @@ int kvm_pgtable_stage2_relax_perms(struc
+                                  enum kvm_pgtable_prot prot)
+ {
+       int ret;
+-      s8 level;
++      s8 level = TLBI_TTL_UNKNOWN;
+       kvm_pte_t set = 0, clr = 0;
+       if (prot & KVM_PTE_LEAF_ATTR_HI_SW)
diff --git a/queue-6.12/kvm-arm64-fix-propagation-of-tlbi-level-in-kvm_pgtable_stage2_relax_perms.patch b/queue-6.12/kvm-arm64-fix-propagation-of-tlbi-level-in-kvm_pgtable_stage2_relax_perms.patch
new file mode 100644 (file)
index 0000000..1124b39
--- /dev/null
@@ -0,0 +1,46 @@
+From 8d187d4b33c262c0f3e44842553521151d8629e8 Mon Sep 17 00:00:00 2001
+From: Marc Zyngier <maz@kernel.org>
+Date: Tue, 7 Jul 2026 17:29:35 +0100
+Subject: KVM: arm64: Fix propagation of TLBI level in kvm_pgtable_stage2_relax_perms()
+
+From: Marc Zyngier <maz@kernel.org>
+
+commit 8d187d4b33c262c0f3e44842553521151d8629e8 upstream.
+
+Assigning the invalidation level (an s8 value) with TLBI_TTL_UNKNOWN
+(a 32bit signed value) is not ideal, to say the least. Instead of
+this, only pass TLBI_TTL_UNKNOWN to __kvm_tlb_flush_vmid_ipa_nsh()
+when we know for sure that we don't have a provided level.
+
+Fixes: 100baf0184896 ("KVM: arm64: Ensure level is always initialized when relaxing perms")
+Reported-by: Mark Brown <broonie@kernel.org>
+Reviewed-by: Oliver Upton <oupton@kernel.org>
+Link: https://lore.kernel.org/r/akztC7H2IsEKaq4i@sirena.org.uk
+Link: https://patch.msgid.link/20260707162935.1900874-1-maz@kernel.org
+Signed-off-by: Marc Zyngier <maz@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/arm64/kvm/hyp/pgtable.c |    5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+--- a/arch/arm64/kvm/hyp/pgtable.c
++++ b/arch/arm64/kvm/hyp/pgtable.c
+@@ -1314,7 +1314,7 @@ int kvm_pgtable_stage2_relax_perms(struc
+                                  enum kvm_pgtable_prot prot)
+ {
+       int ret;
+-      s8 level = TLBI_TTL_UNKNOWN;
++      s8 level;
+       kvm_pte_t set = 0, clr = 0;
+       if (prot & KVM_PTE_LEAF_ATTR_HI_SW)
+@@ -1333,7 +1333,8 @@ int kvm_pgtable_stage2_relax_perms(struc
+                                      KVM_PGTABLE_WALK_HANDLE_FAULT |
+                                      KVM_PGTABLE_WALK_SHARED);
+       if (!ret || ret == -EAGAIN)
+-              kvm_call_hyp(__kvm_tlb_flush_vmid_ipa_nsh, pgt->mmu, addr, level);
++              kvm_call_hyp(__kvm_tlb_flush_vmid_ipa_nsh, pgt->mmu, addr,
++                           (ret == -EAGAIN) ? TLBI_TTL_UNKNOWN : level);
+       return ret;
+ }
diff --git a/queue-6.12/kvm-move-kvm_io_bus_get_dev-locking-responsibilities-to-callers.patch b/queue-6.12/kvm-move-kvm_io_bus_get_dev-locking-responsibilities-to-callers.patch
new file mode 100644 (file)
index 0000000..f47ea30
--- /dev/null
@@ -0,0 +1,79 @@
+From 3a07249981629ace483ebbef81ef6b34c2d2afec Mon Sep 17 00:00:00 2001
+From: Marc Zyngier <maz@kernel.org>
+Date: Sat, 27 Jun 2026 11:51:05 +0100
+Subject: KVM: Move kvm_io_bus_get_dev() locking responsibilities to callers
+
+From: Marc Zyngier <maz@kernel.org>
+
+commit 3a07249981629ace483ebbef81ef6b34c2d2afec upstream.
+
+kvm_io_bus_get_dev() returns a device that is only matched by the
+address, and nothing else. This can cause a lifetime issue if
+the matched device is not the expected type, as by the time
+the caller can introspect the object, it might be gone (the srcu
+lock having been dropped).
+
+Given that there is only a single user of this helper, the simplest
+option is to move the locking responsibility to the caller, which
+can keep the srcu lock held for as long as it wants.
+
+Note that this aligns with other kvm_io_bus*() helpers, which
+already require the srcu lock to be held by the callers.
+
+Reported-by: Will Deacon <will@kernel.org>
+Fixes: 8a39d00670f07 ("KVM: kvm_io_bus: Add kvm_io_bus_get_dev() call")
+Link: https://lore.kernel.org/all/20260626111344.802555-1-maz@kernel.org
+Cc: stable@vger.kernel.org
+Reviewed-by: Oliver Upton <oupton@kernel.org>
+Link: https://patch.msgid.link/20260627105105.1005990-1-maz@kernel.org
+Signed-off-by: Marc Zyngier <maz@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/arm64/kvm/vgic/vgic-its.c |    2 ++
+ virt/kvm/kvm_main.c            |   16 +++++-----------
+ 2 files changed, 7 insertions(+), 11 deletions(-)
+
+--- a/arch/arm64/kvm/vgic/vgic-its.c
++++ b/arch/arm64/kvm/vgic/vgic-its.c
+@@ -510,6 +510,8 @@ static struct vgic_its *__vgic_doorbell_
+       struct kvm_io_device *kvm_io_dev;
+       struct vgic_io_device *iodev;
++      guard(srcu)(&kvm->srcu);
++
+       kvm_io_dev = kvm_io_bus_get_dev(kvm, KVM_MMIO_BUS, db);
+       if (!kvm_io_dev)
+               return ERR_PTR(-EINVAL);
+--- a/virt/kvm/kvm_main.c
++++ b/virt/kvm/kvm_main.c
+@@ -6063,25 +6063,19 @@ struct kvm_io_device *kvm_io_bus_get_dev
+                                        gpa_t addr)
+ {
+       struct kvm_io_bus *bus;
+-      int dev_idx, srcu_idx;
+-      struct kvm_io_device *iodev = NULL;
++      int dev_idx;
+-      srcu_idx = srcu_read_lock(&kvm->srcu);
++      lockdep_assert_held(&kvm->srcu);
+       bus = srcu_dereference(kvm->buses[bus_idx], &kvm->srcu);
+       if (!bus)
+-              goto out_unlock;
++              return NULL;
+       dev_idx = kvm_io_bus_get_first_dev(bus, addr, 1);
+       if (dev_idx < 0)
+-              goto out_unlock;
++              return NULL;
+-      iodev = bus->range[dev_idx].dev;
+-
+-out_unlock:
+-      srcu_read_unlock(&kvm->srcu, srcu_idx);
+-
+-      return iodev;
++      return bus->range[dev_idx].dev;
+ }
+ EXPORT_SYMBOL_GPL(kvm_io_bus_get_dev);
diff --git a/queue-6.12/mm-damon-core-always-put-unsuccessfully-committed-target-pids.patch b/queue-6.12/mm-damon-core-always-put-unsuccessfully-committed-target-pids.patch
new file mode 100644 (file)
index 0000000..fae5a64
--- /dev/null
@@ -0,0 +1,153 @@
+From 6a66c557a2ab2609575bafd15e093669c05f9711 Mon Sep 17 00:00:00 2001
+From: SeongJae Park <sj@kernel.org>
+Date: Thu, 4 Jun 2026 18:38:48 -0700
+Subject: mm/damon/core: always put unsuccessfully committed target pids
+
+From: SeongJae Park <sj@kernel.org>
+
+commit 6a66c557a2ab2609575bafd15e093669c05f9711 upstream.
+
+damon_commit_target() puts and gets the destination and the source target
+pids.  It puts the destination target pid because it will be overwritten
+by the source target pid.  It gets the source pid because the caller is
+supposed to eventually put the pids.  In more detail, the caller will call
+damon_destroy_ctx() after damon_commit_ctx() to destroy the entire source
+context.  And in this case, [f]vaddr operation set's cleanup_target()
+callback will put the pids.
+
+The commit operation is made at the context level.  The operation can fail
+in multiple places including in the middle and after the targets commit
+operations.  For any such failures, immediately the error is returned to
+the damon_commit_ctx() caller.  If some or all of the source target pids
+were committed to the destination during the unsuccessful context commit
+attempt, those pids should be put twice.
+
+The source context will do the put operations using the above explained
+routine.  However, let's suppose the destination context was not
+originally using [f]vaddr operation set and the commit failed before the
+ops of the source context is committed.  The destination does not have the
+cleanup_target() ops callback, so it cannot put the pids via the
+damon_destroy_ctx().
+
+As a result, the pids are leaked.  The issue in the real world would be
+not very common.  The commit feature is for changing parameters of running
+DAMON context while inheriting internal status like the monitoring
+results.  The monitoring results of a physical address range ain't have
+things that are beneficial to be inherited to a virtual address ranges
+monitoring.  So the problem-causing DAMON control would be not very common
+in the real world.  That said, it is a supported feature.  And
+damon_commit_target() failure due to memory allocation is relatively
+realistic [1] if there are a huge number of target regions.
+
+Fix by putting the pids in the commit operation in case of the failures.
+
+The issue was discovered [2] by Sashiko.
+
+Link: https://lore.kernel.org/20260605013849.83750-1-sj@kernel.org
+Link: https://lore.kernel.org/20260603112306.58490-1-akinobu.mita@gmail.com [1]
+Link: https://lore.kernel.org/20260320020056.835-1-sj@kernel.org [2]
+Fixes: 83dc7bbaecae ("mm/damon/sysfs: use damon_commit_ctx()")
+Signed-off-by: SeongJae Park <sj@kernel.org>
+Cc: <stable@vger.kernel.org> # 6.11.x
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ mm/damon/core.c |   49 +++++++++++++++++++++++++++++++++++++++++++------
+ 1 file changed, 43 insertions(+), 6 deletions(-)
+
+--- a/mm/damon/core.c
++++ b/mm/damon/core.c
+@@ -938,10 +938,36 @@ static int damon_commit_target(
+       return 0;
+ }
++/*
++ * damon_revert_target_commits() - revert unsuccessful target commits.
++ * @dst:      Commit destination context
++ * @failed:   Commit failed destination target
++ * @src:      Commit source context
++ *
++ * Revert target states that changed by damon_commit_target(), and cannot be
++ * cleaned up by the destination context's ops.cleanup_target().
++ */
++static void damon_revert_target_commits(struct damon_ctx *dst,
++              struct damon_target *failed, struct damon_ctx *src)
++{
++      struct damon_target *target;
++
++      if (!damon_target_has_pid(src))
++              return;
++      if (damon_target_has_pid(dst))
++              return;
++      damon_for_each_target(target, dst) {
++              if (target == failed)
++                      return;
++              put_pid(target->pid);
++      }
++}
++
+ static int damon_commit_targets(
+               struct damon_ctx *dst, struct damon_ctx *src)
+ {
+       struct damon_target *dst_target, *next, *src_target, *new_target;
++      struct damon_target *failed;
+       int i = 0, j = 0, err;
+       damon_for_each_target_safe(dst_target, next, dst) {
+@@ -950,8 +976,10 @@ static int damon_commit_targets(
+                       err = damon_commit_target(
+                                       dst_target, damon_target_has_pid(dst),
+                                       src_target, damon_target_has_pid(src));
+-                      if (err)
+-                              return err;
++                      if (err) {
++                              failed = dst_target;
++                              goto out;
++                      }
+               } else {
+                       if (damon_target_has_pid(dst))
+                               put_pid(dst_target->pid);
+@@ -959,21 +987,28 @@ static int damon_commit_targets(
+               }
+       }
++      failed = NULL;
+       damon_for_each_target_safe(src_target, next, src) {
+               if (j++ < i)
+                       continue;
+               new_target = damon_new_target();
+-              if (!new_target)
+-                      return -ENOMEM;
++              if (!new_target) {
++                      err = -ENOMEM;
++                      goto out;
++              }
+               err = damon_commit_target(new_target, false,
+                               src_target, damon_target_has_pid(src));
+               if (err) {
+                       damon_destroy_target(new_target);
+-                      return err;
++                      goto out;
+               }
+               damon_add_target(dst, new_target);
+       }
+       return 0;
++
++out:
++      damon_revert_target_commits(dst, failed, src);
++      return err;
+ }
+ /**
+@@ -1007,8 +1042,10 @@ int damon_commit_ctx(struct damon_ctx *d
+        *    committing require putting pids).
+        */
+       err = damon_set_attrs(dst, &src->attrs);
+-      if (err)
++      if (err) {
++              damon_revert_target_commits(dst, NULL, src);
+               return err;
++      }
+       dst->ops = src->ops;
+       return 0;
diff --git a/queue-6.12/perf-x86-amd-brs-fix-kernel-address-leakage.patch b/queue-6.12/perf-x86-amd-brs-fix-kernel-address-leakage.patch
new file mode 100644 (file)
index 0000000..cf1aca6
--- /dev/null
@@ -0,0 +1,87 @@
+From 47915e855fb38b42133e31ba917d99565f862154 Mon Sep 17 00:00:00 2001
+From: Sandipan Das <sandipan.das@amd.com>
+Date: Fri, 10 Jul 2026 22:04:49 +0530
+Subject: perf/x86/amd/brs: Fix kernel address leakage
+
+From: Sandipan Das <sandipan.das@amd.com>
+
+commit 47915e855fb38b42133e31ba917d99565f862154 upstream.
+
+A user-only branch stack can contain branches that originate from
+the kernel. As a result, kernel addresses are exposed to user space
+even when PERF_SAMPLE_BRANCH_USER is requested. On AMD processors
+supporting X86_FEATURE_BRS (Zen 3 only), perf can still report entries
+such as SYSRET/interrupt returns for which the branch-from addresses
+are in the kernel.
+
+E.g.
+
+  $ perf record -j any,u -c 4000 -e branch-brs -o - -- \
+        perf bench syscall basic --loop 1000 | \
+        perf script -i - -F brstack|tr ' ' '\n'| \
+        grep -E '0x[89a-f][0-9a-f]{15}'
+
+  ...
+  0xffffffff810001c4/0x72e2e32955eb/-/-/-/0//-
+  0xffffffff810001c4/0x72e2d94a9821/-/-/-/0//-
+  0xffffffff810001c4/0x72e2d94ffa1b/-/-/-/0//-
+  ...
+
+BRS provides no hardware branch filtering, so privilege level
+filtering is performed entirely in software. However, amd_brs_match_plm()
+only validates the branch-to address against the requested privilege
+levels. For branches from the kernel to user space, the branch-from
+address is left unchecked and is leaked. Extend the software filter to
+also validate the branch-from address, so that any branch record whose
+branch-from address is in the kernel is dropped when
+PERF_SAMPLE_BRANCH_USER is requested.
+
+Fixes: 8910075d61a3 ("perf/x86/amd: Enable branch sampling priv level filtering")
+Reported-by: Sashiko <sashiko-bot@kernel.org>
+Signed-off-by: Sandipan Das <sandipan.das@amd.com>
+Signed-off-by: Ingo Molnar <mingo@kernel.org>
+Cc: stable@vger.kernel.org
+Cc: Peter Zijlstra <peterz@infradead.org>
+Cc: Stephane Eranian <eranian@google.com>
+Link: https://patch.msgid.link/f05931c4f89a146c364bd5dc6b8170b1ac611c65.1783701239.git.sandipan.das@amd.com
+Closes: https://lore.kernel.org/all/20260710110235.F3FD81F000E9@smtp.kernel.org/
+[sandipan: backport to linux-6.6.y]
+Signed-off-by: Sandipan Das <sandipan.das@amd.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/x86/events/amd/brs.c |   10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+--- a/arch/x86/events/amd/brs.c
++++ b/arch/x86/events/amd/brs.c
+@@ -259,13 +259,13 @@ void amd_brs_disable_all(void)
+               amd_brs_disable();
+ }
+-static bool amd_brs_match_plm(struct perf_event *event, u64 to)
++static bool amd_brs_match_plm(struct perf_event *event, u64 from, u64 to)
+ {
+       int type = event->attr.branch_sample_type;
+       int plm_k = PERF_SAMPLE_BRANCH_KERNEL | PERF_SAMPLE_BRANCH_HV;
+       int plm_u = PERF_SAMPLE_BRANCH_USER;
+-      if (!(type & plm_k) && kernel_ip(to))
++      if (!(type & plm_k) && (kernel_ip(to) || kernel_ip(from)))
+               return 0;
+       if (!(type & plm_u) && !kernel_ip(to))
+@@ -338,11 +338,11 @@ void amd_brs_drain(void)
+                */
+               to = (u64)(((s64)to << shift) >> shift);
+-              if (!amd_brs_match_plm(event, to))
+-                      continue;
+-
+               rdmsrl(brs_from(brs_idx), from);
++              if (!amd_brs_match_plm(event, from, to))
++                      continue;
++
+               perf_clear_branch_entry_bitfields(br+nr);
+               br[nr].from = from;
diff --git a/queue-6.12/selftests-fs-statmount-build-with-tools-include-dir.patch b/queue-6.12/selftests-fs-statmount-build-with-tools-include-dir.patch
new file mode 100644 (file)
index 0000000..bce27f8
--- /dev/null
@@ -0,0 +1,372 @@
+From b13fb4ee46472d7f7fc3e2172c08c06ed8b3f31c Mon Sep 17 00:00:00 2001
+From: Amir Goldstein <amir73il@gmail.com>
+Date: Fri, 9 May 2025 15:32:34 +0200
+Subject: selftests/fs/statmount: build with tools include dir
+
+From: Amir Goldstein <amir73il@gmail.com>
+
+commit b13fb4ee46472d7f7fc3e2172c08c06ed8b3f31c upstream.
+
+Copy the required headers files (mount.h, nsfs.h) to the tools
+include dir and define the statmount/listmount syscall numbers
+to decouple dependency with headers_install for the common cases.
+
+Reviewed-by: John Hubbard <jhubbard@nvidia.com>
+Signed-off-by: Amir Goldstein <amir73il@gmail.com>
+Link: https://lore.kernel.org/20250509133240.529330-3-amir73il@gmail.com
+Reviewed-by: Christian Brauner <brauner@kernel.org>
+Signed-off-by: Christian Brauner <brauner@kernel.org>
+[florian: resolved conflict in statmount/Makefile]
+Signed-off-by: Florian Fainelli <florian.fainelli@broadcom.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ tools/include/uapi/linux/mount.h                          |  235 ++++++++++++++
+ tools/include/uapi/linux/nsfs.h                           |   45 ++
+ tools/testing/selftests/filesystems/statmount/Makefile    |    3 
+ tools/testing/selftests/filesystems/statmount/statmount.h |   36 ++
+ 4 files changed, 318 insertions(+), 1 deletion(-)
+ create mode 100644 tools/include/uapi/linux/mount.h
+ create mode 100644 tools/include/uapi/linux/nsfs.h
+
+--- /dev/null
++++ b/tools/include/uapi/linux/mount.h
+@@ -0,0 +1,235 @@
++#ifndef _UAPI_LINUX_MOUNT_H
++#define _UAPI_LINUX_MOUNT_H
++
++#include <linux/types.h>
++
++/*
++ * These are the fs-independent mount-flags: up to 32 flags are supported
++ *
++ * Usage of these is restricted within the kernel to core mount(2) code and
++ * callers of sys_mount() only.  Filesystems should be using the SB_*
++ * equivalent instead.
++ */
++#define MS_RDONLY      1      /* Mount read-only */
++#define MS_NOSUID      2      /* Ignore suid and sgid bits */
++#define MS_NODEV       4      /* Disallow access to device special files */
++#define MS_NOEXEC      8      /* Disallow program execution */
++#define MS_SYNCHRONOUS        16      /* Writes are synced at once */
++#define MS_REMOUNT    32      /* Alter flags of a mounted FS */
++#define MS_MANDLOCK   64      /* Allow mandatory locks on an FS */
++#define MS_DIRSYNC    128     /* Directory modifications are synchronous */
++#define MS_NOSYMFOLLOW        256     /* Do not follow symlinks */
++#define MS_NOATIME    1024    /* Do not update access times. */
++#define MS_NODIRATIME 2048    /* Do not update directory access times */
++#define MS_BIND               4096
++#define MS_MOVE               8192
++#define MS_REC                16384
++#define MS_VERBOSE    32768   /* War is peace. Verbosity is silence.
++                                 MS_VERBOSE is deprecated. */
++#define MS_SILENT     32768
++#define MS_POSIXACL   (1<<16) /* VFS does not apply the umask */
++#define MS_UNBINDABLE (1<<17) /* change to unbindable */
++#define MS_PRIVATE    (1<<18) /* change to private */
++#define MS_SLAVE      (1<<19) /* change to slave */
++#define MS_SHARED     (1<<20) /* change to shared */
++#define MS_RELATIME   (1<<21) /* Update atime relative to mtime/ctime. */
++#define MS_KERNMOUNT  (1<<22) /* this is a kern_mount call */
++#define MS_I_VERSION  (1<<23) /* Update inode I_version field */
++#define MS_STRICTATIME        (1<<24) /* Always perform atime updates */
++#define MS_LAZYTIME   (1<<25) /* Update the on-disk [acm]times lazily */
++
++/* These sb flags are internal to the kernel */
++#define MS_SUBMOUNT     (1<<26)
++#define MS_NOREMOTELOCK       (1<<27)
++#define MS_NOSEC      (1<<28)
++#define MS_BORN               (1<<29)
++#define MS_ACTIVE     (1<<30)
++#define MS_NOUSER     (1<<31)
++
++/*
++ * Superblock flags that can be altered by MS_REMOUNT
++ */
++#define MS_RMT_MASK   (MS_RDONLY|MS_SYNCHRONOUS|MS_MANDLOCK|MS_I_VERSION|\
++                       MS_LAZYTIME)
++
++/*
++ * Old magic mount flag and mask
++ */
++#define MS_MGC_VAL 0xC0ED0000
++#define MS_MGC_MSK 0xffff0000
++
++/*
++ * open_tree() flags.
++ */
++#define OPEN_TREE_CLONE               1               /* Clone the target tree and attach the clone */
++#define OPEN_TREE_CLOEXEC     O_CLOEXEC       /* Close the file on execve() */
++
++/*
++ * move_mount() flags.
++ */
++#define MOVE_MOUNT_F_SYMLINKS         0x00000001 /* Follow symlinks on from path */
++#define MOVE_MOUNT_F_AUTOMOUNTS               0x00000002 /* Follow automounts on from path */
++#define MOVE_MOUNT_F_EMPTY_PATH               0x00000004 /* Empty from path permitted */
++#define MOVE_MOUNT_T_SYMLINKS         0x00000010 /* Follow symlinks on to path */
++#define MOVE_MOUNT_T_AUTOMOUNTS               0x00000020 /* Follow automounts on to path */
++#define MOVE_MOUNT_T_EMPTY_PATH               0x00000040 /* Empty to path permitted */
++#define MOVE_MOUNT_SET_GROUP          0x00000100 /* Set sharing group instead */
++#define MOVE_MOUNT_BENEATH            0x00000200 /* Mount beneath top mount */
++#define MOVE_MOUNT__MASK              0x00000377
++
++/*
++ * fsopen() flags.
++ */
++#define FSOPEN_CLOEXEC                0x00000001
++
++/*
++ * fspick() flags.
++ */
++#define FSPICK_CLOEXEC                0x00000001
++#define FSPICK_SYMLINK_NOFOLLOW       0x00000002
++#define FSPICK_NO_AUTOMOUNT   0x00000004
++#define FSPICK_EMPTY_PATH     0x00000008
++
++/*
++ * The type of fsconfig() call made.
++ */
++enum fsconfig_command {
++      FSCONFIG_SET_FLAG       = 0,    /* Set parameter, supplying no value */
++      FSCONFIG_SET_STRING     = 1,    /* Set parameter, supplying a string value */
++      FSCONFIG_SET_BINARY     = 2,    /* Set parameter, supplying a binary blob value */
++      FSCONFIG_SET_PATH       = 3,    /* Set parameter, supplying an object by path */
++      FSCONFIG_SET_PATH_EMPTY = 4,    /* Set parameter, supplying an object by (empty) path */
++      FSCONFIG_SET_FD         = 5,    /* Set parameter, supplying an object by fd */
++      FSCONFIG_CMD_CREATE     = 6,    /* Create new or reuse existing superblock */
++      FSCONFIG_CMD_RECONFIGURE = 7,   /* Invoke superblock reconfiguration */
++      FSCONFIG_CMD_CREATE_EXCL = 8,   /* Create new superblock, fail if reusing existing superblock */
++};
++
++/*
++ * fsmount() flags.
++ */
++#define FSMOUNT_CLOEXEC               0x00000001
++
++/*
++ * Mount attributes.
++ */
++#define MOUNT_ATTR_RDONLY     0x00000001 /* Mount read-only */
++#define MOUNT_ATTR_NOSUID     0x00000002 /* Ignore suid and sgid bits */
++#define MOUNT_ATTR_NODEV      0x00000004 /* Disallow access to device special files */
++#define MOUNT_ATTR_NOEXEC     0x00000008 /* Disallow program execution */
++#define MOUNT_ATTR__ATIME     0x00000070 /* Setting on how atime should be updated */
++#define MOUNT_ATTR_RELATIME   0x00000000 /* - Update atime relative to mtime/ctime. */
++#define MOUNT_ATTR_NOATIME    0x00000010 /* - Do not update access times. */
++#define MOUNT_ATTR_STRICTATIME        0x00000020 /* - Always perform atime updates */
++#define MOUNT_ATTR_NODIRATIME 0x00000080 /* Do not update directory access times */
++#define MOUNT_ATTR_IDMAP      0x00100000 /* Idmap mount to @userns_fd in struct mount_attr. */
++#define MOUNT_ATTR_NOSYMFOLLOW        0x00200000 /* Do not follow symlinks */
++
++/*
++ * mount_setattr()
++ */
++struct mount_attr {
++      __u64 attr_set;
++      __u64 attr_clr;
++      __u64 propagation;
++      __u64 userns_fd;
++};
++
++/* List of all mount_attr versions. */
++#define MOUNT_ATTR_SIZE_VER0  32 /* sizeof first published struct */
++
++
++/*
++ * Structure for getting mount/superblock/filesystem info with statmount(2).
++ *
++ * The interface is similar to statx(2): individual fields or groups can be
++ * selected with the @mask argument of statmount().  Kernel will set the @mask
++ * field according to the supported fields.
++ *
++ * If string fields are selected, then the caller needs to pass a buffer that
++ * has space after the fixed part of the structure.  Nul terminated strings are
++ * copied there and offsets relative to @str are stored in the relevant fields.
++ * If the buffer is too small, then EOVERFLOW is returned.  The actually used
++ * size is returned in @size.
++ */
++struct statmount {
++      __u32 size;             /* Total size, including strings */
++      __u32 mnt_opts;         /* [str] Options (comma separated, escaped) */
++      __u64 mask;             /* What results were written */
++      __u32 sb_dev_major;     /* Device ID */
++      __u32 sb_dev_minor;
++      __u64 sb_magic;         /* ..._SUPER_MAGIC */
++      __u32 sb_flags;         /* SB_{RDONLY,SYNCHRONOUS,DIRSYNC,LAZYTIME} */
++      __u32 fs_type;          /* [str] Filesystem type */
++      __u64 mnt_id;           /* Unique ID of mount */
++      __u64 mnt_parent_id;    /* Unique ID of parent (for root == mnt_id) */
++      __u32 mnt_id_old;       /* Reused IDs used in proc/.../mountinfo */
++      __u32 mnt_parent_id_old;
++      __u64 mnt_attr;         /* MOUNT_ATTR_... */
++      __u64 mnt_propagation;  /* MS_{SHARED,SLAVE,PRIVATE,UNBINDABLE} */
++      __u64 mnt_peer_group;   /* ID of shared peer group */
++      __u64 mnt_master;       /* Mount receives propagation from this ID */
++      __u64 propagate_from;   /* Propagation from in current namespace */
++      __u32 mnt_root;         /* [str] Root of mount relative to root of fs */
++      __u32 mnt_point;        /* [str] Mountpoint relative to current root */
++      __u64 mnt_ns_id;        /* ID of the mount namespace */
++      __u32 fs_subtype;       /* [str] Subtype of fs_type (if any) */
++      __u32 sb_source;        /* [str] Source string of the mount */
++      __u32 opt_num;          /* Number of fs options */
++      __u32 opt_array;        /* [str] Array of nul terminated fs options */
++      __u32 opt_sec_num;      /* Number of security options */
++      __u32 opt_sec_array;    /* [str] Array of nul terminated security options */
++      __u64 supported_mask;   /* Mask flags that this kernel supports */
++      __u32 mnt_uidmap_num;   /* Number of uid mappings */
++      __u32 mnt_uidmap;       /* [str] Array of uid mappings (as seen from callers namespace) */
++      __u32 mnt_gidmap_num;   /* Number of gid mappings */
++      __u32 mnt_gidmap;       /* [str] Array of gid mappings (as seen from callers namespace) */
++      __u64 __spare2[43];
++      char str[];             /* Variable size part containing strings */
++};
++
++/*
++ * Structure for passing mount ID and miscellaneous parameters to statmount(2)
++ * and listmount(2).
++ *
++ * For statmount(2) @param represents the request mask.
++ * For listmount(2) @param represents the last listed mount id (or zero).
++ */
++struct mnt_id_req {
++      __u32 size;
++      __u32 spare;
++      __u64 mnt_id;
++      __u64 param;
++      __u64 mnt_ns_id;
++};
++
++/* List of all mnt_id_req versions. */
++#define MNT_ID_REQ_SIZE_VER0  24 /* sizeof first published struct */
++#define MNT_ID_REQ_SIZE_VER1  32 /* sizeof second published struct */
++
++/*
++ * @mask bits for statmount(2)
++ */
++#define STATMOUNT_SB_BASIC            0x00000001U     /* Want/got sb_... */
++#define STATMOUNT_MNT_BASIC           0x00000002U     /* Want/got mnt_... */
++#define STATMOUNT_PROPAGATE_FROM      0x00000004U     /* Want/got propagate_from */
++#define STATMOUNT_MNT_ROOT            0x00000008U     /* Want/got mnt_root  */
++#define STATMOUNT_MNT_POINT           0x00000010U     /* Want/got mnt_point */
++#define STATMOUNT_FS_TYPE             0x00000020U     /* Want/got fs_type */
++#define STATMOUNT_MNT_NS_ID           0x00000040U     /* Want/got mnt_ns_id */
++#define STATMOUNT_MNT_OPTS            0x00000080U     /* Want/got mnt_opts */
++#define STATMOUNT_FS_SUBTYPE          0x00000100U     /* Want/got fs_subtype */
++#define STATMOUNT_SB_SOURCE           0x00000200U     /* Want/got sb_source */
++#define STATMOUNT_OPT_ARRAY           0x00000400U     /* Want/got opt_... */
++#define STATMOUNT_OPT_SEC_ARRAY               0x00000800U     /* Want/got opt_sec... */
++#define STATMOUNT_SUPPORTED_MASK      0x00001000U     /* Want/got supported mask flags */
++#define STATMOUNT_MNT_UIDMAP          0x00002000U     /* Want/got uidmap... */
++#define STATMOUNT_MNT_GIDMAP          0x00004000U     /* Want/got gidmap... */
++
++/*
++ * Special @mnt_id values that can be passed to listmount
++ */
++#define LSMT_ROOT             0xffffffffffffffff      /* root mount */
++#define LISTMOUNT_REVERSE     (1 << 0) /* List later mounts first */
++
++#endif /* _UAPI_LINUX_MOUNT_H */
+--- /dev/null
++++ b/tools/include/uapi/linux/nsfs.h
+@@ -0,0 +1,45 @@
++/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
++#ifndef __LINUX_NSFS_H
++#define __LINUX_NSFS_H
++
++#include <linux/ioctl.h>
++#include <linux/types.h>
++
++#define NSIO  0xb7
++
++/* Returns a file descriptor that refers to an owning user namespace */
++#define NS_GET_USERNS         _IO(NSIO, 0x1)
++/* Returns a file descriptor that refers to a parent namespace */
++#define NS_GET_PARENT         _IO(NSIO, 0x2)
++/* Returns the type of namespace (CLONE_NEW* value) referred to by
++   file descriptor */
++#define NS_GET_NSTYPE         _IO(NSIO, 0x3)
++/* Get owner UID (in the caller's user namespace) for a user namespace */
++#define NS_GET_OWNER_UID      _IO(NSIO, 0x4)
++/* Get the id for a mount namespace */
++#define NS_GET_MNTNS_ID               _IOR(NSIO, 0x5, __u64)
++/* Translate pid from target pid namespace into the caller's pid namespace. */
++#define NS_GET_PID_FROM_PIDNS _IOR(NSIO, 0x6, int)
++/* Return thread-group leader id of pid in the callers pid namespace. */
++#define NS_GET_TGID_FROM_PIDNS        _IOR(NSIO, 0x7, int)
++/* Translate pid from caller's pid namespace into a target pid namespace. */
++#define NS_GET_PID_IN_PIDNS   _IOR(NSIO, 0x8, int)
++/* Return thread-group leader id of pid in the target pid namespace. */
++#define NS_GET_TGID_IN_PIDNS  _IOR(NSIO, 0x9, int)
++
++struct mnt_ns_info {
++      __u32 size;
++      __u32 nr_mounts;
++      __u64 mnt_ns_id;
++};
++
++#define MNT_NS_INFO_SIZE_VER0 16 /* size of first published struct */
++
++/* Get information about namespace. */
++#define NS_MNT_GET_INFO               _IOR(NSIO, 10, struct mnt_ns_info)
++/* Get next namespace. */
++#define NS_MNT_GET_NEXT               _IOR(NSIO, 11, struct mnt_ns_info)
++/* Get previous namespace. */
++#define NS_MNT_GET_PREV               _IOR(NSIO, 12, struct mnt_ns_info)
++
++#endif /* __LINUX_NSFS_H */
+--- a/tools/testing/selftests/filesystems/statmount/Makefile
++++ b/tools/testing/selftests/filesystems/statmount/Makefile
+@@ -1,6 +1,7 @@
+ # SPDX-License-Identifier: GPL-2.0-or-later
+-CFLAGS += -Wall -O2 -g $(KHDR_INCLUDES)
++CFLAGS += -Wall -O2 -g $(KHDR_INCLUDES) $(TOOLS_INCLUDES)
++
+ TEST_GEN_PROGS := statmount_test statmount_test_ns
+ include ../../lib.mk
+--- a/tools/testing/selftests/filesystems/statmount/statmount.h
++++ b/tools/testing/selftests/filesystems/statmount/statmount.h
+@@ -7,6 +7,42 @@
+ #include <linux/mount.h>
+ #include <asm/unistd.h>
++#ifndef __NR_statmount
++      #if defined __alpha__
++              #define __NR_statmount 567
++      #elif defined _MIPS_SIM
++              #if _MIPS_SIM == _MIPS_SIM_ABI32        /* o32 */
++                      #define __NR_statmount 4457
++              #endif
++              #if _MIPS_SIM == _MIPS_SIM_NABI32       /* n32 */
++                      #define __NR_statmount 6457
++              #endif
++              #if _MIPS_SIM == _MIPS_SIM_ABI64        /* n64 */
++                      #define __NR_statmount 5457
++              #endif
++      #else
++              #define __NR_statmount 457
++      #endif
++#endif
++
++#ifndef __NR_listmount
++      #if defined __alpha__
++              #define __NR_listmount 568
++      #elif defined _MIPS_SIM
++              #if _MIPS_SIM == _MIPS_SIM_ABI32        /* o32 */
++                      #define __NR_listmount 4458
++              #endif
++              #if _MIPS_SIM == _MIPS_SIM_NABI32       /* n32 */
++                      #define __NR_listmount 6458
++              #endif
++              #if _MIPS_SIM == _MIPS_SIM_ABI64        /* n64 */
++                      #define __NR_listmount 5458
++              #endif
++      #else
++              #define __NR_listmount 458
++      #endif
++#endif
++
+ static inline int statmount(uint64_t mnt_id, uint64_t mnt_ns_id, uint64_t mask,
+                           struct statmount *buf, size_t bufsize,
+                           unsigned int flags)
index bd1ec41caa8d4bfb74dadadebe12471ec5b031aa..3e0b76193859b7e953466e735c5072b875d9e60d 100644 (file)
@@ -1231,3 +1231,17 @@ exfat-fix-incorrect-directory-checksum-after-rename-to-shorter-name.patch
 exfat-preserve-benign-secondary-entries-during-rename-and-move.patch
 btrfs-fix-false-io-failure-after-falling-back-to-buffered-write.patch
 btrfs-fix-incorrect-buffered-io-fallback-for-append-direct-writes.patch
+slab-introduce-kmalloc_obj-and-family.patch
+slab-introduce-kmalloc_flex-and-family.patch
+add-default_gfp-helper-macro-and-use-it-in-the-new-alloc_obj-helpers.patch
+default_gfp-avoid-using-the-newfangled-__va_opt__-trick.patch
+slab-recognize-gfp-parameter-as-optional-in-kernel-doc.patch
+fscrypt-fix-key-setup-in-edge-case-with-multiple-data-unit-sizes.patch
+fscrypt-replace-mk_users-keyring-with-simple-list.patch
+selftests-fs-statmount-build-with-tools-include-dir.patch
+mm-damon-core-always-put-unsuccessfully-committed-target-pids.patch
+kvm-move-kvm_io_bus_get_dev-locking-responsibilities-to-callers.patch
+kvm-arm64-ensure-level-is-always-initialized-when-relaxing-perms.patch
+kvm-arm64-fix-propagation-of-tlbi-level-in-kvm_pgtable_stage2_relax_perms.patch
+bpf-reject-bpf_map_type_inode_storage-creation-if-bpf-lsm-is-uninitialized.patch
+perf-x86-amd-brs-fix-kernel-address-leakage.patch
diff --git a/queue-6.12/slab-introduce-kmalloc_flex-and-family.patch b/queue-6.12/slab-introduce-kmalloc_flex-and-family.patch
new file mode 100644 (file)
index 0000000..c88baf2
--- /dev/null
@@ -0,0 +1,173 @@
+From stable+bounces-276925-greg=kroah.com@vger.kernel.org Fri Jul 17 06:47:13 2026
+From: Eric Biggers <ebiggers@kernel.org>
+Date: Thu, 16 Jul 2026 21:42:58 -0700
+Subject: slab: Introduce kmalloc_flex() and family
+To: stable@vger.kernel.org
+Cc: linux-hardening@vger.kernel.org, linux-fscrypt@vger.kernel.org, linux-kernel@vger.kernel.org, Kees Cook <kees@kernel.org>, Vlastimil Babka <vbabka@suse.cz>, Eric Biggers <ebiggers@kernel.org>
+Message-ID: <20260717044303.425265-3-ebiggers@kernel.org>
+
+From: Kees Cook <kees@kernel.org>
+
+commit e4c8b46b924eb8de66c6f0accc9cdd0c2e8fa23b upstream.
+
+As done for kmalloc_obj*(), introduce a type-aware allocator for flexible
+arrays, which may also have "counted_by" annotations:
+
+       ptr = kmalloc(struct_size(ptr, flex_member, count), gfp);
+
+becomes:
+
+       ptr = kmalloc_flex(*ptr, flex_member, count, gfp);
+
+The internal use of __flex_counter() allows for automatically setting
+the counter member of a struct's flexible array member when it has
+been annotated with __counted_by(), avoiding any missed early size
+initializations while __counted_by() annotations are added to the
+kernel. Additionally, this also checks for "too large" allocations based
+on the type size of the counter variable. For example:
+
+       if (count > type_max(ptr->flex_counter))
+               fail...;
+       size = struct_size(ptr, flex_member, count);
+       ptr = kmalloc(size, gfp);
+       if (!ptr)
+               fail...;
+       ptr->flex_counter = count;
+
+becomes (n.b. unchanged from earlier example):
+
+       ptr = kmalloc_flex(*ptr, flex_member, count, gfp);
+       if (!ptr)
+               fail...;
+       ptr->flex_counter = count;
+
+Note that manual initialization of the flexible array counter is still
+required (at some point) after allocation as not all compiler versions
+support the __counted_by annotation yet. But doing it internally makes
+sure they cannot be missed when __counted_by _is_ available, meaning
+that the bounds checker will not trip due to the lack of "early enough"
+initializations that used to work before enabling the stricter bounds
+checking. For example:
+
+       ptr = kmalloc_flex(*ptr, flex_member, count, gfp);
+       fill(ptr->flex, count);
+       ptr->flex_count = count;
+
+This works correctly before adding a __counted_by annotation (since
+nothing is checking ptr->flex accesses against ptr->flex_count). After
+adding the annotation, the bounds sanitizer would trip during fill()
+because ptr->flex_count wasn't set yet. But with kmalloc_flex() setting
+ptr->flex_count internally at allocation time, the existing code works
+without needing to move the ptr->flex_count assignment before the call
+to fill(). (This has been a stumbling block for __counted_by adoption.)
+
+Link: https://patch.msgid.link/20251203233036.3212363-4-kees@kernel.org
+Acked-by: Vlastimil Babka <vbabka@suse.cz>
+Signed-off-by: Kees Cook <kees@kernel.org>
+[Backport-notes: Removed the actual flex counter handling.  That's a new
+ feature, which isn't necessary for just adding the new allocation APIs
+ to get backports to apply cleanly.  Also, the allocation-time overflow
+ check in the upstream commit was reverted upstream.]
+Signed-off-by: Eric Biggers <ebiggers@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ Documentation/process/deprecated.rst |    7 +++++
+ include/linux/slab.h                 |   42 +++++++++++++++++++++++++++++++++++
+ 2 files changed, 49 insertions(+)
+
+--- a/Documentation/process/deprecated.rst
++++ b/Documentation/process/deprecated.rst
+@@ -387,6 +387,7 @@ allocations. For example, these open cod
+       ptr = kzalloc(sizeof(*ptr), gfp);
+       ptr = kmalloc_array(count, sizeof(*ptr), gfp);
+       ptr = kcalloc(count, sizeof(*ptr), gfp);
++      ptr = kmalloc(struct_size(ptr, flex_member, count), gfp);
+       ptr = kmalloc(sizeof(struct foo, gfp);
+ become, respectively::
+@@ -395,4 +396,10 @@ become, respectively::
+       ptr = kzalloc_obj(*ptr, gfp);
+       ptr = kmalloc_objs(*ptr, count, gfp);
+       ptr = kzalloc_objs(*ptr, count, gfp);
++      ptr = kmalloc_flex(*ptr, flex_member, count, gfp);
+       __auto_type ptr = kmalloc_obj(struct foo, gfp);
++
++If `ptr->flex_member` is annotated with __counted_by(), the allocation
++will automatically fail if `count` is larger than the maximum
++representable value that can be stored in the counter member associated
++with `flex_member`.
+--- a/include/linux/slab.h
++++ b/include/linux/slab.h
+@@ -901,6 +901,27 @@ static __always_inline __alloc_size(1) v
+ })
+ /**
++ * __alloc_flex - Allocate an object that has a trailing flexible array
++ * @KMALLOC: kmalloc wrapper function to use for allocation.
++ * @GFP: GFP flags for the allocation.
++ * @TYPE: type of structure to allocate space for.
++ * @FAM: The name of the flexible array member of @TYPE structure.
++ * @COUNT: how many @FAM elements to allocate space for.
++ *
++ * Returns: Newly allocated pointer to @TYPE with @COUNT-many trailing
++ * @FAM elements, or NULL on failure or if @COUNT cannot be represented
++ * by the member of @TYPE that counts the @FAM elements (annotated via
++ * __counted_by()).
++ */
++#define __alloc_flex(KMALLOC, GFP, TYPE, FAM, COUNT)                  \
++({                                                                    \
++      const size_t __count = (COUNT);                                 \
++      const size_t __obj_size = struct_size_t(TYPE, FAM, __count);    \
++      TYPE *__obj_ptr = KMALLOC(__obj_size, GFP);                     \
++      __obj_ptr;                                                      \
++})
++
++/**
+  * kmalloc_obj - Allocate a single instance of the given type
+  * @VAR_OR_TYPE: Variable or type to allocate.
+  * @GFP: GFP flags for the allocation.
+@@ -923,23 +944,44 @@ static __always_inline __alloc_size(1) v
+ #define kmalloc_objs(VAR_OR_TYPE, COUNT, GFP)         \
+       __alloc_objs(kmalloc, GFP, typeof(VAR_OR_TYPE), COUNT)
++/**
++ * kmalloc_flex - Allocate a single instance of the given flexible structure
++ * @VAR_OR_TYPE: Variable or type to allocate (with its flex array).
++ * @FAM: The name of the flexible array member of the structure.
++ * @COUNT: How many flexible array member elements are desired.
++ * @GFP: GFP flags for the allocation.
++ *
++ * Returns: newly allocated pointer to @VAR_OR_TYPE on success, NULL on
++ * failure. If @FAM has been annotated with __counted_by(), the allocation
++ * will immediately fail if @COUNT is larger than what the type of the
++ * struct's counter variable can represent.
++ */
++#define kmalloc_flex(VAR_OR_TYPE, FAM, COUNT, GFP)    \
++      __alloc_flex(kmalloc, GFP, typeof(VAR_OR_TYPE), FAM, COUNT)
++
+ /* All kzalloc aliases for kmalloc_(obj|objs|flex). */
+ #define kzalloc_obj(P, GFP)                           \
+       __alloc_objs(kzalloc, GFP, typeof(P), 1)
+ #define kzalloc_objs(P, COUNT, GFP)                   \
+       __alloc_objs(kzalloc, GFP, typeof(P), COUNT)
++#define kzalloc_flex(P, FAM, COUNT, GFP)              \
++      __alloc_flex(kzalloc, GFP, typeof(P), FAM, COUNT)
+ /* All kvmalloc aliases for kmalloc_(obj|objs|flex). */
+ #define kvmalloc_obj(P, GFP)                          \
+       __alloc_objs(kvmalloc, GFP, typeof(P), 1)
+ #define kvmalloc_objs(P, COUNT, GFP)                  \
+       __alloc_objs(kvmalloc, GFP, typeof(P), COUNT)
++#define kvmalloc_flex(P, FAM, COUNT, GFP)             \
++      __alloc_flex(kvmalloc, GFP, typeof(P), FAM, COUNT)
+ /* All kvzalloc aliases for kmalloc_(obj|objs|flex). */
+ #define kvzalloc_obj(P, GFP)                          \
+       __alloc_objs(kvzalloc, GFP, typeof(P), 1)
+ #define kvzalloc_objs(P, COUNT, GFP)                  \
+       __alloc_objs(kvzalloc, GFP, typeof(P), COUNT)
++#define kvzalloc_flex(P, FAM, COUNT, GFP)             \
++      __alloc_flex(kvzalloc, GFP, typeof(P), FAM, COUNT)
+ #define kmem_buckets_alloc(_b, _size, _flags) \
+       alloc_hooks(__kmalloc_node_noprof(PASS_BUCKET_PARAMS(_size, _b), _flags, NUMA_NO_NODE))
diff --git a/queue-6.12/slab-introduce-kmalloc_obj-and-family.patch b/queue-6.12/slab-introduce-kmalloc_obj-and-family.patch
new file mode 100644 (file)
index 0000000..19c45cf
--- /dev/null
@@ -0,0 +1,162 @@
+From stable+bounces-276924-greg=kroah.com@vger.kernel.org Fri Jul 17 06:47:09 2026
+From: Eric Biggers <ebiggers@kernel.org>
+Date: Thu, 16 Jul 2026 21:42:57 -0700
+Subject: slab: Introduce kmalloc_obj() and family
+To: stable@vger.kernel.org
+Cc: linux-hardening@vger.kernel.org, linux-fscrypt@vger.kernel.org, linux-kernel@vger.kernel.org, Kees Cook <kees@kernel.org>, Vlastimil Babka <vbabka@suse.cz>, Eric Biggers <ebiggers@kernel.org>
+Message-ID: <20260717044303.425265-2-ebiggers@kernel.org>
+
+From: Kees Cook <kees@kernel.org>
+
+commit 2932ba8d9c99875b98c951d9d3fd6d651d35df3a upstream.
+
+Introduce type-aware kmalloc-family helpers to replace the common
+idioms for single object and arrays of objects allocation:
+
+       ptr = kmalloc(sizeof(*ptr), gfp);
+       ptr = kmalloc(sizeof(struct some_obj_name), gfp);
+       ptr = kzalloc(sizeof(*ptr), gfp);
+       ptr = kmalloc_array(count, sizeof(*ptr), gfp);
+       ptr = kcalloc(count, sizeof(*ptr), gfp);
+
+These become, respectively:
+
+       ptr = kmalloc_obj(*ptr, gfp);
+       ptr = kmalloc_obj(*ptr, gfp);
+       ptr = kzalloc_obj(*ptr, gfp);
+       ptr = kmalloc_objs(*ptr, count, gfp);
+       ptr = kzalloc_objs(*ptr, count, gfp);
+
+Beyond the other benefits outlined below, the primary ergonomic benefit
+is the elimination of needing "sizeof" nor the type name, and the
+enforcement of assignment types (they do not return "void *", but rather
+a pointer to the type of the first argument). The type name _can_ be
+used, though, in the case where an assignment is indirect (e.g. via
+"return"). This additionally allows[1] variables to be declared via
+__auto_type:
+
+       __auto_type ptr = kmalloc_obj(struct foo, gfp);
+
+Internal introspection of the allocated type now becomes possible,
+allowing for future alignment-aware choices to be made by the allocator
+and future hardening work that can be type sensitive. For example,
+adding __alignof(*ptr) as an argument to the internal allocators so that
+appropriate/efficient alignment choices can be made, or being able to
+correctly choose per-allocation offset randomization within a bucket
+that does not break alignment requirements.
+
+Link: https://lore.kernel.org/all/CAHk-=wiCOTW5UftUrAnvJkr6769D29tF7Of79gUjdQHS_TkF5A@mail.gmail.com/ [1]
+Acked-by: Vlastimil Babka <vbabka@suse.cz>
+Link: https://patch.msgid.link/20251203233036.3212363-1-kees@kernel.org
+Signed-off-by: Kees Cook <kees@kernel.org>
+Signed-off-by: Eric Biggers <ebiggers@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ Documentation/process/deprecated.rst |   24 ++++++++++++++
+ include/linux/slab.h                 |   58 +++++++++++++++++++++++++++++++++++
+ 2 files changed, 82 insertions(+)
+
+--- a/Documentation/process/deprecated.rst
++++ b/Documentation/process/deprecated.rst
+@@ -372,3 +372,27 @@ The helper must be used::
+                       DECLARE_FLEX_ARRAY(struct type2, two);
+               };
+       };
++
++Open-coded kmalloc assignments for struct objects
++-------------------------------------------------
++Performing open-coded kmalloc()-family allocation assignments prevents
++the kernel (and compiler) from being able to examine the type of the
++variable being assigned, which limits any related introspection that
++may help with alignment, wrap-around, or additional hardening. The
++kmalloc_obj()-family of macros provide this introspection, which can be
++used for the common code patterns for single, array, and flexible object
++allocations. For example, these open coded assignments::
++
++      ptr = kmalloc(sizeof(*ptr), gfp);
++      ptr = kzalloc(sizeof(*ptr), gfp);
++      ptr = kmalloc_array(count, sizeof(*ptr), gfp);
++      ptr = kcalloc(count, sizeof(*ptr), gfp);
++      ptr = kmalloc(sizeof(struct foo, gfp);
++
++become, respectively::
++
++      ptr = kmalloc_obj(*ptr, gfp);
++      ptr = kzalloc_obj(*ptr, gfp);
++      ptr = kmalloc_objs(*ptr, count, gfp);
++      ptr = kzalloc_objs(*ptr, count, gfp);
++      __auto_type ptr = kmalloc_obj(struct foo, gfp);
+--- a/include/linux/slab.h
++++ b/include/linux/slab.h
+@@ -12,6 +12,7 @@
+ #ifndef _LINUX_SLAB_H
+ #define       _LINUX_SLAB_H
++#include <linux/bug.h>
+ #include <linux/cache.h>
+ #include <linux/gfp.h>
+ #include <linux/overflow.h>
+@@ -883,6 +884,63 @@ static __always_inline __alloc_size(1) v
+ }
+ #define kmalloc(...)                          alloc_hooks(kmalloc_noprof(__VA_ARGS__))
++/**
++ * __alloc_objs - Allocate objects of a given type using
++ * @KMALLOC: which size-based kmalloc wrapper to allocate with.
++ * @GFP: GFP flags for the allocation.
++ * @TYPE: type to allocate space for.
++ * @COUNT: how many @TYPE objects to allocate.
++ *
++ * Returns: Newly allocated pointer to (first) @TYPE of @COUNT-many
++ * allocated @TYPE objects, or NULL on failure.
++ */
++#define __alloc_objs(KMALLOC, GFP, TYPE, COUNT)                               \
++({                                                                    \
++      const size_t __obj_size = size_mul(sizeof(TYPE), COUNT);        \
++      (TYPE *)KMALLOC(__obj_size, GFP);                               \
++})
++
++/**
++ * kmalloc_obj - Allocate a single instance of the given type
++ * @VAR_OR_TYPE: Variable or type to allocate.
++ * @GFP: GFP flags for the allocation.
++ *
++ * Returns: newly allocated pointer to a @VAR_OR_TYPE on success, or NULL
++ * on failure.
++ */
++#define kmalloc_obj(VAR_OR_TYPE, GFP)                 \
++      __alloc_objs(kmalloc, GFP, typeof(VAR_OR_TYPE), 1)
++
++/**
++ * kmalloc_objs - Allocate an array of the given type
++ * @VAR_OR_TYPE: Variable or type to allocate an array of.
++ * @COUNT: How many elements in the array.
++ * @GFP: GFP flags for the allocation.
++ *
++ * Returns: newly allocated pointer to array of @VAR_OR_TYPE on success,
++ * or NULL on failure.
++ */
++#define kmalloc_objs(VAR_OR_TYPE, COUNT, GFP)         \
++      __alloc_objs(kmalloc, GFP, typeof(VAR_OR_TYPE), COUNT)
++
++/* All kzalloc aliases for kmalloc_(obj|objs|flex). */
++#define kzalloc_obj(P, GFP)                           \
++      __alloc_objs(kzalloc, GFP, typeof(P), 1)
++#define kzalloc_objs(P, COUNT, GFP)                   \
++      __alloc_objs(kzalloc, GFP, typeof(P), COUNT)
++
++/* All kvmalloc aliases for kmalloc_(obj|objs|flex). */
++#define kvmalloc_obj(P, GFP)                          \
++      __alloc_objs(kvmalloc, GFP, typeof(P), 1)
++#define kvmalloc_objs(P, COUNT, GFP)                  \
++      __alloc_objs(kvmalloc, GFP, typeof(P), COUNT)
++
++/* All kvzalloc aliases for kmalloc_(obj|objs|flex). */
++#define kvzalloc_obj(P, GFP)                          \
++      __alloc_objs(kvzalloc, GFP, typeof(P), 1)
++#define kvzalloc_objs(P, COUNT, GFP)                  \
++      __alloc_objs(kvzalloc, GFP, typeof(P), COUNT)
++
+ #define kmem_buckets_alloc(_b, _size, _flags) \
+       alloc_hooks(__kmalloc_node_noprof(PASS_BUCKET_PARAMS(_size, _b), _flags, NUMA_NO_NODE))
diff --git a/queue-6.12/slab-recognize-gfp-parameter-as-optional-in-kernel-doc.patch b/queue-6.12/slab-recognize-gfp-parameter-as-optional-in-kernel-doc.patch
new file mode 100644 (file)
index 0000000..0806f7b
--- /dev/null
@@ -0,0 +1,60 @@
+From stable+bounces-276928-greg=kroah.com@vger.kernel.org Fri Jul 17 06:48:15 2026
+From: Eric Biggers <ebiggers@kernel.org>
+Date: Thu, 16 Jul 2026 21:43:01 -0700
+Subject: slab: recognize @GFP parameter as optional in kernel-doc
+To: stable@vger.kernel.org
+Cc: linux-hardening@vger.kernel.org, linux-fscrypt@vger.kernel.org, linux-kernel@vger.kernel.org, Randy Dunlap <rdunlap@infradead.org>, "Harry Yoo (Oracle)" <harry@kernel.org>, "Vlastimil Babka (SUSE)" <vbabka@kernel.org>, Eric Biggers <ebiggers@kernel.org>
+Message-ID: <20260717044303.425265-6-ebiggers@kernel.org>
+
+From: Randy Dunlap <rdunlap@infradead.org>
+
+commit 7b5f5865fb11e60edd03c5e063e2d228b7062317 upstream.
+
+Since the @GFP parameter in kmalloc_obj() etc. is now optional, change
+the kernel-doc to indicate that it is optional. This avoids kernel-doc
+warnings:
+
+WARNING: include/linux/slab.h:1101 Excess function parameter 'GFP' description in 'kmalloc_obj'
+WARNING: include/linux/slab.h:1113 Excess function parameter 'GFP' description in 'kmalloc_objs'
+WARNING: include/linux/slab.h:1128 Excess function parameter 'GFP' description in 'kmalloc_flex'
+
+Fixes: e19e1b480ac7 ("add default_gfp() helper macro and use it in the new *alloc_obj() helpers")
+Signed-off-by: Randy Dunlap <rdunlap@infradead.org>
+Acked-by: Harry Yoo (Oracle) <harry@kernel.org>
+Link: https://patch.msgid.link/20260617163125.2716279-1-rdunlap@infradead.org
+Signed-off-by: Vlastimil Babka (SUSE) <vbabka@kernel.org>
+Signed-off-by: Eric Biggers <ebiggers@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ include/linux/slab.h |    6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+--- a/include/linux/slab.h
++++ b/include/linux/slab.h
+@@ -924,7 +924,7 @@ static __always_inline __alloc_size(1) v
+ /**
+  * kmalloc_obj - Allocate a single instance of the given type
+  * @VAR_OR_TYPE: Variable or type to allocate.
+- * @GFP: GFP flags for the allocation.
++ * @...: optional GFP flags for the allocation (GFP_KERNEL when not specified).
+  *
+  * Returns: newly allocated pointer to a @VAR_OR_TYPE on success, or NULL
+  * on failure.
+@@ -936,7 +936,7 @@ static __always_inline __alloc_size(1) v
+  * kmalloc_objs - Allocate an array of the given type
+  * @VAR_OR_TYPE: Variable or type to allocate an array of.
+  * @COUNT: How many elements in the array.
+- * @GFP: GFP flags for the allocation.
++ * @...: optional GFP flags for the allocation (GFP_KERNEL when not specified).
+  *
+  * Returns: newly allocated pointer to array of @VAR_OR_TYPE on success,
+  * or NULL on failure.
+@@ -949,7 +949,7 @@ static __always_inline __alloc_size(1) v
+  * @VAR_OR_TYPE: Variable or type to allocate (with its flex array).
+  * @FAM: The name of the flexible array member of the structure.
+  * @COUNT: How many flexible array member elements are desired.
+- * @GFP: GFP flags for the allocation.
++ * @...: optional GFP flags for the allocation (GFP_KERNEL when not specified).
+  *
+  * Returns: newly allocated pointer to @VAR_OR_TYPE on success, NULL on
+  * failure. If @FAM has been annotated with __counted_by(), the allocation