[PATCH RFC v3 12/90] fs: add kuid_has_fsmapping() and kgid_has_fsmapping()

From: Josef Bacik

Date: Thu Nov 05 2026 - 10:46:15 EST


Several places ask whether a filesystem can hold a given id. Each of them
calls kuid_has_mapping() or kgid_has_mapping() on the user namespace of
the filesystem:

- fsuidgid_has_mapping(), when a file is created
- posix_acl_valid(), for an ACL entry
- the uid and gid mount options of tmpfs, fuse and bpffs
- ovl_copy_up_one(), which runs with the credentials of the mounter, so
current_user_ns() there is the user namespace of the overlay

The same two helpers are also used for many unrelated questions. Nothing
distinguishes the callers that ask about a filesystem, so there is no
place for a rule that should apply to filesystems only.

Add kuid_has_fsmapping() and kgid_has_fsmapping(), next to
vfsuid_has_fsmapping() and vfsgid_has_fsmapping(), and use them in the
places listed above.

No functional change.

Signed-off-by: Josef Bacik <josef@xxxxxxxxxxxxxx>
---
fs/fuse/inode.c | 4 ++--
fs/overlayfs/copy_up.c | 4 ++--
fs/posix_acl.c | 4 ++--
include/linux/fs.h | 4 ++--
include/linux/mnt_idmapping.h | 31 +++++++++++++++++++++++++++++++
kernel/bpf/inode.c | 4 ++--
mm/shmem.c | 4 ++--
7 files changed, 43 insertions(+), 12 deletions(-)

diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
index 1341b681d0ed..37712fce905b 100644
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -888,7 +888,7 @@ static int fuse_parse_param(struct fs_context *fsc, struct fs_parameter *param)
* The requested uid must be representable in the
* filesystem's idmapping.
*/
- if (!kuid_has_mapping(fsc->user_ns, kuid))
+ if (!kuid_has_fsmapping(fsc->user_ns, kuid))
return invalfc(fsc, "Invalid user_id");
ctx->user_id = kuid;
ctx->user_id_present = true;
@@ -900,7 +900,7 @@ static int fuse_parse_param(struct fs_context *fsc, struct fs_parameter *param)
* The requested gid must be representable in the
* filesystem's idmapping.
*/
- if (!kgid_has_mapping(fsc->user_ns, kgid))
+ if (!kgid_has_fsmapping(fsc->user_ns, kgid))
return invalfc(fsc, "Invalid group_id");
ctx->group_id = kgid;
ctx->group_id_present = true;
diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c
index c147ad155b79..48cd09a2b69b 100644
--- a/fs/overlayfs/copy_up.c
+++ b/fs/overlayfs/copy_up.c
@@ -1173,8 +1173,8 @@ static int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry,
if (err)
return err;

- if (!kuid_has_mapping(current_user_ns(), ctx.stat.uid) ||
- !kgid_has_mapping(current_user_ns(), ctx.stat.gid))
+ if (!kuid_has_fsmapping(current_user_ns(), ctx.stat.uid) ||
+ !kgid_has_fsmapping(current_user_ns(), ctx.stat.gid))
return -EOVERFLOW;

