]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
Fixes for all trees master
authorSasha Levin <sashal@kernel.org>
Mon, 17 Aug 2026 03:25:46 +0000 (23:25 -0400)
committerSasha Levin <sashal@kernel.org>
Mon, 17 Aug 2026 03:25:46 +0000 (23:25 -0400)
Signed-off-by: Sasha Levin <sashal@kernel.org>
24 files changed:
queue-5.10/fscrypt-replace-mk_users-keyring-with-simple-list.patch [new file with mode: 0644]
queue-5.10/mips-sched-fix-cpumask_offstack-memory-corruption.patch [new file with mode: 0644]
queue-5.10/rdma-rxe-fix-a-use-after-free-problem-in-rxe_mmap.patch [new file with mode: 0644]
queue-5.10/series
queue-5.15/fscrypt-replace-mk_users-keyring-with-simple-list.patch [new file with mode: 0644]
queue-5.15/rdma-rxe-fix-a-use-after-free-problem-in-rxe_mmap.patch [new file with mode: 0644]
queue-5.15/series
queue-6.1/fscrypt-replace-mk_users-keyring-with-simple-list.patch [new file with mode: 0644]
queue-6.1/rdma-rxe-fix-a-use-after-free-problem-in-rxe_mmap.patch [new file with mode: 0644]
queue-6.1/selftests-bpf-adapt-sockmap-update-error-handling.patch [new file with mode: 0644]
queue-6.1/selftests-bpf-fail-unbound-udp-on-sockmap-update.patch [new file with mode: 0644]
queue-6.1/series
queue-6.12/selftests-bpf-adapt-sockmap-update-error-handling.patch [new file with mode: 0644]
queue-6.12/selftests-bpf-ensure-udp-sockets-are-bound.patch [new file with mode: 0644]
queue-6.12/series
queue-6.18/selftests-bpf-adapt-sockmap-update-error-handling.patch [new file with mode: 0644]
queue-6.18/selftests-bpf-ensure-udp-sockets-are-bound.patch [new file with mode: 0644]
queue-6.18/series
queue-6.6/fscrypt-replace-mk_users-keyring-with-simple-list.patch [new file with mode: 0644]
queue-6.6/selftests-bpf-adapt-sockmap-update-error-handling.patch [new file with mode: 0644]
queue-6.6/series
queue-7.1/selftests-bpf-adapt-sockmap-update-error-handling.patch [new file with mode: 0644]
queue-7.1/selftests-bpf-ensure-udp-sockets-are-bound.patch [new file with mode: 0644]
queue-7.1/series

