* [REPORT] binfmt_misc: leaked write-access denial on F-flag interpreter inode
@ 2026-07-18 4:43 Vivek Parikh
2026-07-19 11:47 ` Jori Koolstra
0 siblings, 1 reply; 2+ messages in thread
From: Vivek Parikh @ 2026-07-18 4:43 UTC (permalink / raw)
To: viro, brauner, kees; +Cc: linux-fsdevel
Note: this bug was found with AI assistance, so I am treating it as public
per Documentation/process/security-bugs. A reproducer (unprivileged C PoC)
is available on request; I am not posting it here.
Summary
-------
put_binfmt_handler() closes an F-flag (MISC_FMT_OPEN_FILE) entry's
interpreter file without restoring the write access that open_exec()
denied at registration. Every register/delete cycle of an F entry leaks
one i_writecount denial on the interpreter's inode, so that inode returns
-ETXTBSY to all writers until it is evicted from the inode cache or the
machine reboots.
Affected versions
-----------------
Introduced in v4.7 by commit 948b701a607f. Present through v7.2.0-rc3
(fs/binfmt_misc.c:162-168). Root-only from v4.7; reachable by an
unprivileged user from v6.7 onward, when binfmt_misc gained
FS_USERNS_MOUNT and can be mounted inside a user namespace with no
capability check on registration (on systems that permit unprivileged
user namespaces).
Details
-------
Registration of an F entry opens the interpreter via open_exec()
(fs/binfmt_misc.c:821), which calls exe_file_deny_write_access() in
do_open_execat() (fs/exec.c:800). do_open_execat() documents that the
caller must call exe_file_allow_write_access() before releasing the file.
The registration error path honors this (fs/binfmt_misc.c:834):
exe_file_allow_write_access(f);
filp_close(f, NULL);
The teardown path does not (fs/binfmt_misc.c:162-168):
static void put_binfmt_handler(Node *e)
{
if (refcount_dec_and_test(&e->users)) {
if (e->flags & MISC_FMT_OPEN_FILE)
filp_close(e->interp_file, NULL);
kfree(e);
}
}
filp_close()/fput() do not reverse the deny count, so the denial is
leaked. This is the persistent file opened by open_exec() at
registration; it is distinct from the per-exec clone made in
load_misc_binary() (fs/binfmt_misc.c:251-254), which is released
elsewhere.
Reproduction (conditions)
-------------------------
- CONFIG_BINFMT_MISC enabled.
- For the unprivileged case: kernel/distro permitting unprivileged user
namespaces (v6.7+ for the userns-mount path).
- Steps: mount binfmt_misc; register ":x:E::x::<victim>:F" for any
world-readable regular file on a non-noexec mount; delete the entry
("echo -1"); open(victim, O_WRONLY) then fails with -ETXTBSY.
The victim needs no execute bit; open_exec only requires a regular file
on a non-noexec mount.
Verified: unprivileged (uid 1000) on a 7.0.0-27-generic host, and as
root on a 7.2.0-rc3 build.
Fix
---
Mirror the registration error-path fix on the teardown path.
exe_file_allow_write_access() is NULL-safe and skips the same
FMODE_FSNOTIFY_HSM files that exe_file_deny_write_access() skipped, so
no imbalance is possible.
diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c
--- a/fs/binfmt_misc.c
+++ b/fs/binfmt_misc.c
@@ -162,8 +162,10 @@ static void put_binfmt_handler(Node *e)
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);
}
}
Fixes: 948b701a607f ("binfmt_misc: add persistent opened binary
handler for containers")
Signed-off-by: Vivek Parikh <viv0411.parikh@gmail.com>
^ permalink raw reply [flat|nested] 2+ messages in thread* Re: [REPORT] binfmt_misc: leaked write-access denial on F-flag interpreter inode
2026-07-18 4:43 [REPORT] binfmt_misc: leaked write-access denial on F-flag interpreter inode Vivek Parikh
@ 2026-07-19 11:47 ` Jori Koolstra
0 siblings, 0 replies; 2+ messages in thread
From: Jori Koolstra @ 2026-07-19 11:47 UTC (permalink / raw)
To: Vivek Parikh; +Cc: viro, brauner, kees, linux-fsdevel
On Sat, Jul 18, 2026 at 10:13:46AM +0530, Vivek Parikh wrote:
> Note: this bug was found with AI assistance, so I am treating it as public
> per Documentation/process/security-bugs. A reproducer (unprivileged C PoC)
> is available on request; I am not posting it here.
>
> Summary
> -------
> put_binfmt_handler() closes an F-flag (MISC_FMT_OPEN_FILE) entry's
> interpreter file without restoring the write access that open_exec()
> denied at registration. Every register/delete cycle of an F entry leaks
> one i_writecount denial on the interpreter's inode, so that inode returns
> -ETXTBSY to all writers until it is evicted from the inode cache or the
> machine reboots.
>
> Affected versions
> -----------------
> Introduced in v4.7 by commit 948b701a607f. Present through v7.2.0-rc3
> (fs/binfmt_misc.c:162-168). Root-only from v4.7; reachable by an
> unprivileged user from v6.7 onward, when binfmt_misc gained
> FS_USERNS_MOUNT and can be mounted inside a user namespace with no
> capability check on registration (on systems that permit unprivileged
> user namespaces).
>
> Details
> -------
> Registration of an F entry opens the interpreter via open_exec()
> (fs/binfmt_misc.c:821), which calls exe_file_deny_write_access() in
> do_open_execat() (fs/exec.c:800). do_open_execat() documents that the
> caller must call exe_file_allow_write_access() before releasing the file.
>
> The registration error path honors this (fs/binfmt_misc.c:834):
>
> exe_file_allow_write_access(f);
> filp_close(f, NULL);
>
> The teardown path does not (fs/binfmt_misc.c:162-168):
>
> static void put_binfmt_handler(Node *e)
> {
> if (refcount_dec_and_test(&e->users)) {
> if (e->flags & MISC_FMT_OPEN_FILE)
> filp_close(e->interp_file, NULL);
> kfree(e);
> }
> }
>
> filp_close()/fput() do not reverse the deny count, so the denial is
> leaked. This is the persistent file opened by open_exec() at
> registration; it is distinct from the per-exec clone made in
> load_misc_binary() (fs/binfmt_misc.c:251-254), which is released
> elsewhere.
>
> Reproduction (conditions)
> -------------------------
> - CONFIG_BINFMT_MISC enabled.
> - For the unprivileged case: kernel/distro permitting unprivileged user
> namespaces (v6.7+ for the userns-mount path).
> - Steps: mount binfmt_misc; register ":x:E::x::<victim>:F" for any
> world-readable regular file on a non-noexec mount; delete the entry
> ("echo -1"); open(victim, O_WRONLY) then fails with -ETXTBSY.
> The victim needs no execute bit; open_exec only requires a regular file
> on a non-noexec mount.
>
> Verified: unprivileged (uid 1000) on a 7.0.0-27-generic host, and as
> root on a 7.2.0-rc3 build.
>
> Fix
> ---
> Mirror the registration error-path fix on the teardown path.
> exe_file_allow_write_access() is NULL-safe and skips the same
> FMODE_FSNOTIFY_HSM files that exe_file_deny_write_access() skipped, so
> no imbalance is possible.
>
> diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c
> --- a/fs/binfmt_misc.c
> +++ b/fs/binfmt_misc.c
> @@ -162,8 +162,10 @@ static void put_binfmt_handler(Node *e)
> 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);
> }
> }
>
> Fixes: 948b701a607f ("binfmt_misc: add persistent opened binary
> handler for containers")
> Signed-off-by: Vivek Parikh <viv0411.parikh@gmail.com>
Thanks!
This is already addressed by a recent patchset of Brauner.[1]
Best,
Jori.
[1]: https://lore.kernel.org/linux-fsdevel/20260710-work-binfmt_misc-locking-v3-1-a162f7cb58d6@kernel.org/
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-07-19 11:46 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-18 4:43 [REPORT] binfmt_misc: leaked write-access denial on F-flag interpreter inode Vivek Parikh
2026-07-19 11:47 ` Jori Koolstra
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox