From: Greg Kroah-Hartman Date: Wed, 5 Aug 2026 09:58:58 +0000 (+0200) Subject: 7.1-stable patches X-Git-Url: http://git.ipfire.org/index.cgi?a=commitdiff_plain;h=46ffb4ee67a0bff65fe86a0bee4163d48ccf7b6e;p=thirdparty%2Fkernel%2Fstable-queue.git 7.1-stable patches added patches: binfmt_misc-don-t-leak-the-user-namespace-when-the-mount-fails.patch binfmt_misc-don-t-let-an-f-entry-pin-its-own-instance.patch binfmt_misc-reject-a-flag-character-as-the-field-delimiter.patch binfmt_misc-restore-write-access-when-removing-an-entry.patch binfmt_misc-use-exe_file_deny_write_access-for-the-interpreter-clone.patch --- diff --git a/queue-7.1/binfmt_misc-don-t-leak-the-user-namespace-when-the-mount-fails.patch b/queue-7.1/binfmt_misc-don-t-leak-the-user-namespace-when-the-mount-fails.patch new file mode 100644 index 0000000000..6b1373a353 --- /dev/null +++ b/queue-7.1/binfmt_misc-don-t-leak-the-user-namespace-when-the-mount-fails.patch @@ -0,0 +1,118 @@ +From b8206f516fe7cbe785cf44bf09c17c438d7c3cad Mon Sep 17 00:00:00 2001 +From: Christian Brauner +Date: Tue, 28 Jul 2026 15:48:10 +0200 +Subject: binfmt_misc: don't leak the user namespace when the mount fails + +From: Christian Brauner + +commit b8206f516fe7cbe785cf44bf09c17c438d7c3cad upstream. + +bm_get_tree() takes a reference to the user namespace and hands it to +get_tree_keyed() as the sget key. sget_fc() moves that reference into +sb->s_fs_info and clears fc->s_fs_info, so from that point on the +superblock owns it and bm_free() doesn't see it anymore. + +The superblock drops it in ->put_super(). But generic_shutdown_super() +only calls ->put_super() from inside the if (sb->s_root) branch, so +nothing releases it when bm_fill_super() fails: + +- The kzalloc_obj() failure leaves s_root NULL and the whole branch is + skipped. + +- A simple_fill_super() failure in the file loop leaves s_root set, but + s_op still points at simple_super_operations, which has no + ->put_super(). bm_fill_super() installs s_ops only once + simple_fill_super() returned success, and installing it earlier + wouldn't help either because simple_fill_super() overwrites s_op. + +Either way vfs_get_super() calls deactivate_locked_super() and the +reference is gone for good. binfmt_misc mounts are available in a user +namespace and both the inode and the dentry cache are SLAB_ACCOUNT, so +an unprivileged caller under a tight memory cgroup can fail +simple_fill_super() on demand and leak one user namespace per attempt. + +Drop the reference in ->kill_sb() instead, which runs unconditionally, +the same way nfsd and rpc_pipefs release their keyed s_fs_info. + +That also stops ->put_super() from clearing s_fs_info while the +superblock is still on @fs_supers. generic_shutdown_super() leaves it +there on purpose so that sget_fc() keeps finding it until kill_sb() has +run, but a NULL s_fs_info makes test_keyed_super() miss it, so a +concurrent mount for the same user namespace skips the grab_super() +wait and creates a second superblock for a namespace that is still +being torn down. + +Link: https://patch.msgid.link/20260728-work-binfmt_misc-usernsleak-v1-1-dbd8d5e626e7@kernel.org +Fixes: 21ca59b365c0 ("binfmt_misc: enable sandboxed mounts") +Cc: stable@vger.kernel.org +Signed-off-by: Christian Brauner (Amutable) +Signed-off-by: Greg Kroah-Hartman +--- + fs/binfmt_misc.c | 32 +++++++++++++++----------------- + 1 file changed, 15 insertions(+), 17 deletions(-) + +--- a/fs/binfmt_misc.c ++++ b/fs/binfmt_misc.c +@@ -921,18 +921,9 @@ static const struct file_operations bm_s + + /* Superblock handling */ + +-static void bm_put_super(struct super_block *sb) +-{ +- struct user_namespace *user_ns = sb->s_fs_info; +- +- sb->s_fs_info = NULL; +- put_user_ns(user_ns); +-} +- + static const struct super_operations s_ops = { + .statfs = simple_statfs, + .evict_inode = bm_evict_inode, +- .put_super = bm_put_super, + }; + + static int bm_fill_super(struct super_block *sb, struct fs_context *fc) +@@ -990,13 +981,12 @@ static int bm_fill_super(struct super_bl + /* + * When the binfmt_misc superblock for this userns is shutdown + * ->enabled might have been set to false and we don't reinitialize +- * ->enabled again in put_super() as someone might already be mounting +- * binfmt_misc again. It also would be pointless since by the time +- * ->put_super() is called we know that the binary type list for this +- * bintfmt_misc mount is empty making load_misc_binary() return +- * -ENOEXEC independent of whether ->enabled is true. Instead, if +- * someone mounts binfmt_misc for the first time or again we simply +- * reset ->enabled to true. ++ * ->enabled again during shutdown as someone might already be mounting ++ * binfmt_misc again. It also would be pointless since by then we know ++ * that the binary type list for this binfmt_misc mount is empty making ++ * load_misc_binary() return -ENOEXEC independent of whether ->enabled ++ * is true. Instead, if someone mounts binfmt_misc for the first time or ++ * again we simply reset ->enabled to true. + */ + misc->enabled = true; + +@@ -1022,6 +1012,14 @@ static const struct fs_context_operation + .get_tree = bm_get_tree, + }; + ++static void bm_kill_sb(struct super_block *sb) ++{ ++ struct user_namespace *user_ns = sb->s_fs_info; ++ ++ kill_anon_super(sb); ++ put_user_ns(user_ns); ++} ++ + static int bm_init_fs_context(struct fs_context *fc) + { + fc->ops = &bm_context_ops; +@@ -1038,7 +1036,7 @@ static struct file_system_type bm_fs_typ + .name = "binfmt_misc", + .init_fs_context = bm_init_fs_context, + .fs_flags = FS_USERNS_MOUNT, +- .kill_sb = kill_anon_super, ++ .kill_sb = bm_kill_sb, + }; + MODULE_ALIAS_FS("binfmt_misc"); + diff --git a/queue-7.1/binfmt_misc-don-t-let-an-f-entry-pin-its-own-instance.patch b/queue-7.1/binfmt_misc-don-t-let-an-f-entry-pin-its-own-instance.patch new file mode 100644 index 0000000000..c3ded23492 --- /dev/null +++ b/queue-7.1/binfmt_misc-don-t-let-an-f-entry-pin-its-own-instance.patch @@ -0,0 +1,71 @@ +From 79055d82772b9584f259b747fe40ff56a076678d Mon Sep 17 00:00:00 2001 +From: Christian Brauner +Date: Tue, 28 Jul 2026 14:26:32 +0200 +Subject: binfmt_misc: don't let an 'F' entry pin its own instance + +From: Christian Brauner + +commit 79055d82772b9584f259b747fe40ff56a076678d upstream. + +An entry registered with 'F' opens its interpreter at registration time +and holds that file until the entry is freed. Any entry nobody removes +by hand only gets closed once the binfmt_misc superblock is shut down. +If the interpreter lives on a mount that keeps that superblock alive the +two pin each other: + + binfmt_misc sb -> inode -> entry -> interp_file -> vfsmount -> binfmt_misc sb + +TL;DR the file is never closed. Once the mount namespace is gone there +is nothing left to unregister through either. + +There are two ways to trigger this bug: + +- Point the interpreter at the instance itself. Its files are regular + files owned by the mounter and both bm_get_inode() and + simple_fill_super() leave i_op at empty_iops. So notify_change() falls + back to simple_setattr() and chmod +x works. We never set SB_I_NOEXEC + and so open_exec() accepts it. + +- Use the instance as an overlayfs lower layer. The overlay superblock + holds a clone_private_mount() of every layer until it is destroyed and + that clone is in no namespace. So umount_tree() never reaches it. + +That's a DoS. And it isn't only the superblock that leaks. It pins the +user namespace it was mounted in, so every iteration permanently eats +one of the caller's user namespace charges. + +So let's just do the sane thing. SB_I_NOEXEC makes open_exec() fail on +the instance's own files and s_stack_depth makes overlayfs reject the +layer before it ever takes a clone. That also covers the ecryptfs and +fuse passthrough variants. What 'F' promises is unchanged. + +The stable tag is narrower than the Fixes tags on purpose. Before +sandboxed mounts this needed global root against the single instance +everyone shares, and the change doesn't apply to those trees anyway. + +Note that SB_I_NODEV is implicitly raised for userns mounts but raise it +explicitly here as well. + +Link: https://patch.msgid.link/20260728-work-binfmt_misc-selfpin-v1-1-74df5daeca5b@kernel.org +Fixes: 948b701a607f ("binfmt_misc: add persistent opened binary handler for containers") +Fixes: 21ca59b365c0 ("binfmt_misc: enable sandboxed mounts") +Cc: stable@vger.kernel.org # v6.7+ +Signed-off-by: Christian Brauner (Amutable) +Signed-off-by: Greg Kroah-Hartman +--- + fs/binfmt_misc.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/fs/binfmt_misc.c ++++ b/fs/binfmt_misc.c +@@ -949,6 +949,10 @@ static int bm_fill_super(struct super_bl + if (WARN_ON(user_ns != current_user_ns())) + return -EINVAL; + ++ /* Never exec off this instance and never let anything stack on it. */ ++ sb->s_iflags |= SB_I_NOEXEC | SB_I_NODEV; ++ sb->s_stack_depth = FILESYSTEM_MAX_STACK_DEPTH; ++ + /* + * Lazily allocate a new binfmt_misc instance for this namespace, i.e. + * do it here during the first mount of binfmt_misc. We don't need to diff --git a/queue-7.1/binfmt_misc-reject-a-flag-character-as-the-field-delimiter.patch b/queue-7.1/binfmt_misc-reject-a-flag-character-as-the-field-delimiter.patch new file mode 100644 index 0000000000..a0665ab0ec --- /dev/null +++ b/queue-7.1/binfmt_misc-reject-a-flag-character-as-the-field-delimiter.patch @@ -0,0 +1,65 @@ +From 8e85d50ba1117fd446bf9a250bd8a97d48384bdc Mon Sep 17 00:00:00 2001 +From: Christian Brauner +Date: Fri, 10 Jul 2026 11:33:04 +0200 +Subject: binfmt_misc: reject a flag character as the field delimiter + +From: Christian Brauner + +commit 8e85d50ba1117fd446bf9a250bd8a97d48384bdc upstream. + +The registration string starts with a user chosen delimiter that +separates the individual fields. So that the field parsers terminate +even on a truncated string create_entry() pads the buffer with that +same delimiter: + + memset(buf + count, del, 8); + +Most fields are scanned for the delimiter with strchr()/scanarg() and +happily stop on the padding. The flags field is different: instead of +scanning for the delimiter check_special_flags() consumes the flag +characters 'P', 'O', 'C' and 'F' and stops at the first byte that is +none of them, relying on the trailing delimiter to end the scan. + +If the delimiter is itself a flag character the padding no longer acts +as a terminator. The scan swallows all eight padding bytes and keeps +reading past the end of the allocation until it hits a byte that is +not a flag character. For example registering + + PaPEPPxPPiP + +with 'P' as the delimiter (name "a", type extension, magic "x", +interpreter "i", empty flags) leaves the flag scan running off the end +of the buffer. The registration is rejected in the end because the +parser does not stop exactly at buf + count, but only after the out of +bounds read has already happened. With an unlucky allocation layout the +scan can walk into an unmapped page; under KASAN it is reported as a +slab out of bounds read. binfmt_misc mounts are available to +unprivileged users in a user namespace so the read is reachable without +privileges. + +Reject a delimiter that is one of the flag characters up front. Such a +registration was always rejected anyway, only after the out of bounds +read, so no valid registration string changes meaning. + +Link: https://patch.msgid.link/20260710-work-binfmt_misc-locking-v3-3-a162f7cb58d6@kernel.org +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Cc: stable@vger.kernel.org +Signed-off-by: Christian Brauner (Amutable) +Signed-off-by: Greg Kroah-Hartman +--- + fs/binfmt_misc.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/fs/binfmt_misc.c ++++ b/fs/binfmt_misc.c +@@ -384,6 +384,10 @@ static Node *create_entry(const char __u + + pr_debug("register: delim: %#x {%c}\n", del, del); + ++ /* A flag-char delimiter runs the flag scan off the buffer. */ ++ if (del == 'P' || del == 'O' || del == 'C' || del == 'F') ++ goto einval; ++ + /* Pad the buffer with the delim to simplify parsing below. */ + memset(buf + count, del, 8); + diff --git a/queue-7.1/binfmt_misc-restore-write-access-when-removing-an-entry.patch b/queue-7.1/binfmt_misc-restore-write-access-when-removing-an-entry.patch new file mode 100644 index 0000000000..e88d0a052e --- /dev/null +++ b/queue-7.1/binfmt_misc-restore-write-access-when-removing-an-entry.patch @@ -0,0 +1,48 @@ +From db1856ea9196cf6e015d12199a34c0b9313c7bfa Mon Sep 17 00:00:00 2001 +From: Christian Brauner +Date: Fri, 10 Jul 2026 11:33:02 +0200 +Subject: binfmt_misc: restore write access when removing an entry + +From: Christian Brauner + +commit db1856ea9196cf6e015d12199a34c0b9313c7bfa upstream. + +Registering an entry with the MISC_FMT_OPEN_FILE flag opens the +interpreter via open_exec() which denies write access to it for as +long as the entry exists. Removing the entry closes the interpreter +file via filp_close() but never restores write access, leaving the +inode's i_writecount permanently negative. Opening the interpreter +for writing keeps failing with ETXTBSY long after the entry is gone +until the inode is evicted from the inode cache. + +Commit 90f601b497d7 ("binfmt_misc: restore write access before +closing files opened by open_exec()") fixed the same imbalance in the +error path of bm_register_write() but the actual removal path has +been leaking the write denial since the introduction of the flag. + +Restore write access in put_binfmt_handler() before closing the +interpreter file. + +Link: https://patch.msgid.link/20260710-work-binfmt_misc-locking-v3-1-a162f7cb58d6@kernel.org +Fixes: 948b701a607f ("binfmt_misc: add persistent opened binary handler for containers") +Cc: stable@vger.kernel.org +Signed-off-by: Christian Brauner (Amutable) +Signed-off-by: Greg Kroah-Hartman +--- + fs/binfmt_misc.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/fs/binfmt_misc.c ++++ b/fs/binfmt_misc.c +@@ -162,8 +162,10 @@ static Node *get_binfmt_handler(struct b + static void put_binfmt_handler(Node *e) + { + if (refcount_dec_and_test(&e->users)) { +- if (e->flags & MISC_FMT_OPEN_FILE) ++ if (e->flags & MISC_FMT_OPEN_FILE) { ++ exe_file_allow_write_access(e->interp_file); + filp_close(e->interp_file, NULL); ++ } + kfree(e); + } + } diff --git a/queue-7.1/binfmt_misc-use-exe_file_deny_write_access-for-the-interpreter-clone.patch b/queue-7.1/binfmt_misc-use-exe_file_deny_write_access-for-the-interpreter-clone.patch new file mode 100644 index 0000000000..40b029e770 --- /dev/null +++ b/queue-7.1/binfmt_misc-use-exe_file_deny_write_access-for-the-interpreter-clone.patch @@ -0,0 +1,59 @@ +From fa5990ca8fd917003e526036bcc50413edb9722c Mon Sep 17 00:00:00 2001 +From: Christian Brauner +Date: Fri, 10 Jul 2026 11:33:03 +0200 +Subject: binfmt_misc: use exe_file_deny_write_access() for the interpreter clone + +From: Christian Brauner + +commit fa5990ca8fd917003e526036bcc50413edb9722c upstream. + +For MISC_FMT_OPEN_FILE entries load_misc_binary() clones the +registered interpreter file and denies write access to the clone via +plain deny_write_access(). The clone is installed as +bprm->interpreter and later released by the exec machinery through +exe_file_allow_write_access() which skips the i_writecount increment +for files with FMODE_FSNOTIFY_HSM set. + +The deny and allow side can therefore come to different conclusions +when pre-content watches are in play: if a pre-content watch is added +to the interpreter after registration every subsequent exec through +that entry takes a write denial on the clone that is never paired +with a write allowance, driving the interpreter inode's i_writecount +further down with each exec and leaving the interpreter unwritable +even after the entry and all its users are gone. + +Take the write denial via exe_file_deny_write_access() so both sides +of the pairing base their decision on the same file mode, and +propagate failure instead of silently ignoring it: an interpreter +that is concurrently open for writing now fails the exec with +ETXTBSY, exactly like an interpreter freshly opened via open_exec() +would. + +Link: https://patch.msgid.link/20260710-work-binfmt_misc-locking-v3-2-a162f7cb58d6@kernel.org +Fixes: 0357ef03c94e ("fs: don't block write during exec on pre-content watched files") +Cc: stable@vger.kernel.org +Signed-off-by: Christian Brauner (Amutable) +Signed-off-by: Greg Kroah-Hartman +--- + fs/binfmt_misc.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +--- a/fs/binfmt_misc.c ++++ b/fs/binfmt_misc.c +@@ -249,8 +249,14 @@ static int load_misc_binary(struct linux + + if (fmt->flags & MISC_FMT_OPEN_FILE) { + interp_file = file_clone_open(fmt->interp_file); +- if (!IS_ERR(interp_file)) +- deny_write_access(interp_file); ++ if (!IS_ERR(interp_file)) { ++ int err = exe_file_deny_write_access(interp_file); ++ ++ if (err) { ++ fput(interp_file); ++ interp_file = ERR_PTR(err); ++ } ++ } + } else { + interp_file = open_exec(fmt->interpreter); + } diff --git a/queue-7.1/series b/queue-7.1/series index 9cc1cfa621..a7e10e7f06 100644 --- a/queue-7.1/series +++ b/queue-7.1/series @@ -285,3 +285,8 @@ tipc-avoid-use-after-free-in-poll-trace-queue-dumps.patch x86-cpu-amd-carve-out-a-zen5-models-range.patch wifi-mac80211-fix-tid_tx-use-after-free-on-ba-session-stop.patch wifi-mwifiex-use-the-subframe-length-when-parsing-a-msdu-tdls-frames.patch +binfmt_misc-restore-write-access-when-removing-an-entry.patch +binfmt_misc-use-exe_file_deny_write_access-for-the-interpreter-clone.patch +binfmt_misc-reject-a-flag-character-as-the-field-delimiter.patch +binfmt_misc-don-t-let-an-f-entry-pin-its-own-instance.patch +binfmt_misc-don-t-leak-the-user-namespace-when-the-mount-fails.patch