[RFC PATCH v2 18/41] fs: keep UUID and GUID owners off filesystems that can't store them

Jan Koester jan.koester at tuxist.de
Wed Oct 21 03:15:38 UTC 2026


Filesystems write inode owners with i_uid_read()/i_gid_read(), which
turn a UUID or GUID into -1. Add SB_I_UID_R for filesystems that can
store such owners, and refuse them elsewhere with -EOVERFLOW, the error
already used for ids without a mapping in the filesystem's namespace:

- notify_change() refuses ATTR_UID/ATTR_GID with such an id,
- fsuidgid_has_mapping() is false for a caller whose fsuid or fsgid is
  one, so may_create() and friends refuse to create inodes owned by it.

No filesystem sets the flag yet.

Assisted-by: Claude:claude-opus-5-5

Signed-off-by: Jan Koester <jan.koester at tuxist.de>
---
 fs/attr.c                      |  7 +++++++
 include/linux/fs.h             | 29 +++++++++++++++++++++++++----
 include/linux/fs/super_types.h |  1 +
 3 files changed, 33 insertions(+), 4 deletions(-)

diff --git a/fs/attr.c b/fs/attr.c
index 71888ac903..09d51b1a32 100644
--- a/fs/attr.c
+++ b/fs/attr.c
@@ -526,6 +526,13 @@ int notify_change(struct mnt_idmap *idmap, struct dentry *dentry,
 	    !vfsgid_has_fsmapping(idmap, inode->i_sb->s_user_ns,
 				  attr->ia_vfsgid))
 		return -EOVERFLOW;
+	/* and that the filesystem can store a UUID or GUID owner */
+	if (ia_valid & ATTR_UID &&
+	    !sb_can_own_kuid(inode->i_sb, vfsuid_into_kuid(attr->ia_vfsuid)))
+		return -EOVERFLOW;
+	if (ia_valid & ATTR_GID &&
+	    !sb_can_own_kgid(inode->i_sb, vfsgid_into_kgid(attr->ia_vfsgid)))
+		return -EOVERFLOW;
 
 	/* Don't allow modifications of files with invalid uids or
 	 * gids unless those uids & gids are being made valid.
diff --git a/include/linux/fs.h b/include/linux/fs.h
index deb411e866..05c4611c87 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1563,14 +1563,35 @@ static inline void inode_fsgid_set(struct inode *inode,
 	inode->i_gid = mapped_fsgid(idmap, i_user_ns(inode));
 }
 
+/**
+ * sb_can_own_kuid() - check whether a filesystem can store an owner
+ * @sb: the superblock
+ * @kuid: the owner
+ *
+ * Classic ids fit any filesystem; UUIDs and GUIDs only those that set
+ * SB_I_UID_R. Elsewhere i_uid_read() would turn them into -1.
+ *
+ * Return: true if @sb can store @kuid.
+ */
+static inline bool sb_can_own_kuid(const struct super_block *sb, kuid_t kuid)
+{
+	return uid_is_legacy(kuid) || (sb->s_iflags & SB_I_UID_R);
+}
+
+static inline bool sb_can_own_kgid(const struct super_block *sb, kgid_t kgid)
+{
+	return gid_is_legacy(kgid) || (sb->s_iflags & SB_I_UID_R);
+}
+
 /**
  * fsuidgid_has_mapping() - check whether caller's fsuid/fsgid is mapped
  * @sb: the superblock we want a mapping in
  * @idmap: idmap of the relevant mount
  *
  * Check whether the caller's fsuid and fsgid have a valid mapping in the
- * s_user_ns of the superblock @sb. If the caller is on an idmapped mount map
- * the caller's fsuid and fsgid according to the @idmap first.
+ * s_user_ns of the superblock @sb, and whether @sb can store them as owner
+ * of a new inode. If the caller is on an idmapped mount map the caller's
+ * fsuid and fsgid according to the @idmap first.
  *
  * Return: true if fsuid and fsgid is mapped, false if not.
  */
@@ -1582,10 +1603,10 @@ static inline bool fsuidgid_has_mapping(struct super_block *sb,
 	kgid_t kgid;
 
 	kuid = mapped_fsuid(idmap, fs_userns);
-	if (!uid_valid(kuid))
+	if (!uid_valid(kuid) || !sb_can_own_kuid(sb, kuid))
 		return false;
 	kgid = mapped_fsgid(idmap, fs_userns);
-	if (!gid_valid(kgid))
+	if (!gid_valid(kgid) || !sb_can_own_kgid(sb, kgid))
 		return false;
 	return kuid_has_mapping(fs_userns, kuid) &&
 	       kgid_has_mapping(fs_userns, kgid);
diff --git a/include/linux/fs/super_types.h b/include/linux/fs/super_types.h
index ecd96aeb1c..1f5c596b18 100644
--- a/include/linux/fs/super_types.h
+++ b/include/linux/fs/super_types.h
@@ -352,5 +352,6 @@ struct super_block {
 #define SB_I_NOIDMAP	0x00002000	/* No idmapped mounts on this superblock */
 #define SB_I_ALLOW_HSM	0x00004000	/* Allow HSM events on this superblock */
 #define SB_I_NO_DATA_INTEGRITY	0x00008000 /* fs cannot guarantee data persistence on sync */
+#define SB_I_UID_R	0x00010000	/* fs stores UUID and GUID owners, not just classic ids */
 
 #endif /* _LINUX_FS_SUPER_TYPES_H */
-- 
2.56.0




More information about the Linux-security-module-archive mailing list