diff --git a/queue-5.10/fscrypt-replace-mk_users-keyring-with-simple-list.patch b/queue-5.10/fscrypt-replace-mk_users-keyring-with-simple-list.patch
new file mode 100644 (file)
index 0000000..d98a1fb
--- /dev/null
@@ -0,0 +1,448 @@
+From f4f836c1c2185ccffa01006331ec19295775e80b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 15 Aug 2026 11:31:41 -0700
+Subject: fscrypt: Replace mk_users keyring with simple list
+
+From: Eric Biggers <ebiggers@kernel.org>
+
+commit 696c030e1e3438955aba443b308ee8b6faa3983e upstream.
+
+Change mk_users (the set of user claims to an fscrypt master key) from a
+'struct key' keyring to a simple linked list.
+
+It's still a collection of 'struct key' for quota tracking.  It was
+originally thought to be natural that a collection of 'struct key'
+should be held in a 'struct key' keyring.  In reality, it's just been
+causing problems, similar to how using 'struct key' for the filesystem
+keyring caused problems and was removed in commit d7e7b9af104c
+("fscrypt: stop using keyrings subsystem for fscrypt_master_key").
+
+Commit d3a7bd420076 ("fscrypt: clear keyring before calling key_put()")
+fixed mk_users cleanup to be synchronous.  But that apparently wasn't
+enough: the keyring subsystem's redundant locking is still generating
+lockdep false positives due to the interaction with filesystem reclaim.
+
+With the simple list, the redundant locking and lockdep issue goes away.
+
+Of course, searching a linked list is linear-time whereas the
+'struct key' keyring used a fancy constant-time associative array.  But
+that's fine here, since in practice there's just one entry in the list.
+In fact the new code is much faster in practice, since it's much smaller
+and doesn't have to convert the kuid_t into a string to search for it.
+
+Reported-by: syzbot+f55b043dacf43776b50c@syzkaller.appspotmail.com
+Closes: https://syzkaller.appspot.com/bug?extid=f55b043dacf43776b50c
+Reported-by: Mohammed EL Kadiri <med08elkadiri@gmail.com>
+Closes: https://lore.kernel.org/keyrings/20260614150041.21172-1-med08elkadiri@gmail.com/
+Fixes: 23c688b54016 ("fscrypt: allow unprivileged users to add/remove keys for v2 policies")
+Cc: stable@vger.kernel.org
+Link: https://patch.msgid.link/20260618221921.87896-1-ebiggers@kernel.org
+Signed-off-by: Eric Biggers <ebiggers@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/crypto/fscrypt_private.h |  32 ++++--
+ fs/crypto/keyring.c         | 212 ++++++++++++++++--------------------
+ 2 files changed, 113 insertions(+), 131 deletions(-)
+
+diff --git a/fs/crypto/fscrypt_private.h b/fs/crypto/fscrypt_private.h
+index b746d7df37582..72db3df9dfad7 100644
+--- a/fs/crypto/fscrypt_private.h
++++ b/fs/crypto/fscrypt_private.h
+@@ -403,6 +403,19 @@ fscrypt_is_key_prepared(struct fscrypt_prepared_key *prep_key,
+ /* 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
+  */
+@@ -489,19 +502,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.
++       * 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.
+        *
+-       * This is NULL for v1 policy keys; those can only be added by root.
++       * 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.  (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 ->mk_secret.)
++       * 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
+diff --git a/fs/crypto/keyring.c b/fs/crypto/keyring.c
+index 02f8bf8bd54da..51cd45785f0c9 100644
+--- a/fs/crypto/keyring.c
++++ b/fs/crypto/keyring.c
+@@ -64,18 +64,19 @@ static void fscrypt_free_master_key(struct rcu_head *head)
+       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(refcount_read(&mk->mk_active_refs) != 0);
+-      key_put(mk->mk_users);
+-      mk->mk_users = NULL;
++      clear_mk_users(mk);
+       call_rcu(&mk->mk_rcu_head, fscrypt_free_master_key);
+ }
+@@ -141,8 +142,8 @@ static void fscrypt_user_key_describe(const struct key *key, struct seq_file *m)
+ }
+ /*
+- * 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
+@@ -156,30 +157,9 @@ static struct key_type key_type_fscrypt_user = {
+       .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)
+ {
+@@ -318,91 +298,94 @@ fscrypt_find_master_key(struct super_block *sb,
+       return mk;
+ }
+-static int allocate_master_key_users_keyring(struct fscrypt_master_key *mk)
++/* 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)
+ {
+-      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;
+-}
++      struct fscrypt_master_key_user *mk_user;
++      kuid_t uid = current_fsuid();
+-/*
+- * 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);
++      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;
++      }
+-      err = key_instantiate_and_link(mk_user, NULL, 0, mk->mk_users, NULL);
+-      key_put(mk_user);
+-      return err;
++      mk_user = kzalloc(sizeof(*mk_user), GFP_KERNEL);
++      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;
++}
++
++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);
+ }
+ /*
+@@ -426,13 +409,12 @@ static int add_new_master_key(struct super_block *sb,
+       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);
+       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;
+@@ -460,19 +442,13 @@ static int add_existing_master_key(struct fscrypt_master_key *mk,
+       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;
+@@ -787,7 +763,6 @@ int fscrypt_verify_key_added(struct super_block *sb,
+ {
+       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;
+@@ -799,13 +774,10 @@ int fscrypt_verify_key_added(struct super_block *sb,
+               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:
+@@ -998,16 +970,18 @@ static int do_remove_key(struct file *filp, void __user *_uarg, bool all_users)
+       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
+@@ -1095,6 +1069,8 @@ int fscrypt_ioctl_get_key_status(struct file *filp, void __user *uarg)
+       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)))
+@@ -1127,19 +1103,13 @@ int fscrypt_ioctl_get_key_status(struct file *filp, void __user *uarg)
+       }
+       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:
+-- 
+2.53.0
+
diff --git a/queue-5.10/mips-sched-fix-cpumask_offstack-memory-corruption.patch b/queue-5.10/mips-sched-fix-cpumask_offstack-memory-corruption.patch
new file mode 100644 (file)
index 0000000..d61d2f1
--- /dev/null
@@ -0,0 +1,99 @@
+From 36481f7263218b5ab8ebf66cbe88df52e981fd14 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 15 Aug 2026 20:36:33 -0400
+Subject: mips: sched: Fix CPUMASK_OFFSTACK memory corruption
+
+From: Aaron Tomlin <atomlin@atomlin.com>
+
+[ Upstream commit 98e37db4a34d3af3fb2f4648295c25b5e40b20e3 ]
+
+This patch addresses a critical memory management flaw. When
+CONFIG_CPUMASK_OFFSTACK is enabled, cpumask_var_t is a pointer.
+Consequently, sizeof(new_mask) evaluates to the pointer size, causing
+copy_from_user() to clobber the mask pointer. Furthermore, the old
+logic performed copy_from_user() before allocating the mask.
+
+Fix this by allocating new_mask first. To handle variable-sized user
+masks correctly, use cpumask_size() to truncate overly large user masks
+or pad undersized masks with zeros before copying the data directly into
+the allocated buffer.
+
+Fixes: 295cbf6d63165 ("[MIPS] Move FPU affinity code into separate file.")
+Cc: stable@vger.kernel.org
+Signed-off-by: Aaron Tomlin <atomlin@atomlin.com>
+Signed-off-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/mips/kernel/mips-mt-fpaff.c | 28 +++++++++++++++-------------
+ 1 file changed, 15 insertions(+), 13 deletions(-)
+
+diff --git a/arch/mips/kernel/mips-mt-fpaff.c b/arch/mips/kernel/mips-mt-fpaff.c
+index 6c590ef276482..5feffc8708ada 100644
+--- a/arch/mips/kernel/mips-mt-fpaff.c
++++ b/arch/mips/kernel/mips-mt-fpaff.c
+@@ -70,11 +70,16 @@ asmlinkage long mipsmt_sys_sched_setaffinity(pid_t pid, unsigned int len,
+       struct task_struct *p;
+       int retval;
+-      if (len < sizeof(new_mask))
+-              return -EINVAL;
+-
+-      if (copy_from_user(&new_mask, user_mask_ptr, sizeof(new_mask)))
+-              return -EFAULT;
++      if (!alloc_cpumask_var(&new_mask, GFP_KERNEL))
++              return -ENOMEM;
++      if (len < cpumask_size())
++              cpumask_clear(new_mask);
++      else if (len > cpumask_size())
++              len = cpumask_size();
++      if (copy_from_user(new_mask, user_mask_ptr, len)) {
++              retval = -EFAULT;
++              goto out_free_new_mask;
++      }
+       get_online_cpus();
+       rcu_read_lock();
+@@ -83,7 +88,8 @@ asmlinkage long mipsmt_sys_sched_setaffinity(pid_t pid, unsigned int len,
+       if (!p) {
+               rcu_read_unlock();
+               put_online_cpus();
+-              return -ESRCH;
++              retval = -ESRCH;
++              goto out_free_new_mask;
+       }
+       /* Prevent p going away */
+@@ -94,13 +100,9 @@ asmlinkage long mipsmt_sys_sched_setaffinity(pid_t pid, unsigned int len,
+               retval = -ENOMEM;
+               goto out_put_task;
+       }
+-      if (!alloc_cpumask_var(&new_mask, GFP_KERNEL)) {
+-              retval = -ENOMEM;
+-              goto out_free_cpus_allowed;
+-      }
+       if (!alloc_cpumask_var(&effective_mask, GFP_KERNEL)) {
+               retval = -ENOMEM;
+-              goto out_free_new_mask;
++              goto out_free_cpus_allowed;
+       }
+       if (!check_same_owner(p) && !capable(CAP_SYS_NICE)) {
+               retval = -EPERM;
+@@ -141,13 +143,13 @@ asmlinkage long mipsmt_sys_sched_setaffinity(pid_t pid, unsigned int len,
+       }
+ out_unlock:
+       free_cpumask_var(effective_mask);
+-out_free_new_mask:
+-      free_cpumask_var(new_mask);
+ out_free_cpus_allowed:
+       free_cpumask_var(cpus_allowed);
+ out_put_task:
+       put_task_struct(p);
+       put_online_cpus();
++out_free_new_mask:
++      free_cpumask_var(new_mask);
+       return retval;
+ }
+-- 
+2.53.0
+
diff --git a/queue-5.10/rdma-rxe-fix-a-use-after-free-problem-in-rxe_mmap.patch b/queue-5.10/rdma-rxe-fix-a-use-after-free-problem-in-rxe_mmap.patch
new file mode 100644 (file)
index 0000000..d92363e
--- /dev/null
@@ -0,0 +1,166 @@
+From d2065fbd2e7334b6c9d18fa13d2fd2ff512748ad Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 14 Aug 2026 13:23:59 -0700
+Subject: RDMA/rxe: Fix a use-after-free problem in rxe_mmap
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Zhu Yanjun <yanjun.zhu@linux.dev>
+
+[ Upstream commit 35744ab3d03c5fca8c1752f53fc8fc674e14c561 ]
+
+rxe_mmap() removes a rxe_mmap_info struct from the pending_mmaps list
+and releases pending_lock while the struct's kref is still at 1:
+
+   list_del_init(&ip->pending_mmaps);
+   spin_unlock_bh(&rxe->pending_lock);   /* ref == 1, no lock held */
+   ret = remap_vmalloc_range(vma, ip->obj, 0);  /* walks PTEs */
+   [...]
+   rxe_vma_open(vma);                    /* kref_get, ref â†’ 2 */
+   remap_vmalloc_range_partial() walks PTEs without any lock.
+
+A concurrent DESTROY_CQ ioctl on another CPU calls:
+
+    kref_put(&q->ip->ref, rxe_mmap_release)   /* ref 1→0 */
+    vfree(ip->obj)   /* clears vmalloc PTEs mid-walk */
+    kfree(ip)        /* frees rxe_mmap_info */
+
+This yields:
+
+   1. Kernel crash, vmalloc_to_page() returns NULL when vfree wins the
+   per-PTE race -> vm_insert_page(NULL) â†’ GPF in validate_page_before_insert
+
+   2. Page UAF, vmalloc_to_page() reads a stale PTE before vfree clears
+   it. User VMA holds a PTE to a free'd page which might eventually get
+   reallocated later by vmalloc which allows the attacker to get a clean
+   page-level UAF.
+
+   It is worth noting that even though a page-level UAF is possible given
+   the strong primitive, it is statistically very difficult to achieve
+   given the very short time window (after the last insert_page and before
+   the kref_get).
+
+The call trace are as below:
+
+  Oops: general protection fault, probably for non-canonical address 0xdffffc0000000001: 0000 [#1] SMP KASAN NOPTI
+  KASAN: null-ptr-deref in range [0x0000000000000008-0x000000000000000f]
+  CPU: 0 UID: 1000 PID: 413 Comm: poc Not tainted 7.0.0-rc5-dirty #28 PREEMPT(lazy)
+  Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.15.0-1 04/01/2014
+  RIP: 0010:validate_page_before_insert+0x32/0x300
+  Code: e5 41 57 41 56 49 89 fe 41 55 41 54 53 48 89 f3 e8 93 b5 a3 ff 48 8d 7b 08 48 b8 00 00 00 00 00 fc ff df 48 89 fa 48 c1 ea 03 <80> 3c 02 00 0f 85 7b 02 00 00 4c 8b 63 08 31 ff 4d 89 e5 41 83 e5
+  RSP: 0018:ffff88811b15f2f0 EFLAGS: 00000202
+  RAX: dffffc0000000000 RBX: 0000000000000000 RCX: 0000000000000000
+  RDX: 0000000000000001 RSI: 0000000000000000 RDI: 0000000000000008
+  RBP: ffff88811b15f318 R08: 0000000000000000 R09: 0000000000000000
+  R10: 0000000000000000 R11: 0000000000000000 R12: ffff8881181eee00
+  R13: 0000000000000000 R14: ffff8881181eee00 R15: ffff8881181eee20
+  FS:  00007b1e000f76c0(0000) GS:ffff8884268e0000(0000) knlGS:0000000000000000
+  CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+  CR2: 00007b1e00a24ac0 CR3: 0000000116eb3000 CR4: 00000000000006f0
+  Call Trace:
+   <TASK>
+   insert_page+0x8f/0x190
+   ? __pfx_insert_page+0x10/0x10
+   ? kasan_save_alloc_info+0x38/0x60
+   vm_insert_page+0x2e7/0x400
+   remap_vmalloc_range_partial+0x212/0x3e0
+   remap_vmalloc_range+0x6e/0xb0
+   ? __kasan_check_write+0x14/0x30
+   rxe_mmap+0x2e9/0x5d0
+   ib_uverbs_mmap+0x1ad/0x2c0
+   __mmap_region+0x12c2/0x2ad0
+   ? __pfx___mmap_region+0x10/0x10
+   ? __sanitizer_cov_trace_switch+0x58/0xb0
+   ? mas_prev_slot+0x360/0x39c0
+   ? __sanitizer_cov_trace_switch+0x58/0xb0
+   ? mas_next_slot+0x1e5b/0x2f40
+   ? __sanitizer_cov_trace_cmp8+0x18/0x30
+   ? unmapped_area_topdown+0x4dd/0x610
+   ? kfree+0x1b1/0x440
+   ? free_cpumask_var+0x16/0x30
+   ? __kasan_slab_free+0x7d/0xa0
+   ? __sanitizer_cov_trace_cmp8+0x18/0x30
+   mmap_region+0x2e6/0x3c0
+   do_mmap+0xa3e/0x12a0
+   ? __pfx_do_mmap+0x10/0x10
+   ? __kasan_check_write+0x14/0x30
+   ? down_write_killable+0xba/0x160
+   ? __pfx_down_write_killable+0x10/0x10
+   ? __sanitizer_cov_trace_cmp4+0x16/0x30
+   vm_mmap_pgoff+0x2d4/0x4a0
+   ? __pfx_vm_mmap_pgoff+0x10/0x10
+   ? fget+0x1bf/0x270
+   ksys_mmap_pgoff+0x40c/0x690
+   ? __sanitizer_cov_trace_const_cmp4+0x16/0x30
+   ? __pfx_ksys_mmap_pgoff+0x10/0x10
+   ? __kasan_check_write+0x14/0x30
+   ? _raw_spin_trylock+0xbb/0x130
+   ? __pfx__raw_spin_trylock+0x10/0x10
+   __x64_sys_mmap+0x135/0x1e0
+   x64_sys_call+0x1c14/0x2790
+   do_syscall_64+0xd2/0x1050
+   ? rcu_core+0x352/0x7d0
+   ? rcu_core_si+0xe/0x20
+   ? handle_softirqs+0x1aa/0x650
+   ? __sanitizer_cov_trace_cmp4+0x16/0x30
+   ? fpregs_assert_state_consistent+0xe1/0x160
+   ? irqentry_exit+0xb1/0x670
+   entry_SYSCALL_64_after_hwframe+0x76/0x7e
+
+Link: https://patch.msgid.link/r/20260515002537.6209-1-yanjun.zhu@linux.dev
+Reported-and-tested-by: nasm <n4sm@protonmail.com>
+Suggested-by: nasm <n4sm@protonmail.com>
+Fixes: 8700e3e7c485 ("Soft RoCE driver")
+Signed-off-by: Zhu Yanjun <yanjun.zhu@linux.dev>
+Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
+(cherry picked from commit 35744ab3d03c5fca8c1752f53fc8fc674e14c561)
+[Harshit: Minor conflict resolution pr_err() vs rxe_dbg_dev() usage]
+Signed-off-by: Harshit Mogalapalli <harshit.m.mogalapalli@oracle.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/infiniband/sw/rxe/rxe_mmap.c | 19 ++++++++++++++++---
+ 1 file changed, 16 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/infiniband/sw/rxe/rxe_mmap.c b/drivers/infiniband/sw/rxe/rxe_mmap.c
+index 035f226af1336..edd9345da295c 100644
+--- a/drivers/infiniband/sw/rxe/rxe_mmap.c
++++ b/drivers/infiniband/sw/rxe/rxe_mmap.c
+@@ -94,18 +94,31 @@ int rxe_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
+       goto done;
+ found_it:
++      /*
++       * Increment refcount and check whether it is being freed atm while
++       * holding lock to prevent UAF
++       */
++      if (!kref_get_unless_zero(&ip->ref)) {
++              spin_unlock_bh(&rxe->pending_lock);
++              ret = -ENXIO;
++              goto done;
++      }
++
+       list_del_init(&ip->pending_mmaps);
+       spin_unlock_bh(&rxe->pending_lock);
++      vma->vm_ops = &rxe_vm_ops;
++      vma->vm_private_data = ip;
++
+       ret = remap_vmalloc_range(vma, ip->obj, 0);
+       if (ret) {
++              vma->vm_private_data = NULL;
++              vma->vm_ops = NULL;
++              kref_put(&ip->ref, rxe_mmap_release);
+               pr_err("err %d from remap_vmalloc_range\n", ret);
+               goto done;
+       }
+-      vma->vm_ops = &rxe_vm_ops;
+-      vma->vm_private_data = ip;
+-      rxe_vma_open(vma);
+ done:
+       return ret;
+ }
+-- 
+2.53.0
+
index 50857fa086400a00bbfb04375430b7214616e6e2..181ae305b5c5c0020b0f49e261ecfb3833099245 100644 (file)
@@ -351,3 +351,6 @@ bluetooth-l2cap-fix-uaf-in-channel-timeout-by-holdin.patch
 bluetooth-6lowpan-fix-using-chan-conn-as-indication-.patch
 ima-fix-out-of-bounds-read-in-xattr_verify.patch
 futex-prevent-robust-futex-exit-race-some-more.patch