/*
diff --git a/fs/posix_acl.c b/fs/posix_acl.c
index fe77934ea8f2..a2e2ca984d95 100644
--- a/fs/posix_acl.c
+++ b/fs/posix_acl.c
@@ -260,7 +260,7 @@ posix_acl_valid(struct user_namespace *user_ns, const struct posix_acl *acl)
case ACL_USER:
if (state != ACL_USER)
return -EINVAL;
- if (!kuid_has_mapping(user_ns, pa->e_uid))
+ if (!kuid_has_fsmapping(user_ns, pa->e_uid))
return -EINVAL;
needs_mask = 1;
break;
@@ -275,7 +275,7 @@ posix_acl_valid(struct user_namespace *user_ns, const struct posix_acl *acl)
case ACL_GROUP:
if (state != ACL_GROUP)
return -EINVAL;
- if (!kgid_has_mapping(user_ns, pa->e_gid))
+ if (!kgid_has_fsmapping(user_ns, pa->e_gid))
return -EINVAL;
needs_mask = 1;
break;
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 88748be03505..ea9b9d5a667d 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1589,8 +1589,8 @@ static inline bool fsuidgid_has_mapping(struct super_block *sb,
kgid = mapped_fsgid(idmap, fs_userns);
if (!gid_valid(kgid))
return false;
- return kuid_has_mapping(fs_userns, kuid) &&
- kgid_has_mapping(fs_userns, kgid);
+ return kuid_has_fsmapping(fs_userns, kuid) &&
+ kgid_has_fsmapping(fs_userns, kgid);
}

struct timespec64 current_time(struct inode *inode);
diff --git a/include/linux/mnt_idmapping.h b/include/linux/mnt_idmapping.h
index 78eeef4c2996..b5e0772aa190 100644
--- a/include/linux/mnt_idmapping.h
+++ b/include/linux/mnt_idmapping.h
@@ -136,6 +136,37 @@ kuid_t from_vfsuid(const struct mnt_idmap *idmap,
kgid_t from_vfsgid(const struct mnt_idmap *idmap,
struct user_namespace *fs_userns, vfsgid_t vfsgid);

+/**
+ * kuid_has_fsmapping - check whether a filesystem can hold a kuid
+ * @fs_userns: the filesystem's idmapping
+ * @kuid: the kuid, after the idmapping of the mount has been applied
+ *
+ * Use this function, and not kuid_has_mapping(), for a kuid that is about to end
+ * up in a filesystem: as the owner of a file, in an ACL, by a mount option.
+ *
+ * Return: true if @kuid has a mapping in the filesystem, false if not.
+ */
+static inline bool kuid_has_fsmapping(struct user_namespace *fs_userns,
+ kuid_t kuid)
+{
+ return kuid_has_mapping(fs_userns, kuid);
+}
+
+/**
+ * kgid_has_fsmapping - check whether a filesystem can hold a kgid
+ * @fs_userns: the filesystem's idmapping
+ * @kgid: the kgid, after the idmapping of the mount has been applied
+ *
+ * See kuid_has_fsmapping().
+ *
+ * Return: true if @kgid has a mapping in the filesystem, false if not.
+ */
+static inline bool kgid_has_fsmapping(struct user_namespace *fs_userns,
+ kgid_t kgid)
+{
+ return kgid_has_mapping(fs_userns, kgid);
+}
+
/**
* vfsuid_has_fsmapping - check whether a vfsuid maps into the filesystem
* @idmap: the mount's idmapping
diff --git a/kernel/bpf/inode.c b/kernel/bpf/inode.c
index c6f328e4752e..504bb7accb39 100644
--- a/kernel/bpf/inode.c
+++ b/kernel/bpf/inode.c
@@ -1026,7 +1026,7 @@ static int bpf_parse_param(struct fs_context *fc, struct fs_parameter *param)
* The requested uid must be representable in the
* filesystem's idmapping.
*/
- if (!kuid_has_mapping(fc->user_ns, uid))
+ if (!kuid_has_fsmapping(fc->user_ns, uid))
goto bad_value;

opts->uid = uid;
@@ -1040,7 +1040,7 @@ static int bpf_parse_param(struct fs_context *fc, struct fs_parameter *param)
* The requested gid must be representable in the
* filesystem's idmapping.
*/
- if (!kgid_has_mapping(fc->user_ns, gid))
+ if (!kgid_has_fsmapping(fc->user_ns, gid))
goto bad_value;

opts->gid = gid;
diff --git a/mm/shmem.c b/mm/shmem.c
index af21a89abb0f..8e7b51797ab8 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -4793,7 +4793,7 @@ static int shmem_parse_one(struct fs_context *fc, struct fs_parameter *param)
* The requested uid must be representable in the
* filesystem's idmapping.
*/
- if (!kuid_has_mapping(fc->user_ns, kuid))
+ if (!kuid_has_fsmapping(fc->user_ns, kuid))
goto bad_value;

ctx->uid = kuid;
@@ -4805,7 +4805,7 @@ static int shmem_parse_one(struct fs_context *fc, struct fs_parameter *param)
* The requested gid must be representable in the
* filesystem's idmapping.
*/
- if (!kgid_has_mapping(fc->user_ns, kgid))
+ if (!kgid_has_fsmapping(fc->user_ns, kgid))
goto bad_value;

ctx->gid = kgid;

--
2.55.0