[PATCH] idmapped-mounts: probe O_TMPFILE support with the caller's mapped id
Zizhi Wo <[email protected]> Fri, 31 Jul 2026 17:02:53 +0800
| Newsgroups | org.kernel.vger.fstests |
|---|---|
| Message-ID | <[email protected]> |
From: Zizhi Wo <[email protected]> Kernel commit 539dce114465 ("fs: refuse O_TMPFILE creation with an unmapped fsuid or fsgid") made vfs_tmpfile() return -EOVERFLOW when the caller's fsuid/fsgid has no mapping in the filesystem's user namespace after applying the mount's idmapping. This is a no-op on non-idmapped mounts and only takes effect on an idmapped mount that does not map the caller. The idmapped-mount testcases behind generic/696 and generic/697 build an idmapping (e.g. "0 10000 10000") that covers host uid 10000-19999 but not uid 0, then call openat_tmpfile_supported() from the parent process that is still real root (fsuid 0). The probe now gets -EOVERFLOW, falls into the log_errno() branch, and prints utils.c: 928: openat_tmpfile_supported - Value too large for defined \ data type - failure: create to stderr. Both testcases expect "Silence is golden", so this spurious output fails them, even though the kernel behavior is correct and the testcases' own assertions all pass. Move each openat_tmpfile_supported() call into the child, after switch_ids()/switch_userns(), so it probes with the mapped identity the tmpfile section uses. Silencing EOVERFLOW in openat_tmpfile_supported() would make it indistinguishable whether the idmapping genuinely has no mapping for any caller, or the probe just ran in the unmapped parent before the switch. Signed-off-by: Zizhi Wo <[email protected]> --- src/vfs/idmapped-mounts.c | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/src/vfs/idmapped-mounts.c b/src/vfs/idmapped-mounts.c index ed9992f9..bfbe9042 100644 --- a/src/vfs/idmapped-mounts.c +++ b/src/vfs/idmapped-mounts.c @@ -3838,8 +3838,6 @@ int tcore_setgid_create_idmapped(const struct vfstest_info *info) goto out; } - supported = openat_tmpfile_supported(open_tree_fd); - pid = fork(); if (pid < 0) { log_stderr("failure: fork"); @@ -3849,6 +3847,8 @@ int tcore_setgid_create_idmapped(const struct vfstest_info *info) if (!switch_ids(10000, 11000)) die("failure: switch fsids"); + supported = openat_tmpfile_supported(open_tree_fd); + /* create regular file via open() */ file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, S_IXGRP | S_ISGID); if (file1_fd < 0) @@ -4014,8 +4014,6 @@ int tcore_setgid_create_idmapped_in_userns(const struct vfstest_info *info) goto out; } - supported = openat_tmpfile_supported(open_tree_fd); - pid = fork(); if (pid < 0) { log_stderr("failure: fork"); @@ -4025,6 +4023,8 @@ int tcore_setgid_create_idmapped_in_userns(const struct vfstest_info *info) if (!switch_userns(attr.userns_fd, 0, 0, false)) die("failure: switch_userns"); + supported = openat_tmpfile_supported(open_tree_fd); + /* create regular file via open() */ file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, S_IXGRP | S_ISGID); if (file1_fd < 0) @@ -4133,6 +4133,8 @@ int tcore_setgid_create_idmapped_in_userns(const struct vfstest_info *info) if (!switch_userns(attr.userns_fd, 0, 0, false)) die("failure: switch_userns"); + supported = openat_tmpfile_supported(open_tree_fd); + if (!caps_down_fsetid()) die("failure: caps_down_fsetid"); @@ -4257,6 +4259,8 @@ int tcore_setgid_create_idmapped_in_userns(const struct vfstest_info *info) if (!switch_userns(attr.userns_fd, 0, 1000, false)) die("failure: switch_userns"); + supported = openat_tmpfile_supported(open_tree_fd); + if (!caps_down_fsetid()) die("failure: caps_down_fsetid"); @@ -7733,8 +7737,6 @@ static int setgid_create_umask_idmapped(const struct vfstest_info *info) goto out; } - supported = openat_tmpfile_supported(open_tree_fd); - pid = fork(); if (pid < 0) { log_stderr("failure: fork"); @@ -7752,6 +7754,8 @@ static int setgid_create_umask_idmapped(const struct vfstest_info *info) if (!switch_ids(10000, 11000)) die("failure: switch fsids"); + supported = openat_tmpfile_supported(open_tree_fd); + /* create regular file via open() */ file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, S_IXGRP | S_ISGID); if (file1_fd < 0) @@ -7947,8 +7951,6 @@ static int setgid_create_umask_idmapped_in_userns(const struct vfstest_info *inf goto out; } - supported = openat_tmpfile_supported(open_tree_fd); - /* * Below we verify that setgid inheritance for a newly created file or * directory works correctly. As part of this we need to verify that @@ -7984,6 +7986,8 @@ static int setgid_create_umask_idmapped_in_userns(const struct vfstest_info *inf if (!switch_userns(attr.userns_fd, 0, 0, false)) die("failure: switch_userns"); + supported = openat_tmpfile_supported(open_tree_fd); + if (!caps_down_fsetid()) die("failure: caps_down_fsetid"); @@ -8181,8 +8185,6 @@ static int setgid_create_acl_idmapped(const struct vfstest_info *info) goto out; } - supported = openat_tmpfile_supported(open_tree_fd); - pid = fork(); if (pid < 0) { log_stderr("failure: fork"); @@ -8207,6 +8209,8 @@ static int setgid_create_acl_idmapped(const struct vfstest_info *info) if (!switch_ids(10000, 11000)) die("failure: switch fsids"); + supported = openat_tmpfile_supported(open_tree_fd); + /* create regular file via open() */ file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, S_IXGRP | S_ISGID); if (file1_fd < 0) @@ -8342,6 +8346,8 @@ static int setgid_create_acl_idmapped(const struct vfstest_info *info) if (!switch_ids(10000, 11000)) die("failure: switch fsids"); + supported = openat_tmpfile_supported(open_tree_fd); + /* create regular file via open() */ file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, S_IXGRP | S_ISGID); if (file1_fd < 0) @@ -8536,8 +8542,6 @@ static int setgid_create_acl_idmapped_in_userns(const struct vfstest_info *info) goto out; } - supported = openat_tmpfile_supported(open_tree_fd); - /* * Below we verify that setgid inheritance for a newly created file or * directory works correctly. As part of this we need to verify that @@ -8580,6 +8584,8 @@ static int setgid_create_acl_idmapped_in_userns(const struct vfstest_info *info) if (!switch_userns(attr.userns_fd, 0, 0, false)) die("failure: switch_userns"); + supported = openat_tmpfile_supported(open_tree_fd); + if (!caps_down_fsetid()) die("failure: caps_down_fsetid"); @@ -8723,6 +8729,8 @@ static int setgid_create_acl_idmapped_in_userns(const struct vfstest_info *info) if (!switch_userns(attr.userns_fd, 0, 0, false)) die("failure: switch_userns"); + supported = openat_tmpfile_supported(open_tree_fd); + if (!caps_down_fsetid()) die("failure: caps_down_fsetid"); -- 2.52.0