+rdma-rxe-fix-a-use-after-free-problem-in-rxe_mmap.patch
+mips-sched-fix-cpumask_offstack-memory-corruption.patch
+fscrypt-replace-mk_users-keyring-with-simple-list.patch
diff --git a/queue-5.15/fscrypt-replace-mk_users-keyring-with-simple-list.patch b/queue-5.15/fscrypt-replace-mk_users-keyring-with-simple-list.patch
new file mode 100644 (file)
index 0000000..8ee71a4
--- /dev/null
@@ -0,0 +1,448 @@
+From 61d4250cea229fc032210fc00b1252bba6d0e98e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 15 Aug 2026 11:31:26 -0700
+Subject: fscrypt: Replace mk_users keyring with simple list
+
+From: Eric Biggers <ebiggers@kernel.org>
+
+commit 696c030e1e3438955aba443b308ee8b6faa3983e upstream.
+
+Change mk_users (the set of user claims to an fscrypt master key) from a
+'struct key' keyring to a simple linked list.
+
+It's still a collection of 'struct key' for quota tracking.  It was
+originally thought to be natural that a collection of 'struct key'
+should be held in a 'struct key' keyring.  In reality, it's just been
+causing problems, similar to how using 'struct key' for the filesystem
+keyring caused problems and was removed in commit d7e7b9af104c
+("fscrypt: stop using keyrings subsystem for fscrypt_master_key").
+
+Commit d3a7bd420076 ("fscrypt: clear keyring before calling key_put()")
+fixed mk_users cleanup to be synchronous.  But that apparently wasn't
+enough: the keyring subsystem's redundant locking is still generating
+lockdep false positives due to the interaction with filesystem reclaim.
+
+With the simple list, the redundant locking and lockdep issue goes away.
+
+Of course, searching a linked list is linear-time whereas the
+'struct key' keyring used a fancy constant-time associative array.  But
+that's fine here, since in practice there's just one entry in the list.
+In fact the new code is much faster in practice, since it's much smaller
+and doesn't have to convert the kuid_t into a string to search for it.
+
+Reported-by: syzbot+f55b043dacf43776b50c@syzkaller.appspotmail.com
+Closes: https://syzkaller.appspot.com/bug?extid=f55b043dacf43776b50c
+Reported-by: Mohammed EL Kadiri <med08elkadiri@gmail.com>
+Closes: https://lore.kernel.org/keyrings/20260614150041.21172-1-med08elkadiri@gmail.com/
+Fixes: 23c688b54016 ("fscrypt: allow unprivileged users to add/remove keys for v2 policies")
+Cc: stable@vger.kernel.org
+Link: https://patch.msgid.link/20260618221921.87896-1-ebiggers@kernel.org
+Signed-off-by: Eric Biggers <ebiggers@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/crypto/fscrypt_private.h |  32 ++++--
+ fs/crypto/keyring.c         | 212 ++++++++++++++++--------------------
+ 2 files changed, 113 insertions(+), 131 deletions(-)
+
+diff --git a/fs/crypto/fscrypt_private.h b/fs/crypto/fscrypt_private.h
+index 373c434b375c0..555d942342ccc 100644
+--- a/fs/crypto/fscrypt_private.h
++++ b/fs/crypto/fscrypt_private.h
+@@ -402,6 +402,19 @@ fscrypt_is_key_prepared(struct fscrypt_prepared_key *prep_key,
+ /* 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
+  */
+@@ -488,19 +501,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.
++       * 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.
+        *
+-       * This is NULL for v1 policy keys; those can only be added by root.
++       * 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.  (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 ->mk_secret.)
++       * 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
+diff --git a/fs/crypto/keyring.c b/fs/crypto/keyring.c
+index 02f8bf8bd54da..51cd45785f0c9 100644
+--- a/fs/crypto/keyring.c
++++ b/fs/crypto/keyring.c
+@@ -64,18 +64,19 @@ static void fscrypt_free_master_key(struct rcu_head *head)
+       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(refcount_read(&mk->mk_active_refs) != 0);
+-      key_put(mk->mk_users);
+-      mk->mk_users = NULL;
++      clear_mk_users(mk);
+       call_rcu(&mk->mk_rcu_head, fscrypt_free_master_key);
+ }
+@@ -141,8 +142,8 @@ static void fscrypt_user_key_describe(const struct key *key, struct seq_file *m)
+ }
+ /*
+- * 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
+@@ -156,30 +157,9 @@ static struct key_type key_type_fscrypt_user = {
+       .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)
+ {
+@@ -318,91 +298,94 @@ fscrypt_find_master_key(struct super_block *sb,
+       return mk;
+ }
+-static int allocate_master_key_users_keyring(struct fscrypt_master_key *mk)
++/* 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)
+ {
+-      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;
+-}
++      struct fscrypt_master_key_user *mk_user;
++      kuid_t uid = current_fsuid();
+-/*
+- * 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);
++      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;
++      }
+-      err = key_instantiate_and_link(mk_user, NULL, 0, mk->mk_users, NULL);
+-      key_put(mk_user);
+-      return err;
++      mk_user = kzalloc(sizeof(*mk_user), GFP_KERNEL);
++      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;
++}
++
++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);
+ }
+ /*
+@@ -426,13 +409,12 @@ static int add_new_master_key(struct super_block *sb,
+       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);
+       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;
+@@ -460,19 +442,13 @@ static int add_existing_master_key(struct fscrypt_master_key *mk,
+       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;
+@@ -787,7 +763,6 @@ int fscrypt_verify_key_added(struct super_block *sb,
+ {
+       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;
+@@ -799,13 +774,10 @@ int fscrypt_verify_key_added(struct super_block *sb,
+               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:
+@@ -998,16 +970,18 @@ static int do_remove_key(struct file *filp, void __user *_uarg, bool all_users)
+       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
+@@ -1095,6 +1069,8 @@ int fscrypt_ioctl_get_key_status(struct file *filp, void __user *uarg)
+       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)))
+@@ -1127,19 +1103,13 @@ int fscrypt_ioctl_get_key_status(struct file *filp, void __user *uarg)
+       }
+       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:
+-- 
+2.53.0
+
diff --git a/queue-5.15/rdma-rxe-fix-a-use-after-free-problem-in-rxe_mmap.patch b/queue-5.15/rdma-rxe-fix-a-use-after-free-problem-in-rxe_mmap.patch
new file mode 100644 (file)
index 0000000..fb08657
--- /dev/null
@@ -0,0 +1,166 @@
+From 44d7d080a04bfcc2df9e77ab36fb59c0645bfd9b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 14 Aug 2026 13:23:59 -0700
+Subject: RDMA/rxe: Fix a use-after-free problem in rxe_mmap
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Zhu Yanjun <yanjun.zhu@linux.dev>
+
+[ Upstream commit 35744ab3d03c5fca8c1752f53fc8fc674e14c561 ]
+
+rxe_mmap() removes a rxe_mmap_info struct from the pending_mmaps list
+and releases pending_lock while the struct's kref is still at 1:
+
+   list_del_init(&ip->pending_mmaps);
+   spin_unlock_bh(&rxe->pending_lock);   /* ref == 1, no lock held */
+   ret = remap_vmalloc_range(vma, ip->obj, 0);  /* walks PTEs */
+   [...]
+   rxe_vma_open(vma);                    /* kref_get, ref â†’ 2 */
+   remap_vmalloc_range_partial() walks PTEs without any lock.
+
+A concurrent DESTROY_CQ ioctl on another CPU calls:
+
+    kref_put(&q->ip->ref, rxe_mmap_release)   /* ref 1→0 */
+    vfree(ip->obj)   /* clears vmalloc PTEs mid-walk */
+    kfree(ip)        /* frees rxe_mmap_info */
+
+This yields:
+
+   1. Kernel crash, vmalloc_to_page() returns NULL when vfree wins the
+   per-PTE race -> vm_insert_page(NULL) â†’ GPF in validate_page_before_insert
+
+   2. Page UAF, vmalloc_to_page() reads a stale PTE before vfree clears
+   it. User VMA holds a PTE to a free'd page which might eventually get
+   reallocated later by vmalloc which allows the attacker to get a clean
+   page-level UAF.
+
+   It is worth noting that even though a page-level UAF is possible given
+   the strong primitive, it is statistically very difficult to achieve
+   given the very short time window (after the last insert_page and before
+   the kref_get).
+
+The call trace are as below:
+
+  Oops: general protection fault, probably for non-canonical address 0xdffffc0000000001: 0000 [#1] SMP KASAN NOPTI
+  KASAN: null-ptr-deref in range [0x0000000000000008-0x000000000000000f]
+  CPU: 0 UID: 1000 PID: 413 Comm: poc Not tainted 7.0.0-rc5-dirty #28 PREEMPT(lazy)
+  Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.15.0-1 04/01/2014
+  RIP: 0010:validate_page_before_insert+0x32/0x300
+  Code: e5 41 57 41 56 49 89 fe 41 55 41 54 53 48 89 f3 e8 93 b5 a3 ff 48 8d 7b 08 48 b8 00 00 00 00 00 fc ff df 48 89 fa 48 c1 ea 03 <80> 3c 02 00 0f 85 7b 02 00 00 4c 8b 63 08 31 ff 4d 89 e5 41 83 e5
+  RSP: 0018:ffff88811b15f2f0 EFLAGS: 00000202
+  RAX: dffffc0000000000 RBX: 0000000000000000 RCX: 0000000000000000
+  RDX: 0000000000000001 RSI: 0000000000000000 RDI: 0000000000000008
+  RBP: ffff88811b15f318 R08: 0000000000000000 R09: 0000000000000000
+  R10: 0000000000000000 R11: 0000000000000000 R12: ffff8881181eee00
+  R13: 0000000000000000 R14: ffff8881181eee00 R15: ffff8881181eee20
+  FS:  00007b1e000f76c0(0000) GS:ffff8884268e0000(0000) knlGS:0000000000000000
+  CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+  CR2: 00007b1e00a24ac0 CR3: 0000000116eb3000 CR4: 00000000000006f0
+  Call Trace:
+   <TASK>
+   insert_page+0x8f/0x190
+   ? __pfx_insert_page+0x10/0x10
+   ? kasan_save_alloc_info+0x38/0x60
+   vm_insert_page+0x2e7/0x400
+   remap_vmalloc_range_partial+0x212/0x3e0
+   remap_vmalloc_range+0x6e/0xb0
+   ? __kasan_check_write+0x14/0x30
+   rxe_mmap+0x2e9/0x5d0
+   ib_uverbs_mmap+0x1ad/0x2c0
+   __mmap_region+0x12c2/0x2ad0
+   ? __pfx___mmap_region+0x10/0x10
+   ? __sanitizer_cov_trace_switch+0x58/0xb0
+   ? mas_prev_slot+0x360/0x39c0
+   ? __sanitizer_cov_trace_switch+0x58/0xb0
+   ? mas_next_slot+0x1e5b/0x2f40
+   ? __sanitizer_cov_trace_cmp8+0x18/0x30
+   ? unmapped_area_topdown+0x4dd/0x610
+   ? kfree+0x1b1/0x440
+   ? free_cpumask_var+0x16/0x30
+   ? __kasan_slab_free+0x7d/0xa0
+   ? __sanitizer_cov_trace_cmp8+0x18/0x30
+   mmap_region+0x2e6/0x3c0
+   do_mmap+0xa3e/0x12a0
+   ? __pfx_do_mmap+0x10/0x10
+   ? __kasan_check_write+0x14/0x30
+   ? down_write_killable+0xba/0x160
+   ? __pfx_down_write_killable+0x10/0x10
+   ? __sanitizer_cov_trace_cmp4+0x16/0x30
+   vm_mmap_pgoff+0x2d4/0x4a0
+   ? __pfx_vm_mmap_pgoff+0x10/0x10
+   ? fget+0x1bf/0x270
+   ksys_mmap_pgoff+0x40c/0x690
+   ? __sanitizer_cov_trace_const_cmp4+0x16/0x30
+   ? __pfx_ksys_mmap_pgoff+0x10/0x10
+   ? __kasan_check_write+0x14/0x30
+   ? _raw_spin_trylock+0xbb/0x130
+   ? __pfx__raw_spin_trylock+0x10/0x10
+   __x64_sys_mmap+0x135/0x1e0
+   x64_sys_call+0x1c14/0x2790
+   do_syscall_64+0xd2/0x1050
+   ? rcu_core+0x352/0x7d0
+   ? rcu_core_si+0xe/0x20
+   ? handle_softirqs+0x1aa/0x650
+   ? __sanitizer_cov_trace_cmp4+0x16/0x30
+   ? fpregs_assert_state_consistent+0xe1/0x160
+   ? irqentry_exit+0xb1/0x670
+   entry_SYSCALL_64_after_hwframe+0x76/0x7e
+
+Link: https://patch.msgid.link/r/20260515002537.6209-1-yanjun.zhu@linux.dev
+Reported-and-tested-by: nasm <n4sm@protonmail.com>
+Suggested-by: nasm <n4sm@protonmail.com>
+Fixes: 8700e3e7c485 ("Soft RoCE driver")
+Signed-off-by: Zhu Yanjun <yanjun.zhu@linux.dev>
+Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
+(cherry picked from commit 35744ab3d03c5fca8c1752f53fc8fc674e14c561)
+[Harshit: Minor conflict resolution pr_err() vs rxe_dbg_dev() usage]
+Signed-off-by: Harshit Mogalapalli <harshit.m.mogalapalli@oracle.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/infiniband/sw/rxe/rxe_mmap.c | 19 ++++++++++++++++---
+ 1 file changed, 16 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/infiniband/sw/rxe/rxe_mmap.c b/drivers/infiniband/sw/rxe/rxe_mmap.c
+index 035f226af1336..edd9345da295c 100644
+--- a/drivers/infiniband/sw/rxe/rxe_mmap.c
++++ b/drivers/infiniband/sw/rxe/rxe_mmap.c
+@@ -94,18 +94,31 @@ int rxe_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
+       goto done;
+ found_it:
++      /*
++       * Increment refcount and check whether it is being freed atm while
++       * holding lock to prevent UAF
++       */
++      if (!kref_get_unless_zero(&ip->ref)) {
++              spin_unlock_bh(&rxe->pending_lock);
++              ret = -ENXIO;
++              goto done;
++      }
++
+       list_del_init(&ip->pending_mmaps);
+       spin_unlock_bh(&rxe->pending_lock);
++      vma->vm_ops = &rxe_vm_ops;
++      vma->vm_private_data = ip;
++
+       ret = remap_vmalloc_range(vma, ip->obj, 0);
+       if (ret) {
++              vma->vm_private_data = NULL;
++              vma->vm_ops = NULL;
++              kref_put(&ip->ref, rxe_mmap_release);
+               pr_err("err %d from remap_vmalloc_range\n", ret);
+               goto done;
+       }
+-      vma->vm_ops = &rxe_vm_ops;
+-      vma->vm_private_data = ip;
+-      rxe_vma_open(vma);
+ done:
+       return ret;
+ }
+-- 
+2.53.0
+
index 1783532e364eeae078a6a89bb641c5b64d38675b..f66a48316d43419787d30161d21767fbd8aaa1dd 100644 (file)
@@ -411,3 +411,5 @@ bluetooth-l2cap-fix-uaf-in-channel-timeout-by-holdin.patch
 bluetooth-6lowpan-fix-using-chan-conn-as-indication-.patch
 futex-prevent-robust-futex-exit-race-some-more.patch
 pinctrl-renesas-rzg2l-use-enotsupp-instead-of-eopnot.patch
