From: Greg Kroah-Hartman Date: Tue, 21 Jul 2026 13:14:47 +0000 (+0200) Subject: 6.12-stable patches X-Git-Url: http://git.ipfire.org/gitweb/index.cgi?a=commitdiff_plain;h=38cc5386419976dec9f5df84110ef55ff2100ef1;p=thirdparty%2Fkernel%2Fstable-queue.git 6.12-stable patches 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 --- 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 index 0000000000..629257d758 --- /dev/null +++ b/queue-6.12/add-default_gfp-helper-macro-and-use-it-in-the-new-alloc_obj-helpers.patch @@ -0,0 +1,134 @@ +From stable+bounces-276926-greg=kroah.com@vger.kernel.org Fri Jul 17 06:47:26 2026 +From: Eric Biggers +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 , Eric Biggers +Message-ID: <20260717044303.425265-4-ebiggers@kernel.org> + +From: Linus Torvalds + +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 +Signed-off-by: Eric Biggers +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..343fef6e13 --- /dev/null +++ b/queue-6.12/bpf-reject-bpf_map_type_inode_storage-creation-if-bpf-lsm-is-uninitialized.patch @@ -0,0 +1,112 @@ +From a6f0643e4f63cfaa0d5d4a69de4f132eac4b8fe4 Mon Sep 17 00:00:00 2001 +From: Matt Bobrowski +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 + +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 +Signed-off-by: Matt Bobrowski +Signed-off-by: Daniel Borkmann +Reviewed-by: Emil Tsalapatis +Reviewed-by: Amery Hung +Link: https://lore.kernel.org/bpf/20260628201103.3624525-1-mattbobrowski@google.com +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 +@@ -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 + #include + ++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 index 0000000000..b3ecce5a3e --- /dev/null +++ b/queue-6.12/default_gfp-avoid-using-the-newfangled-__va_opt__-trick.patch @@ -0,0 +1,50 @@ +From stable+bounces-276927-greg=kroah.com@vger.kernel.org Fri Jul 17 06:47:05 2026 +From: Eric Biggers +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 , Ricardo Ribalda , Richard Fitzgerald , Ben Dooks , Eric Biggers +Message-ID: <20260717044303.425265-5-ebiggers@kernel.org> + +From: Linus Torvalds + +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 +Reported-and-tested-by: Richard Fitzgerald +Reported-by: Ben Dooks +Fixes: e19e1b480ac7 ("add default_gfp() helper macro and use it in the new *alloc_obj() helpers") +Signed-off-by: Linus Torvalds +Signed-off-by: Eric Biggers +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..fc45570ec2 --- /dev/null +++ b/queue-6.12/fscrypt-fix-key-setup-in-edge-case-with-multiple-data-unit-sizes.patch @@ -0,0 +1,427 @@ +From stable+bounces-276929-greg=kroah.com@vger.kernel.org Fri Jul 17 06:48:56 2026 +From: Eric Biggers +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 +Message-ID: <20260717044303.425265-7-ebiggers@kernel.org> + +From: Eric Biggers + +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 +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..6c98eb7064 --- /dev/null +++ b/queue-6.12/fscrypt-replace-mk_users-keyring-with-simple-list.patch @@ -0,0 +1,454 @@ +From stable+bounces-276930-greg=kroah.com@vger.kernel.org Fri Jul 17 06:47:25 2026 +From: Eric Biggers +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 , syzbot+f55b043dacf43776b50c@syzkaller.appspotmail.com, Mohammed EL Kadiri +Message-ID: <20260717044303.425265-8-ebiggers@kernel.org> + +From: Eric Biggers + +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 +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 +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..30b43ac823 --- /dev/null +++ b/queue-6.12/kvm-arm64-ensure-level-is-always-initialized-when-relaxing-perms.patch @@ -0,0 +1,39 @@ +From 100baf0184896f859290a684f864b8200d8ac872 Mon Sep 17 00:00:00 2001 +From: Oliver Upton +Date: Wed, 1 Jul 2026 16:16:19 -0700 +Subject: KVM: arm64: Ensure level is always initialized when relaxing perms + +From: Oliver Upton + +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 +Reviewed-by: Wei-Lin Chang +Link: https://patch.msgid.link/20260701231620.3300204-2-oupton@kernel.org +Signed-off-by: Marc Zyngier +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..1124b39b1d --- /dev/null +++ b/queue-6.12/kvm-arm64-fix-propagation-of-tlbi-level-in-kvm_pgtable_stage2_relax_perms.patch @@ -0,0 +1,46 @@ +From 8d187d4b33c262c0f3e44842553521151d8629e8 Mon Sep 17 00:00:00 2001 +From: Marc Zyngier +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 + +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 +Reviewed-by: Oliver Upton +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 +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..f47ea30e0c --- /dev/null +++ b/queue-6.12/kvm-move-kvm_io_bus_get_dev-locking-responsibilities-to-callers.patch @@ -0,0 +1,79 @@ +From 3a07249981629ace483ebbef81ef6b34c2d2afec Mon Sep 17 00:00:00 2001 +From: Marc Zyngier +Date: Sat, 27 Jun 2026 11:51:05 +0100 +Subject: KVM: Move kvm_io_bus_get_dev() locking responsibilities to callers + +From: Marc Zyngier + +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 +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 +Link: https://patch.msgid.link/20260627105105.1005990-1-maz@kernel.org +Signed-off-by: Marc Zyngier +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..fae5a646e2 --- /dev/null +++ b/queue-6.12/mm-damon-core-always-put-unsuccessfully-committed-target-pids.patch @@ -0,0 +1,153 @@ +From 6a66c557a2ab2609575bafd15e093669c05f9711 Mon Sep 17 00:00:00 2001 +From: SeongJae Park +Date: Thu, 4 Jun 2026 18:38:48 -0700 +Subject: mm/damon/core: always put unsuccessfully committed target pids + +From: SeongJae Park + +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 +Cc: # 6.11.x +Signed-off-by: Andrew Morton +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..cf1aca6542 --- /dev/null +++ b/queue-6.12/perf-x86-amd-brs-fix-kernel-address-leakage.patch @@ -0,0 +1,87 @@ +From 47915e855fb38b42133e31ba917d99565f862154 Mon Sep 17 00:00:00 2001 +From: Sandipan Das +Date: Fri, 10 Jul 2026 22:04:49 +0530 +Subject: perf/x86/amd/brs: Fix kernel address leakage + +From: Sandipan Das + +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 +Signed-off-by: Sandipan Das +Signed-off-by: Ingo Molnar +Cc: stable@vger.kernel.org +Cc: Peter Zijlstra +Cc: Stephane Eranian +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 +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..bce27f8f70 --- /dev/null +++ b/queue-6.12/selftests-fs-statmount-build-with-tools-include-dir.patch @@ -0,0 +1,372 @@ +From b13fb4ee46472d7f7fc3e2172c08c06ed8b3f31c Mon Sep 17 00:00:00 2001 +From: Amir Goldstein +Date: Fri, 9 May 2025 15:32:34 +0200 +Subject: selftests/fs/statmount: build with tools include dir + +From: Amir Goldstein + +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 +Signed-off-by: Amir Goldstein +Link: https://lore.kernel.org/20250509133240.529330-3-amir73il@gmail.com +Reviewed-by: Christian Brauner +Signed-off-by: Christian Brauner +[florian: resolved conflict in statmount/Makefile] +Signed-off-by: Florian Fainelli +Signed-off-by: Greg Kroah-Hartman +--- + 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 ++ ++/* ++ * 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 ++#include ++ ++#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 + #include + ++#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) diff --git a/queue-6.12/series b/queue-6.12/series index bd1ec41caa..3e0b761938 100644 --- a/queue-6.12/series +++ b/queue-6.12/series @@ -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 index 0000000000..c88baf2ae4 --- /dev/null +++ b/queue-6.12/slab-introduce-kmalloc_flex-and-family.patch @@ -0,0 +1,173 @@ +From stable+bounces-276925-greg=kroah.com@vger.kernel.org Fri Jul 17 06:47:13 2026 +From: Eric Biggers +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 , Vlastimil Babka , Eric Biggers +Message-ID: <20260717044303.425265-3-ebiggers@kernel.org> + +From: Kees Cook + +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 +Signed-off-by: Kees Cook +[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 +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..19c45cfe27 --- /dev/null +++ b/queue-6.12/slab-introduce-kmalloc_obj-and-family.patch @@ -0,0 +1,162 @@ +From stable+bounces-276924-greg=kroah.com@vger.kernel.org Fri Jul 17 06:47:09 2026 +From: Eric Biggers +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 , Vlastimil Babka , Eric Biggers +Message-ID: <20260717044303.425265-2-ebiggers@kernel.org> + +From: Kees Cook + +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 +Link: https://patch.msgid.link/20251203233036.3212363-1-kees@kernel.org +Signed-off-by: Kees Cook +Signed-off-by: Eric Biggers +Signed-off-by: Greg Kroah-Hartman +--- + 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 + #include + #include + #include +@@ -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 index 0000000000..0806f7b136 --- /dev/null +++ b/queue-6.12/slab-recognize-gfp-parameter-as-optional-in-kernel-doc.patch @@ -0,0 +1,60 @@ +From stable+bounces-276928-greg=kroah.com@vger.kernel.org Fri Jul 17 06:48:15 2026 +From: Eric Biggers +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 , "Harry Yoo (Oracle)" , "Vlastimil Babka (SUSE)" , Eric Biggers +Message-ID: <20260717044303.425265-6-ebiggers@kernel.org> + +From: Randy Dunlap + +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 +Acked-by: Harry Yoo (Oracle) +Link: https://patch.msgid.link/20260617163125.2716279-1-rdunlap@infradead.org +Signed-off-by: Vlastimil Babka (SUSE) +Signed-off-by: Eric Biggers +Signed-off-by: Greg Kroah-Hartman +--- + 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