+rdma-rxe-fix-a-use-after-free-problem-in-rxe_mmap.patch
+fscrypt-replace-mk_users-keyring-with-simple-list.patch
diff --git a/queue-6.1/fscrypt-replace-mk_users-keyring-with-simple-list.patch b/queue-6.1/fscrypt-replace-mk_users-keyring-with-simple-list.patch
new file mode 100644 (file)
index 0000000..798ee93
--- /dev/null
@@ -0,0 +1,448 @@
+From 9c99f9f90ca8f04f0a4967fa642ac57e7eed3c59 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 15 Aug 2026 11:30:57 -0700
+Subject: fscrypt: Replace mk_users keyring with simple list
+
+From: Eric Biggers <ebiggers@kernel.org>
+
+commit 696c030e1e3438955aba443b308ee8b6faa3983e upstream.
+
+Change mk_users (the set of user claims to an fscrypt master key) from a
+'struct key' keyring to a simple linked list.
+
+It's still a collection of 'struct key' for quota tracking.  It was
+originally thought to be natural that a collection of 'struct key'
+should be held in a 'struct key' keyring.  In reality, it's just been
+causing problems, similar to how using 'struct key' for the filesystem
+keyring caused problems and was removed in commit d7e7b9af104c
+("fscrypt: stop using keyrings subsystem for fscrypt_master_key").
+
+Commit d3a7bd420076 ("fscrypt: clear keyring before calling key_put()")
+fixed mk_users cleanup to be synchronous.  But that apparently wasn't
+enough: the keyring subsystem's redundant locking is still generating
+lockdep false positives due to the interaction with filesystem reclaim.
+
+With the simple list, the redundant locking and lockdep issue goes away.
+
+Of course, searching a linked list is linear-time whereas the
+'struct key' keyring used a fancy constant-time associative array.  But
+that's fine here, since in practice there's just one entry in the list.
+In fact the new code is much faster in practice, since it's much smaller
+and doesn't have to convert the kuid_t into a string to search for it.
+
+Reported-by: syzbot+f55b043dacf43776b50c@syzkaller.appspotmail.com
+Closes: https://syzkaller.appspot.com/bug?extid=f55b043dacf43776b50c
+Reported-by: Mohammed EL Kadiri <med08elkadiri@gmail.com>
+Closes: https://lore.kernel.org/keyrings/20260614150041.21172-1-med08elkadiri@gmail.com/
+Fixes: 23c688b54016 ("fscrypt: allow unprivileged users to add/remove keys for v2 policies")
+Cc: stable@vger.kernel.org
+Link: https://patch.msgid.link/20260618221921.87896-1-ebiggers@kernel.org
+Signed-off-by: Eric Biggers <ebiggers@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/crypto/fscrypt_private.h |  32 ++++--
+ fs/crypto/keyring.c         | 212 ++++++++++++++++--------------------
+ 2 files changed, 113 insertions(+), 131 deletions(-)
+
+diff --git a/fs/crypto/fscrypt_private.h b/fs/crypto/fscrypt_private.h
+index 88414cbd97aee..aabc3a4751df7 100644
+--- a/fs/crypto/fscrypt_private.h
++++ b/fs/crypto/fscrypt_private.h
+@@ -423,6 +423,19 @@ fscrypt_is_key_prepared(struct fscrypt_prepared_key *prep_key,
+ /* 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
+  */
+@@ -513,19 +526,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.
++       * 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.
+        *
+-       * This is NULL for v1 policy keys; those can only be added by root.
++       * 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.  (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 ->mk_secret.)
++       * 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
+diff --git a/fs/crypto/keyring.c b/fs/crypto/keyring.c
+index 2a24b1f0ae688..e1cce06f43439 100644
+--- a/fs/crypto/keyring.c
++++ b/fs/crypto/keyring.c
+@@ -64,18 +64,19 @@ static void fscrypt_free_master_key(struct rcu_head *head)
+       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(refcount_read(&mk->mk_active_refs) != 0);
+-      key_put(mk->mk_users);
+-      mk->mk_users = NULL;
++      clear_mk_users(mk);
+       call_rcu(&mk->mk_rcu_head, fscrypt_free_master_key);
+ }
+@@ -144,8 +145,8 @@ static void fscrypt_user_key_describe(const struct key *key, struct seq_file *m)
+ }
+ /*
+- * 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
+@@ -159,30 +160,9 @@ static struct key_type key_type_fscrypt_user = {
+       .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)
+ {
+@@ -321,91 +301,94 @@ fscrypt_find_master_key(struct super_block *sb,
+       return mk;
+ }
+-static int allocate_master_key_users_keyring(struct fscrypt_master_key *mk)
++/* 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)
+ {
+-      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;
+-}
++      struct fscrypt_master_key_user *mk_user;
++      kuid_t uid = current_fsuid();
+-/*
+- * 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);
++      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;
++      }
+-      err = key_instantiate_and_link(mk_user, NULL, 0, mk->mk_users, NULL);
+-      key_put(mk_user);
+-      return err;
++      mk_user = kzalloc(sizeof(*mk_user), GFP_KERNEL);
++      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;
++}
++
++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);
+ }
+ /*
+@@ -429,13 +412,12 @@ static int add_new_master_key(struct super_block *sb,
+       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);
+       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;
+@@ -463,19 +445,13 @@ static int add_existing_master_key(struct fscrypt_master_key *mk,
+       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;
+@@ -830,7 +806,6 @@ int fscrypt_verify_key_added(struct super_block *sb,
+ {
+       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;
+@@ -842,13 +817,10 @@ int fscrypt_verify_key_added(struct super_block *sb,
+               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:
+@@ -1041,16 +1013,18 @@ static int do_remove_key(struct file *filp, void __user *_uarg, bool all_users)
+       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
+@@ -1138,6 +1112,8 @@ int fscrypt_ioctl_get_key_status(struct file *filp, void __user *uarg)
+       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)))
+@@ -1170,19 +1146,13 @@ int fscrypt_ioctl_get_key_status(struct file *filp, void __user *uarg)
+       }
+       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:
+-- 
+2.53.0
+
diff --git a/queue-6.1/rdma-rxe-fix-a-use-after-free-problem-in-rxe_mmap.patch b/queue-6.1/rdma-rxe-fix-a-use-after-free-problem-in-rxe_mmap.patch
new file mode 100644 (file)
index 0000000..b329deb
--- /dev/null
@@ -0,0 +1,166 @@
+From 6d97b8d82a84c782b3e17770ce2f8e006b31c9e4 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 14 Aug 2026 13:23:59 -0700
+Subject: RDMA/rxe: Fix a use-after-free problem in rxe_mmap
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Zhu Yanjun <yanjun.zhu@linux.dev>
+
+[ Upstream commit 35744ab3d03c5fca8c1752f53fc8fc674e14c561 ]
+
+rxe_mmap() removes a rxe_mmap_info struct from the pending_mmaps list
+and releases pending_lock while the struct's kref is still at 1:
+
+   list_del_init(&ip->pending_mmaps);
+   spin_unlock_bh(&rxe->pending_lock);   /* ref == 1, no lock held */
+   ret = remap_vmalloc_range(vma, ip->obj, 0);  /* walks PTEs */
+   [...]
+   rxe_vma_open(vma);                    /* kref_get, ref â†’ 2 */
+   remap_vmalloc_range_partial() walks PTEs without any lock.
+
+A concurrent DESTROY_CQ ioctl on another CPU calls:
+
+    kref_put(&q->ip->ref, rxe_mmap_release)   /* ref 1→0 */
+    vfree(ip->obj)   /* clears vmalloc PTEs mid-walk */
+    kfree(ip)        /* frees rxe_mmap_info */
+
+This yields:
+
+   1. Kernel crash, vmalloc_to_page() returns NULL when vfree wins the
+   per-PTE race -> vm_insert_page(NULL) â†’ GPF in validate_page_before_insert
+
+   2. Page UAF, vmalloc_to_page() reads a stale PTE before vfree clears
+   it. User VMA holds a PTE to a free'd page which might eventually get
+   reallocated later by vmalloc which allows the attacker to get a clean
+   page-level UAF.
+
+   It is worth noting that even though a page-level UAF is possible given
+   the strong primitive, it is statistically very difficult to achieve
+   given the very short time window (after the last insert_page and before
+   the kref_get).
+
+The call trace are as below:
+
+  Oops: general protection fault, probably for non-canonical address 0xdffffc0000000001: 0000 [#1] SMP KASAN NOPTI
+  KASAN: null-ptr-deref in range [0x0000000000000008-0x000000000000000f]
+  CPU: 0 UID: 1000 PID: 413 Comm: poc Not tainted 7.0.0-rc5-dirty #28 PREEMPT(lazy)
+  Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.15.0-1 04/01/2014
+  RIP: 0010:validate_page_before_insert+0x32/0x300
+  Code: e5 41 57 41 56 49 89 fe 41 55 41 54 53 48 89 f3 e8 93 b5 a3 ff 48 8d 7b 08 48 b8 00 00 00 00 00 fc ff df 48 89 fa 48 c1 ea 03 <80> 3c 02 00 0f 85 7b 02 00 00 4c 8b 63 08 31 ff 4d 89 e5 41 83 e5
+  RSP: 0018:ffff88811b15f2f0 EFLAGS: 00000202
+  RAX: dffffc0000000000 RBX: 0000000000000000 RCX: 0000000000000000
+  RDX: 0000000000000001 RSI: 0000000000000000 RDI: 0000000000000008
+  RBP: ffff88811b15f318 R08: 0000000000000000 R09: 0000000000000000
+  R10: 0000000000000000 R11: 0000000000000000 R12: ffff8881181eee00
+  R13: 0000000000000000 R14: ffff8881181eee00 R15: ffff8881181eee20
+  FS:  00007b1e000f76c0(0000) GS:ffff8884268e0000(0000) knlGS:0000000000000000
+  CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+  CR2: 00007b1e00a24ac0 CR3: 0000000116eb3000 CR4: 00000000000006f0
+  Call Trace:
+   <TASK>
+   insert_page+0x8f/0x190
+   ? __pfx_insert_page+0x10/0x10
+   ? kasan_save_alloc_info+0x38/0x60
+   vm_insert_page+0x2e7/0x400
+   remap_vmalloc_range_partial+0x212/0x3e0
+   remap_vmalloc_range+0x6e/0xb0
+   ? __kasan_check_write+0x14/0x30
+   rxe_mmap+0x2e9/0x5d0
+   ib_uverbs_mmap+0x1ad/0x2c0
+   __mmap_region+0x12c2/0x2ad0
+   ? __pfx___mmap_region+0x10/0x10
+   ? __sanitizer_cov_trace_switch+0x58/0xb0
+   ? mas_prev_slot+0x360/0x39c0
+   ? __sanitizer_cov_trace_switch+0x58/0xb0
+   ? mas_next_slot+0x1e5b/0x2f40
+   ? __sanitizer_cov_trace_cmp8+0x18/0x30
+   ? unmapped_area_topdown+0x4dd/0x610
+   ? kfree+0x1b1/0x440
+   ? free_cpumask_var+0x16/0x30
+   ? __kasan_slab_free+0x7d/0xa0
+   ? __sanitizer_cov_trace_cmp8+0x18/0x30
+   mmap_region+0x2e6/0x3c0
+   do_mmap+0xa3e/0x12a0
+   ? __pfx_do_mmap+0x10/0x10
+   ? __kasan_check_write+0x14/0x30
+   ? down_write_killable+0xba/0x160
+   ? __pfx_down_write_killable+0x10/0x10
+   ? __sanitizer_cov_trace_cmp4+0x16/0x30
+   vm_mmap_pgoff+0x2d4/0x4a0
+   ? __pfx_vm_mmap_pgoff+0x10/0x10
+   ? fget+0x1bf/0x270
+   ksys_mmap_pgoff+0x40c/0x690
+   ? __sanitizer_cov_trace_const_cmp4+0x16/0x30
+   ? __pfx_ksys_mmap_pgoff+0x10/0x10
+   ? __kasan_check_write+0x14/0x30
+   ? _raw_spin_trylock+0xbb/0x130
+   ? __pfx__raw_spin_trylock+0x10/0x10
+   __x64_sys_mmap+0x135/0x1e0
+   x64_sys_call+0x1c14/0x2790
+   do_syscall_64+0xd2/0x1050
+   ? rcu_core+0x352/0x7d0
+   ? rcu_core_si+0xe/0x20
+   ? handle_softirqs+0x1aa/0x650
+   ? __sanitizer_cov_trace_cmp4+0x16/0x30
+   ? fpregs_assert_state_consistent+0xe1/0x160
+   ? irqentry_exit+0xb1/0x670
+   entry_SYSCALL_64_after_hwframe+0x76/0x7e
+
+Link: https://patch.msgid.link/r/20260515002537.6209-1-yanjun.zhu@linux.dev
+Reported-and-tested-by: nasm <n4sm@protonmail.com>
+Suggested-by: nasm <n4sm@protonmail.com>
+Fixes: 8700e3e7c485 ("Soft RoCE driver")
+Signed-off-by: Zhu Yanjun <yanjun.zhu@linux.dev>
+Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
+(cherry picked from commit 35744ab3d03c5fca8c1752f53fc8fc674e14c561)
+[Harshit: Minor conflict resolution pr_err() vs rxe_dbg_dev() usage]
+Signed-off-by: Harshit Mogalapalli <harshit.m.mogalapalli@oracle.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/infiniband/sw/rxe/rxe_mmap.c | 19 ++++++++++++++++---
+ 1 file changed, 16 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/infiniband/sw/rxe/rxe_mmap.c b/drivers/infiniband/sw/rxe/rxe_mmap.c
+index 9149b60954296..2749ed48b014a 100644
+--- a/drivers/infiniband/sw/rxe/rxe_mmap.c
++++ b/drivers/infiniband/sw/rxe/rxe_mmap.c
+@@ -93,18 +93,31 @@ int rxe_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
+       goto done;
+ found_it:
++      /*
++       * Increment refcount and check whether it is being freed atm while
++       * holding lock to prevent UAF
++       */
++      if (!kref_get_unless_zero(&ip->ref)) {
++              spin_unlock_bh(&rxe->pending_lock);
++              ret = -ENXIO;
++              goto done;
++      }
++
+       list_del_init(&ip->pending_mmaps);
+       spin_unlock_bh(&rxe->pending_lock);
++      vma->vm_ops = &rxe_vm_ops;
++      vma->vm_private_data = ip;
++
+       ret = remap_vmalloc_range(vma, ip->obj, 0);
+       if (ret) {
++              vma->vm_private_data = NULL;
++              vma->vm_ops = NULL;
++              kref_put(&ip->ref, rxe_mmap_release);
+               pr_err("err %d from remap_vmalloc_range\n", ret);
+               goto done;
+       }
+-      vma->vm_ops = &rxe_vm_ops;
+-      vma->vm_private_data = ip;
+-      rxe_vma_open(vma);
+ done:
+       return ret;
+ }
+-- 
+2.53.0
+
diff --git a/queue-6.1/selftests-bpf-adapt-sockmap-update-error-handling.patch b/queue-6.1/selftests-bpf-adapt-sockmap-update-error-handling.patch
new file mode 100644 (file)
index 0000000..c3f7ebf
--- /dev/null
@@ -0,0 +1,92 @@
+From 676d49ec011c70b9563b0054f0aa2db2747761ff Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 7 Jul 2026 06:23:58 +0200
+Subject: selftests/bpf: Adapt sockmap update error handling
+
+From: Michal Luczaj <mhal@rbox.co>
+
+[ Upstream commit 30581eda4a07ff15db623612cac578e81869e96f ]
+
+Update sockmap_listen to accommodate the recent change in sockmap that
+rejects unbound UDP sockets.
+
+TCP: Reject unbound and bound (unless established or listening).
+UDP: Accept only bound sockets.
+
+While at it, migrate to ASSERT_* and enforce reverse xmas tree.
+
+Signed-off-by: Michal Luczaj <mhal@rbox.co>
+Reviewed-by: Kuniyuki Iwashima <kuniyu@google.com>
+Reviewed-by: Jakub Sitnicki <jakub@cloudflare.com>
+Link: https://lore.kernel.org/bpf/20260707-sockmap-lookup-udp-leak-v4-3-f878346f27ab@rbox.co
+Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../selftests/bpf/prog_tests/sockmap_listen.c | 21 ++++++++++---------
+ 1 file changed, 11 insertions(+), 10 deletions(-)
+
+diff --git a/tools/testing/selftests/bpf/prog_tests/sockmap_listen.c b/tools/testing/selftests/bpf/prog_tests/sockmap_listen.c
+index cef5d35951711..2112b01a4b03a 100644
+--- a/tools/testing/selftests/bpf/prog_tests/sockmap_listen.c
++++ b/tools/testing/selftests/bpf/prog_tests/sockmap_listen.c
+@@ -341,8 +341,8 @@ static void test_insert_invalid(int family, int sotype, int mapfd)
+ static void test_insert_opened(int family, int sotype, int mapfd)
+ {
+       u32 key = 0;
+-      u64 value;
+       int err, s;
++      u64 value;
+       s = xsocket(family, sotype, 0);
+       if (s == -1)
+@@ -351,11 +351,8 @@ static void test_insert_opened(int family, int sotype, int mapfd)
+       errno = 0;
+       value = s;
+       err = bpf_map_update_elem(mapfd, &key, &value, BPF_NOEXIST);
+-      if (sotype == SOCK_STREAM) {
+-              if (!err || errno != EOPNOTSUPP)
+-                      FAIL_ERRNO("map_update: expected EOPNOTSUPP");
+-      } else if (err)
+-              FAIL_ERRNO("map_update: expected success");
++      ASSERT_ERR(err, "map_update");
++      ASSERT_EQ(errno, EOPNOTSUPP, "errno");
+       xclose(s);
+ }
+@@ -364,8 +361,8 @@ static void test_insert_bound(int family, int sotype, int mapfd)
+       struct sockaddr_storage addr;
+       socklen_t len;
+       u32 key = 0;
+-      u64 value;
+       int err, s;
++      u64 value;
+       init_addr_loopback(family, &addr, &len);
+@@ -380,8 +377,12 @@ static void test_insert_bound(int family, int sotype, int mapfd)
+       errno = 0;
+       value = s;
+       err = bpf_map_update_elem(mapfd, &key, &value, BPF_NOEXIST);
+-      if (!err || errno != EOPNOTSUPP)
+-              FAIL_ERRNO("map_update: expected EOPNOTSUPP");
++      if (sotype == SOCK_STREAM) {
++              ASSERT_ERR(err, "map_update");
++              ASSERT_EQ(errno, EOPNOTSUPP, "errno");
++      } else {
++              ASSERT_OK(err, "map_update");
++      }
+ close:
+       xclose(s);
+ }
+@@ -1480,7 +1481,7 @@ static void test_ops(struct test_sockmap_listen *skel, struct bpf_map *map,
+               /* insert */
+               TEST(test_insert_invalid),
+               TEST(test_insert_opened),
+-              TEST(test_insert_bound, SOCK_STREAM),
++              TEST(test_insert_bound),
+               TEST(test_insert),
+               /* delete */
+               TEST(test_delete_after_insert),
+-- 
+2.53.0
+
diff --git a/queue-6.1/selftests-bpf-fail-unbound-udp-on-sockmap-update.patch b/queue-6.1/selftests-bpf-fail-unbound-udp-on-sockmap-update.patch
new file mode 100644 (file)
index 0000000..59814b1
--- /dev/null
@@ -0,0 +1,55 @@
+From f792f83a4123bfa0cbc617b53ac85f5ee56f64e3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 7 Jul 2026 06:23:59 +0200
+Subject: selftests/bpf: Fail unbound UDP on sockmap update
+
+From: Michal Luczaj <mhal@rbox.co>
+
+[ Upstream commit 203b06932777b9ad5085319389dea566f5c2ca63 ]
+
+sockmap now rejects unbound UDP sockets. Adjust test_maps. While at it,
+check socket()'s return value.
+
+This effectively reverts commit c39aa2159974 ("bpf, selftests: Fix
+test_maps now that sockmap supports UDP").
+
+Signed-off-by: Michal Luczaj <mhal@rbox.co>
+Reviewed-by: Kuniyuki Iwashima <kuniyu@google.com>
+Reviewed-by: Jakub Sitnicki <jakub@cloudflare.com>
+Link: https://lore.kernel.org/bpf/20260707-sockmap-lookup-udp-leak-v4-4-f878346f27ab@rbox.co
+Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ tools/testing/selftests/bpf/test_maps.c | 13 ++++++-------
+ 1 file changed, 6 insertions(+), 7 deletions(-)
+
+diff --git a/tools/testing/selftests/bpf/test_maps.c b/tools/testing/selftests/bpf/test_maps.c
+index 81cd48cc80c23..73878ec8ec7d0 100644
+--- a/tools/testing/selftests/bpf/test_maps.c
++++ b/tools/testing/selftests/bpf/test_maps.c
+@@ -752,16 +752,15 @@ static void test_sockmap(unsigned int tasks, void *data)
+               goto out_sockmap;
+       }
+-      /* Test update with unsupported UDP socket */
++      /* Test update with unsupported unbound UDP socket */
+       udp = socket(AF_INET, SOCK_DGRAM, 0);
+-      i = 0;
+-      err = bpf_map_update_elem(fd, &i, &udp, BPF_ANY);
+-      if (err) {
+-              printf("Failed socket update SOCK_DGRAM '%i:%i'\n",
+-                     i, udp);
++      CHECK(udp < 0, "socket(AF_INET, SOCK_DGRAM)", "errno:%d\n", errno);
++      err = bpf_map_update_elem(fd, &(int){0}, &udp, BPF_ANY);
++      close(udp);
++      if (!err) {
++              printf("Unexpectedly succeeded unbound UDP update '0:%i'\n", udp);
+               goto out_sockmap;
+       }
+-      close(udp);
+       /* Test update without programs */
+       for (i = 0; i < 6; i++) {
+-- 
+2.53.0
+
index 5540a5059aed05e3d32652b2fcc636a94d49112f..964263ce86bf64bd8782c54d74ea3e4476855078 100644 (file)
@@ -550,3 +550,7 @@ futex-prevent-robust-futex-exit-race-some-more.patch
 fortify-refactor-test_fortify-makefile-to-fix-some-b.patch
 fortify-disable-wstringop-overread-in-tests.patch
 pinctrl-renesas-rzg2l-use-enotsupp-instead-of-eopnot.patch
+rdma-rxe-fix-a-use-after-free-problem-in-rxe_mmap.patch
+fscrypt-replace-mk_users-keyring-with-simple-list.patch
+selftests-bpf-adapt-sockmap-update-error-handling.patch
+selftests-bpf-fail-unbound-udp-on-sockmap-update.patch
diff --git a/queue-6.12/selftests-bpf-adapt-sockmap-update-error-handling.patch b/queue-6.12/selftests-bpf-adapt-sockmap-update-error-handling.patch
new file mode 100644 (file)
index 0000000..1345769
--- /dev/null
@@ -0,0 +1,92 @@
+From de5a0c4a4ae0202b97eba7018dba6fbb67a21b54 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 7 Jul 2026 06:23:58 +0200
+Subject: selftests/bpf: Adapt sockmap update error handling
+
+From: Michal Luczaj <mhal@rbox.co>
+
+[ Upstream commit 30581eda4a07ff15db623612cac578e81869e96f ]
+
+Update sockmap_listen to accommodate the recent change in sockmap that
+rejects unbound UDP sockets.
+
+TCP: Reject unbound and bound (unless established or listening).
+UDP: Accept only bound sockets.
+
+While at it, migrate to ASSERT_* and enforce reverse xmas tree.
+
+Signed-off-by: Michal Luczaj <mhal@rbox.co>
+Reviewed-by: Kuniyuki Iwashima <kuniyu@google.com>
+Reviewed-by: Jakub Sitnicki <jakub@cloudflare.com>
+Link: https://lore.kernel.org/bpf/20260707-sockmap-lookup-udp-leak-v4-3-f878346f27ab@rbox.co
+Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../selftests/bpf/prog_tests/sockmap_listen.c | 21 ++++++++++---------
+ 1 file changed, 11 insertions(+), 10 deletions(-)
+
+diff --git a/tools/testing/selftests/bpf/prog_tests/sockmap_listen.c b/tools/testing/selftests/bpf/prog_tests/sockmap_listen.c
+index 1cfed83156b03..b04b8188b1514 100644
+--- a/tools/testing/selftests/bpf/prog_tests/sockmap_listen.c
++++ b/tools/testing/selftests/bpf/prog_tests/sockmap_listen.c
+@@ -53,8 +53,8 @@ static void test_insert_opened(struct test_sockmap_listen *skel __always_unused,
+                              int family, int sotype, int mapfd)
+ {
+       u32 key = 0;
+-      u64 value;
+       int err, s;
++      u64 value;
+       s = xsocket(family, sotype, 0);
+       if (s == -1)
+@@ -63,11 +63,8 @@ static void test_insert_opened(struct test_sockmap_listen *skel __always_unused,
+       errno = 0;
+       value = s;
+       err = bpf_map_update_elem(mapfd, &key, &value, BPF_NOEXIST);
+-      if (sotype == SOCK_STREAM) {
+-              if (!err || errno != EOPNOTSUPP)
+-                      FAIL_ERRNO("map_update: expected EOPNOTSUPP");
+-      } else if (err)
+-              FAIL_ERRNO("map_update: expected success");
++      ASSERT_ERR(err, "map_update");
++      ASSERT_EQ(errno, EOPNOTSUPP, "errno");
+       xclose(s);
+ }
+@@ -77,8 +74,8 @@ static void test_insert_bound(struct test_sockmap_listen *skel __always_unused,
+       struct sockaddr_storage addr;
+       socklen_t len = 0;
+       u32 key = 0;
+-      u64 value;
+       int err, s;
++      u64 value;
+       init_addr_loopback(family, &addr, &len);
+@@ -93,8 +90,12 @@ static void test_insert_bound(struct test_sockmap_listen *skel __always_unused,
+       errno = 0;
+       value = s;
+       err = bpf_map_update_elem(mapfd, &key, &value, BPF_NOEXIST);
+-      if (!err || errno != EOPNOTSUPP)
+-              FAIL_ERRNO("map_update: expected EOPNOTSUPP");
++      if (sotype == SOCK_STREAM) {
++              ASSERT_ERR(err, "map_update");
++              ASSERT_EQ(errno, EOPNOTSUPP, "errno");
++      } else {
++              ASSERT_OK(err, "map_update");
++      }
+ close:
+       xclose(s);
+ }
+@@ -1289,7 +1290,7 @@ static void test_ops(struct test_sockmap_listen *skel, struct bpf_map *map,
+               /* insert */
+               TEST(test_insert_invalid),
+               TEST(test_insert_opened),
+-              TEST(test_insert_bound, SOCK_STREAM),
++              TEST(test_insert_bound),
+               TEST(test_insert),
+               /* delete */
+               TEST(test_delete_after_insert),
+-- 
+2.53.0
+
diff --git a/queue-6.12/selftests-bpf-ensure-udp-sockets-are-bound.patch b/queue-6.12/selftests-bpf-ensure-udp-sockets-are-bound.patch
new file mode 100644 (file)
index 0000000..d419a6d
--- /dev/null
@@ -0,0 +1,56 @@
+From 8cf293a8d6d96dd7fc12163be0dbe030c70bc9b9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 7 Jul 2026 06:23:56 +0200
+Subject: selftests/bpf: Ensure UDP sockets are bound
+
+From: Michal Luczaj <mhal@rbox.co>
+
+[ Upstream commit fe3ff273767ef22fe8a7cb3816f264927c190e50 ]
+
+Update sockmap_basic tests to bind sockets before they are used. This
+accommodates the recent change in sockmap that rejects unbound UDP sockets.
+
+Signed-off-by: Michal Luczaj <mhal@rbox.co>
+Reviewed-by: Kuniyuki Iwashima <kuniyu@google.com>
+Reviewed-by: Jakub Sitnicki <jakub@cloudflare.com>
+Link: https://lore.kernel.org/bpf/20260707-sockmap-lookup-udp-leak-v4-1-f878346f27ab@rbox.co
+Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ tools/testing/selftests/bpf/prog_tests/sockmap_basic.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/tools/testing/selftests/bpf/prog_tests/sockmap_basic.c b/tools/testing/selftests/bpf/prog_tests/sockmap_basic.c
+index fb08c565d6aad..99522cf68dc8c 100644
+--- a/tools/testing/selftests/bpf/prog_tests/sockmap_basic.c
++++ b/tools/testing/selftests/bpf/prog_tests/sockmap_basic.c
+@@ -703,7 +703,7 @@ static void test_sockmap_many_socket(void)
+               return;
+       }
+-      udp = xsocket(AF_INET, SOCK_DGRAM | SOCK_NONBLOCK, 0);
++      udp = socket_loopback(AF_INET, SOCK_DGRAM | SOCK_NONBLOCK);
+       if (udp < 0) {
+               close(dgram);
+               close(tcp);
+@@ -772,7 +772,7 @@ static void test_sockmap_many_maps(void)
+               return;
+       }
+-      udp = xsocket(AF_INET, SOCK_DGRAM | SOCK_NONBLOCK, 0);
++      udp = socket_loopback(AF_INET, SOCK_DGRAM | SOCK_NONBLOCK);
+       if (udp < 0) {
+               close(dgram);
+               close(tcp);
+@@ -843,7 +843,7 @@ static void test_sockmap_same_sock(void)
+               return;
+       }
+-      udp = xsocket(AF_INET, SOCK_DGRAM | SOCK_NONBLOCK, 0);
++      udp = socket_loopback(AF_INET, SOCK_DGRAM | SOCK_NONBLOCK);
+       if (udp < 0) {
+               close(dgram);
+               close(tcp);
+-- 
+2.53.0
+
index 4606336adb38d00cbea48b1d0d280e87d21e8b8d..ec94fdb6ae303e7121711daa9fcf0b3e59a732c4 100644 (file)
@@ -99,3 +99,5 @@ futex-prevent-robust-futex-exit-race-some-more.patch
 kunit-fortify-replace-volatile-with-optimizer_hide_v.patch
 kunit-fortify-add-back-volatile-for-sizeof-constants.patch
 pinctrl-renesas-rzg2l-use-enotsupp-instead-of-eopnot.patch
+selftests-bpf-ensure-udp-sockets-are-bound.patch
+selftests-bpf-adapt-sockmap-update-error-handling.patch
diff --git a/queue-6.18/selftests-bpf-adapt-sockmap-update-error-handling.patch b/queue-6.18/selftests-bpf-adapt-sockmap-update-error-handling.patch
new file mode 100644 (file)
index 0000000..a9f6454
--- /dev/null
@@ -0,0 +1,92 @@
+From 2c63bc8380241946ff7004e8471ff29c29601cbe Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 7 Jul 2026 06:23:58 +0200
+Subject: selftests/bpf: Adapt sockmap update error handling
+
+From: Michal Luczaj <mhal@rbox.co>
+
+[ Upstream commit 30581eda4a07ff15db623612cac578e81869e96f ]
+
+Update sockmap_listen to accommodate the recent change in sockmap that
+rejects unbound UDP sockets.
+
+TCP: Reject unbound and bound (unless established or listening).
+UDP: Accept only bound sockets.
+
+While at it, migrate to ASSERT_* and enforce reverse xmas tree.
+
+Signed-off-by: Michal Luczaj <mhal@rbox.co>
+Reviewed-by: Kuniyuki Iwashima <kuniyu@google.com>
+Reviewed-by: Jakub Sitnicki <jakub@cloudflare.com>
+Link: https://lore.kernel.org/bpf/20260707-sockmap-lookup-udp-leak-v4-3-f878346f27ab@rbox.co
+Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../selftests/bpf/prog_tests/sockmap_listen.c | 21 ++++++++++---------
+ 1 file changed, 11 insertions(+), 10 deletions(-)
+
+diff --git a/tools/testing/selftests/bpf/prog_tests/sockmap_listen.c b/tools/testing/selftests/bpf/prog_tests/sockmap_listen.c
+index f1bdccc7e4e79..0a744f786e107 100644
+--- a/tools/testing/selftests/bpf/prog_tests/sockmap_listen.c
++++ b/tools/testing/selftests/bpf/prog_tests/sockmap_listen.c
+@@ -53,8 +53,8 @@ static void test_insert_opened(struct test_sockmap_listen *skel __always_unused,
+                              int family, int sotype, int mapfd)
+ {
+       u32 key = 0;
+-      u64 value;
+       int err, s;
++      u64 value;
+       s = xsocket(family, sotype, 0);
+       if (s == -1)
+@@ -63,11 +63,8 @@ static void test_insert_opened(struct test_sockmap_listen *skel __always_unused,
+       errno = 0;
+       value = s;
+       err = bpf_map_update_elem(mapfd, &key, &value, BPF_NOEXIST);
+-      if (sotype == SOCK_STREAM) {
+-              if (!err || errno != EOPNOTSUPP)
+-                      FAIL_ERRNO("map_update: expected EOPNOTSUPP");
+-      } else if (err)
+-              FAIL_ERRNO("map_update: expected success");
++      ASSERT_ERR(err, "map_update");
++      ASSERT_EQ(errno, EOPNOTSUPP, "errno");
+       xclose(s);
+ }
+@@ -77,8 +74,8 @@ static void test_insert_bound(struct test_sockmap_listen *skel __always_unused,
+       struct sockaddr_storage addr;
+       socklen_t len = 0;
+       u32 key = 0;
+-      u64 value;
+       int err, s;
++      u64 value;
+       init_addr_loopback(family, &addr, &len);
+@@ -93,8 +90,12 @@ static void test_insert_bound(struct test_sockmap_listen *skel __always_unused,
+       errno = 0;
+       value = s;
+       err = bpf_map_update_elem(mapfd, &key, &value, BPF_NOEXIST);
+-      if (!err || errno != EOPNOTSUPP)
+-              FAIL_ERRNO("map_update: expected EOPNOTSUPP");
++      if (sotype == SOCK_STREAM) {
++              ASSERT_ERR(err, "map_update");
++              ASSERT_EQ(errno, EOPNOTSUPP, "errno");
++      } else {
++              ASSERT_OK(err, "map_update");
++      }
+ close:
+       xclose(s);
+ }
+@@ -1289,7 +1290,7 @@ static void test_ops(struct test_sockmap_listen *skel, struct bpf_map *map,
+               /* insert */
+               TEST(test_insert_invalid),
+               TEST(test_insert_opened),
+-              TEST(test_insert_bound, SOCK_STREAM),
++              TEST(test_insert_bound),
+               TEST(test_insert),
+               /* delete */
+               TEST(test_delete_after_insert),
+-- 
+2.53.0
+
diff --git a/queue-6.18/selftests-bpf-ensure-udp-sockets-are-bound.patch b/queue-6.18/selftests-bpf-ensure-udp-sockets-are-bound.patch
new file mode 100644 (file)
index 0000000..cba7ae6
--- /dev/null
@@ -0,0 +1,56 @@
+From 55a1723b5c60cccdd2b3c8de351744d761684970 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 7 Jul 2026 06:23:56 +0200
+Subject: selftests/bpf: Ensure UDP sockets are bound
+
+From: Michal Luczaj <mhal@rbox.co>
+
+[ Upstream commit fe3ff273767ef22fe8a7cb3816f264927c190e50 ]
+
+Update sockmap_basic tests to bind sockets before they are used. This
+accommodates the recent change in sockmap that rejects unbound UDP sockets.
+
+Signed-off-by: Michal Luczaj <mhal@rbox.co>
+Reviewed-by: Kuniyuki Iwashima <kuniyu@google.com>
+Reviewed-by: Jakub Sitnicki <jakub@cloudflare.com>
+Link: https://lore.kernel.org/bpf/20260707-sockmap-lookup-udp-leak-v4-1-f878346f27ab@rbox.co
+Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ tools/testing/selftests/bpf/prog_tests/sockmap_basic.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/tools/testing/selftests/bpf/prog_tests/sockmap_basic.c b/tools/testing/selftests/bpf/prog_tests/sockmap_basic.c
+index 1e3e4392dcca0..54fd84203dc2b 100644
+--- a/tools/testing/selftests/bpf/prog_tests/sockmap_basic.c
++++ b/tools/testing/selftests/bpf/prog_tests/sockmap_basic.c
+@@ -786,7 +786,7 @@ static void test_sockmap_many_socket(void)
+               return;
+       }
+-      udp = xsocket(AF_INET, SOCK_DGRAM | SOCK_NONBLOCK, 0);
++      udp = socket_loopback(AF_INET, SOCK_DGRAM | SOCK_NONBLOCK);
+       if (udp < 0) {
+               close(dgram);
+               close(tcp);
+@@ -855,7 +855,7 @@ static void test_sockmap_many_maps(void)
+               return;
+       }
+-      udp = xsocket(AF_INET, SOCK_DGRAM | SOCK_NONBLOCK, 0);
++      udp = socket_loopback(AF_INET, SOCK_DGRAM | SOCK_NONBLOCK);
+       if (udp < 0) {
+               close(dgram);
+               close(tcp);
+@@ -926,7 +926,7 @@ static void test_sockmap_same_sock(void)
+               return;
+       }
+-      udp = xsocket(AF_INET, SOCK_DGRAM | SOCK_NONBLOCK, 0);
++      udp = socket_loopback(AF_INET, SOCK_DGRAM | SOCK_NONBLOCK);
+       if (udp < 0) {
+               close(dgram);
+               close(tcp);
+-- 
+2.53.0
+
index c47cecae67f43b8a7948e5cd40ed6f0e459489b9..0b49004922ccc5fb6b43357800e2d65158a47fee 100644 (file)
@@ -135,3 +135,5 @@ futex-prevent-robust-futex-exit-race-some-more.patch
 netfilter-nf_tables-avoid-softlockup-warnings-in-nft.patch
 bluetooth-btrtl-fix-rtl8761b-bu-broken-le-extended-s.patch
 bluetooth-btusb-add-tp-link-ub600-for-realtek-8761bu.patch
+selftests-bpf-ensure-udp-sockets-are-bound.patch
+selftests-bpf-adapt-sockmap-update-error-handling.patch
diff --git a/queue-6.6/fscrypt-replace-mk_users-keyring-with-simple-list.patch b/queue-6.6/fscrypt-replace-mk_users-keyring-with-simple-list.patch
new file mode 100644 (file)
index 0000000..d77833a
--- /dev/null
@@ -0,0 +1,448 @@
+From 02d650b855a6ece429f82bf4893991155e53dff1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 15 Aug 2026 11:30:36 -0700
+Subject: fscrypt: Replace mk_users keyring with simple list
+
+From: Eric Biggers <ebiggers@kernel.org>
+
+commit 696c030e1e3438955aba443b308ee8b6faa3983e upstream.
+
+Change mk_users (the set of user claims to an fscrypt master key) from a
+'struct key' keyring to a simple linked list.
+
+It's still a collection of 'struct key' for quota tracking.  It was
+originally thought to be natural that a collection of 'struct key'
+should be held in a 'struct key' keyring.  In reality, it's just been
+causing problems, similar to how using 'struct key' for the filesystem
+keyring caused problems and was removed in commit d7e7b9af104c
+("fscrypt: stop using keyrings subsystem for fscrypt_master_key").
+
+Commit d3a7bd420076 ("fscrypt: clear keyring before calling key_put()")
+fixed mk_users cleanup to be synchronous.  But that apparently wasn't
+enough: the keyring subsystem's redundant locking is still generating
+lockdep false positives due to the interaction with filesystem reclaim.
+
+With the simple list, the redundant locking and lockdep issue goes away.
+
+Of course, searching a linked list is linear-time whereas the
+'struct key' keyring used a fancy constant-time associative array.  But
+that's fine here, since in practice there's just one entry in the list.
+In fact the new code is much faster in practice, since it's much smaller
+and doesn't have to convert the kuid_t into a string to search for it.
+
+Reported-by: syzbot+f55b043dacf43776b50c@syzkaller.appspotmail.com
+Closes: https://syzkaller.appspot.com/bug?extid=f55b043dacf43776b50c
+Reported-by: Mohammed EL Kadiri <med08elkadiri@gmail.com>
+Closes: https://lore.kernel.org/keyrings/20260614150041.21172-1-med08elkadiri@gmail.com/
+Fixes: 23c688b54016 ("fscrypt: allow unprivileged users to add/remove keys for v2 policies")
+Cc: stable@vger.kernel.org
+Link: https://patch.msgid.link/20260618221921.87896-1-ebiggers@kernel.org
+Signed-off-by: Eric Biggers <ebiggers@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/crypto/fscrypt_private.h |  32 ++++--
+ fs/crypto/keyring.c         | 212 ++++++++++++++++--------------------
+ 2 files changed, 113 insertions(+), 131 deletions(-)
+
+diff --git a/fs/crypto/fscrypt_private.h b/fs/crypto/fscrypt_private.h
+index 14b26036055e4..8be25746fd72e 100644
+--- a/fs/crypto/fscrypt_private.h
++++ b/fs/crypto/fscrypt_private.h
+@@ -422,6 +422,19 @@ fscrypt_is_key_prepared(struct fscrypt_prepared_key *prep_key,
+ /* 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
+  */
+@@ -506,19 +519,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.
++       * 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.
+        *
+-       * This is NULL for v1 policy keys; those can only be added by root.
++       * 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.  (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 ->mk_secret.)
++       * 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
+diff --git a/fs/crypto/keyring.c b/fs/crypto/keyring.c
+index 7cbb1fd872acc..f2a0d89d5f5e1 100644
+--- a/fs/crypto/keyring.c
++++ b/fs/crypto/keyring.c
+@@ -64,18 +64,19 @@ static void fscrypt_free_master_key(struct rcu_head *head)
+       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);
+-      key_put(mk->mk_users);
+-      mk->mk_users = NULL;
++      clear_mk_users(mk);
+       call_rcu(&mk->mk_rcu_head, fscrypt_free_master_key);
+ }
+@@ -145,8 +146,8 @@ static void fscrypt_user_key_describe(const struct key *key, struct seq_file *m)
+ }
+ /*
+- * 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
+@@ -160,30 +161,9 @@ static struct key_type key_type_fscrypt_user = {
+       .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)
+ {
+@@ -319,91 +299,94 @@ fscrypt_find_master_key(struct super_block *sb,
+       return mk;
+ }
+-static int allocate_master_key_users_keyring(struct fscrypt_master_key *mk)
++/* 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)
+ {
+-      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;
+-}
++      struct fscrypt_master_key_user *mk_user;
++      kuid_t uid = current_fsuid();
+-/*
+- * 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);
++      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;
++      }
+-      err = key_instantiate_and_link(mk_user, NULL, 0, mk->mk_users, NULL);
+-      key_put(mk_user);
+-      return err;
++      mk_user = kzalloc(sizeof(*mk_user), GFP_KERNEL);
++      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;
++}
++
++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);
+ }
+ /*
+@@ -426,13 +409,12 @@ static int add_new_master_key(struct super_block *sb,
+       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);
+       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;
+@@ -460,19 +442,13 @@ static int add_existing_master_key(struct fscrypt_master_key *mk,
+       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;
+@@ -819,7 +795,6 @@ int fscrypt_verify_key_added(struct super_block *sb,
+ {
+       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;
+@@ -831,13 +806,10 @@ int fscrypt_verify_key_added(struct super_block *sb,
+               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:
+@@ -1030,16 +1002,18 @@ static int do_remove_key(struct file *filp, void __user *_uarg, bool all_users)
+       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
+@@ -1127,6 +1101,8 @@ int fscrypt_ioctl_get_key_status(struct file *filp, void __user *uarg)
+       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)))
+@@ -1159,19 +1135,13 @@ int fscrypt_ioctl_get_key_status(struct file *filp, void __user *uarg)
+       }
+       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:
+-- 
+2.53.0
+
diff --git a/queue-6.6/selftests-bpf-adapt-sockmap-update-error-handling.patch b/queue-6.6/selftests-bpf-adapt-sockmap-update-error-handling.patch
new file mode 100644 (file)
index 0000000..04359c2
--- /dev/null
@@ -0,0 +1,92 @@
+From 6d6059bf544170964a2ca38cb99a494fe19377c5 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 7 Jul 2026 06:23:58 +0200
+Subject: selftests/bpf: Adapt sockmap update error handling
+
+From: Michal Luczaj <mhal@rbox.co>
+
+[ Upstream commit 30581eda4a07ff15db623612cac578e81869e96f ]
+
+Update sockmap_listen to accommodate the recent change in sockmap that
+rejects unbound UDP sockets.
+
+TCP: Reject unbound and bound (unless established or listening).
+UDP: Accept only bound sockets.
+
+While at it, migrate to ASSERT_* and enforce reverse xmas tree.
+
+Signed-off-by: Michal Luczaj <mhal@rbox.co>
+Reviewed-by: Kuniyuki Iwashima <kuniyu@google.com>
+Reviewed-by: Jakub Sitnicki <jakub@cloudflare.com>
+Link: https://lore.kernel.org/bpf/20260707-sockmap-lookup-udp-leak-v4-3-f878346f27ab@rbox.co
+Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../selftests/bpf/prog_tests/sockmap_listen.c | 21 ++++++++++---------
+ 1 file changed, 11 insertions(+), 10 deletions(-)
+
+diff --git a/tools/testing/selftests/bpf/prog_tests/sockmap_listen.c b/tools/testing/selftests/bpf/prog_tests/sockmap_listen.c
+index a6d8aa8c2a9ac..6386d6069b9db 100644
+--- a/tools/testing/selftests/bpf/prog_tests/sockmap_listen.c
++++ b/tools/testing/selftests/bpf/prog_tests/sockmap_listen.c
+@@ -51,8 +51,8 @@ static void test_insert_opened(struct test_sockmap_listen *skel __always_unused,
+                              int family, int sotype, int mapfd)
+ {
+       u32 key = 0;
+-      u64 value;
+       int err, s;
++      u64 value;
+       s = xsocket(family, sotype, 0);
+       if (s == -1)
+@@ -61,11 +61,8 @@ static void test_insert_opened(struct test_sockmap_listen *skel __always_unused,
+       errno = 0;
+       value = s;
+       err = bpf_map_update_elem(mapfd, &key, &value, BPF_NOEXIST);
+-      if (sotype == SOCK_STREAM) {
+-              if (!err || errno != EOPNOTSUPP)
+-                      FAIL_ERRNO("map_update: expected EOPNOTSUPP");
+-      } else if (err)
+-              FAIL_ERRNO("map_update: expected success");
++      ASSERT_ERR(err, "map_update");
++      ASSERT_EQ(errno, EOPNOTSUPP, "errno");
+       xclose(s);
+ }
+@@ -75,8 +72,8 @@ static void test_insert_bound(struct test_sockmap_listen *skel __always_unused,
+       struct sockaddr_storage addr;
+       socklen_t len;
+       u32 key = 0;
+-      u64 value;
+       int err, s;
++      u64 value;
+       init_addr_loopback(family, &addr, &len);
+@@ -91,8 +88,12 @@ static void test_insert_bound(struct test_sockmap_listen *skel __always_unused,
+       errno = 0;
+       value = s;
+       err = bpf_map_update_elem(mapfd, &key, &value, BPF_NOEXIST);
+-      if (!err || errno != EOPNOTSUPP)
+-              FAIL_ERRNO("map_update: expected EOPNOTSUPP");
++      if (sotype == SOCK_STREAM) {
++              ASSERT_ERR(err, "map_update");
++              ASSERT_EQ(errno, EOPNOTSUPP, "errno");
++      } else {
++              ASSERT_OK(err, "map_update");
++      }
+ close:
+       xclose(s);
+ }
+@@ -1261,7 +1262,7 @@ static void test_ops(struct test_sockmap_listen *skel, struct bpf_map *map,
+               /* insert */
+               TEST(test_insert_invalid),
+               TEST(test_insert_opened),
+-              TEST(test_insert_bound, SOCK_STREAM),
++              TEST(test_insert_bound),
+               TEST(test_insert),
+               /* delete */
+               TEST(test_delete_after_insert),
+-- 
+2.53.0
+
index 74a5d66d85a838c39b157e6940ec48eb8036bca3..8a739cbe50b65fc94d0b28ba6ff371498461f8af 100644 (file)
@@ -81,3 +81,5 @@ futex-prevent-robust-futex-exit-race-some-more.patch
 fortify-refactor-test_fortify-makefile-to-fix-some-b.patch
 fortify-disable-wstringop-overread-in-tests.patch
 pinctrl-renesas-rzg2l-use-enotsupp-instead-of-eopnot.patch
+fscrypt-replace-mk_users-keyring-with-simple-list.patch
+selftests-bpf-adapt-sockmap-update-error-handling.patch
diff --git a/queue-7.1/selftests-bpf-adapt-sockmap-update-error-handling.patch b/queue-7.1/selftests-bpf-adapt-sockmap-update-error-handling.patch
new file mode 100644 (file)
index 0000000..cd343a3
--- /dev/null
@@ -0,0 +1,96 @@
+From b740be59b86ffbc418fb0858155353bce146aa68 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 15 Aug 2026 09:50:39 -0300
+Subject: selftests/bpf: Adapt sockmap update error handling
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Michal Luczaj <mhal@rbox.co>
+
+[ Upstream commit 30581eda4a07ff15db623612cac578e81869e96f ]
+
+Update sockmap_listen to accommodate the recent change in sockmap that
+rejects unbound UDP sockets.
+
+TCP: Reject unbound and bound (unless established or listening).
+UDP: Accept only bound sockets.
+
+While at it, migrate to ASSERT_* and enforce reverse xmas tree.
+
+Signed-off-by: Michal Luczaj <mhal@rbox.co>
+Reviewed-by: Kuniyuki Iwashima <kuniyu@google.com>
+Reviewed-by: Jakub Sitnicki <jakub@cloudflare.com>
+Link: https://lore.kernel.org/bpf/20260707-sockmap-lookup-udp-leak-v4-3-f878346f27ab@rbox.co
+Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
+Signed-off-by: Ricardo B. Marlière (SUSE) <ricardo@marliere.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../selftests/bpf/prog_tests/sockmap_listen.c | 21 ++++++++++---------
+ 1 file changed, 11 insertions(+), 10 deletions(-)
+
+diff --git a/tools/testing/selftests/bpf/prog_tests/sockmap_listen.c b/tools/testing/selftests/bpf/prog_tests/sockmap_listen.c
+index cc0c68bab9079..1c96a3cf4b979 100644
+--- a/tools/testing/selftests/bpf/prog_tests/sockmap_listen.c
++++ b/tools/testing/selftests/bpf/prog_tests/sockmap_listen.c
+@@ -53,8 +53,8 @@ static void test_insert_opened(struct test_sockmap_listen *skel __always_unused,
+                              int family, int sotype, int mapfd)
+ {
+       u32 key = 0;
+-      u64 value;
+       int err, s;
++      u64 value;
+       s = xsocket(family, sotype, 0);
+       if (s == -1)
+@@ -63,11 +63,8 @@ static void test_insert_opened(struct test_sockmap_listen *skel __always_unused,
+       errno = 0;
+       value = s;
+       err = bpf_map_update_elem(mapfd, &key, &value, BPF_NOEXIST);
+-      if (sotype == SOCK_STREAM) {
+-              if (!err || errno != EOPNOTSUPP)
+-                      FAIL_ERRNO("map_update: expected EOPNOTSUPP");
+-      } else if (err)
+-              FAIL_ERRNO("map_update: expected success");
++      ASSERT_ERR(err, "map_update");
++      ASSERT_EQ(errno, EOPNOTSUPP, "errno");
+       xclose(s);
+ }
+@@ -77,8 +74,8 @@ static void test_insert_bound(struct test_sockmap_listen *skel __always_unused,
+       struct sockaddr_storage addr;
+       socklen_t len = 0;
+       u32 key = 0;
+-      u64 value;
+       int err, s;
++      u64 value;
+       init_addr_loopback(family, &addr, &len);
+@@ -93,8 +90,12 @@ static void test_insert_bound(struct test_sockmap_listen *skel __always_unused,
+       errno = 0;
+       value = s;
+       err = bpf_map_update_elem(mapfd, &key, &value, BPF_NOEXIST);
+-      if (!err || errno != EOPNOTSUPP)
+-              FAIL_ERRNO("map_update: expected EOPNOTSUPP");
++      if (sotype == SOCK_STREAM) {
++              ASSERT_ERR(err, "map_update");
++              ASSERT_EQ(errno, EOPNOTSUPP, "errno");
++      } else {
++              ASSERT_OK(err, "map_update");
++      }
+ close:
+       xclose(s);
+ }
+@@ -1289,7 +1290,7 @@ static void test_ops(struct test_sockmap_listen *skel, struct bpf_map *map,
+               /* insert */
+               TEST(test_insert_invalid),
+               TEST(test_insert_opened),
+-              TEST(test_insert_bound, SOCK_STREAM),
++              TEST(test_insert_bound),
+               TEST(test_insert),
+               /* delete */
+               TEST(test_delete_after_insert),
+-- 
+2.53.0
+
diff --git a/queue-7.1/selftests-bpf-ensure-udp-sockets-are-bound.patch b/queue-7.1/selftests-bpf-ensure-udp-sockets-are-bound.patch
new file mode 100644 (file)
index 0000000..e1c1c7e
--- /dev/null
@@ -0,0 +1,60 @@
+From f07f886e3f433ff86f4df4ea6837e39f2a410706 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 15 Aug 2026 09:50:38 -0300
+Subject: selftests/bpf: Ensure UDP sockets are bound
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Michal Luczaj <mhal@rbox.co>
+
+[ Upstream commit fe3ff273767ef22fe8a7cb3816f264927c190e50 ]
+
+Update sockmap_basic tests to bind sockets before they are used. This
+accommodates the recent change in sockmap that rejects unbound UDP sockets.
+
+Signed-off-by: Michal Luczaj <mhal@rbox.co>
+Reviewed-by: Kuniyuki Iwashima <kuniyu@google.com>
+Reviewed-by: Jakub Sitnicki <jakub@cloudflare.com>
+Link: https://lore.kernel.org/bpf/20260707-sockmap-lookup-udp-leak-v4-1-f878346f27ab@rbox.co
+Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
+Signed-off-by: Ricardo B. Marlière (SUSE) <ricardo@marliere.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ tools/testing/selftests/bpf/prog_tests/sockmap_basic.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/tools/testing/selftests/bpf/prog_tests/sockmap_basic.c b/tools/testing/selftests/bpf/prog_tests/sockmap_basic.c
+index d2846579285f2..b4019d1a5575e 100644
+--- a/tools/testing/selftests/bpf/prog_tests/sockmap_basic.c
++++ b/tools/testing/selftests/bpf/prog_tests/sockmap_basic.c
+@@ -807,7 +807,7 @@ static void test_sockmap_many_socket(void)
+               return;
+       }
+-      udp = xsocket(AF_INET, SOCK_DGRAM | SOCK_NONBLOCK, 0);
++      udp = socket_loopback(AF_INET, SOCK_DGRAM | SOCK_NONBLOCK);
+       if (udp < 0) {
+               close(dgram);
+               close(tcp);
+@@ -876,7 +876,7 @@ static void test_sockmap_many_maps(void)
+               return;
+       }
+-      udp = xsocket(AF_INET, SOCK_DGRAM | SOCK_NONBLOCK, 0);
++      udp = socket_loopback(AF_INET, SOCK_DGRAM | SOCK_NONBLOCK);
+       if (udp < 0) {
+               close(dgram);
+               close(tcp);
+@@ -947,7 +947,7 @@ static void test_sockmap_same_sock(void)
+               return;
+       }
+-      udp = xsocket(AF_INET, SOCK_DGRAM | SOCK_NONBLOCK, 0);
++      udp = socket_loopback(AF_INET, SOCK_DGRAM | SOCK_NONBLOCK);
+       if (udp < 0) {
+               close(dgram);
+               close(tcp);
+-- 
+2.53.0
+
index 2fba1cc0c66463abeefee74f049999b7d90e6eda..7a6fbdaf5aefe5a2a547dd35fd75cb99726b2ec1 100644 (file)
@@ -147,3 +147,5 @@ selftests-xsk-fix-too-many-frags-multi-buffer-tx-tes.patch
 selftests-xsk-account-reclaimed-invalid-tx-descripto.patch
 bluetooth-btrtl-fix-rtl8761b-bu-broken-le-extended-s.patch
 bluetooth-btusb-add-tp-link-ub600-for-realtek-8761bu.patch
+selftests-bpf-ensure-udp-sockets-are-bound.patch
+selftests-bpf-adapt-sockmap-update-error-handling.patch