[RFC PATCH v2 39/41] ksmbd: log in UUID and GUID users and map them to SIDs

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


A user whose ids are UUIDs or GUIDs could not use ksmbd: the login
response carries 32 bit ids, sessions ran as make_kuid(uid), and SIDs
were built from from_kuid_munged(), so such users and their files all
became the overflow id.

Take the ids from the login response extension: flags, formerly
reserved and zero, has KSMBD_LOGIN_EXT_ID_R when uid_r and gid_r (also
formerly reserved) hold the user's ids as __kernel_uid_r_t, and
KSMBD_LOGIN_EXT_GROUPS_R when the payload holds __kernel_gid_r_t
supplementary groups instead of gid_t. struct ksmbd_user keeps kuid,
kgid and kgid_t groups, which the session's credentials and durable
handle owners use.

UUID and GUID users and groups have no RID; they are represented as
S-1-22-<kind>-w0-w1-w2-w3 (kind 3/4: UUID user/group, 5/6: GUID
user/group; w0..w3 the 16 bytes as big endian words), next to the
existing S-1-22-1-<uid> and S-1-22-2-<gid>, in security descriptors,
inherited ACEs, POSIX ACL entries and owner changes from clients.

The SMB3 POSIX extension's fixed 16 and 28 byte SID buffers can't hold
such a SID; they keep showing the overflow id.

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

Signed-off-by: Jan Koester <jan.koester at tuxist.de>
---
 fs/smb/server/ksmbd_netlink.h    |  15 ++-
 fs/smb/server/mgmt/user_config.c |  35 +++++-
 fs/smb/server/mgmt/user_config.h |   4 +-
 fs/smb/server/smb2pdu.c          |  10 +-
 fs/smb/server/smb_common.c       |  18 ++--
 fs/smb/server/smbacl.c           | 178 ++++++++++++++++++++++++-------
 fs/smb/server/smbacl.h           |  19 +++-
 fs/smb/server/transport_ipc.c    |   4 +-
 fs/smb/server/vfs_cache.c        |   9 +-
 fs/smb/server/vfs_cache.h        |   4 +-
 10 files changed, 229 insertions(+), 67 deletions(-)

diff --git a/fs/smb/server/ksmbd_netlink.h b/fs/smb/server/ksmbd_netlink.h
index 2673522c76..0d92d3fd4f 100644
--- a/fs/smb/server/ksmbd_netlink.h
+++ b/fs/smb/server/ksmbd_netlink.h
@@ -9,6 +9,7 @@
 #define _LINUX_KSMBD_SERVER_H
 
 #include <linux/types.h>
+#include <linux/uidgid_r.h>
 
 /*
  * This is a userspace ABI to communicate data between ksmbd and user IPC
@@ -153,14 +154,26 @@ struct ksmbd_login_response {
 
 /*
  * IPC user login response extension.
+ *
+ * With KSMBD_LOGIN_EXT_ID_R, uid_r and gid_r are the user's ids and may be
+ * UUIDs or GUIDs (see Documentation/userspace-api/uid_r.rst); the response's
+ * uid and gid are then ignored. With KSMBD_LOGIN_EXT_GROUPS_R the payload
+ * holds ngroups __kernel_gid_r_t instead of ngroups gid_t. A user space
+ * that knows neither leaves flags (formerly reserved) zero.
  */
 struct ksmbd_login_response_ext {
 	__u32	handle;
 	__s32	ngroups;			/* supplementary group count */
-	__s8	reserved[128];			/* Reserved room */
+	__u32	flags;				/* KSMBD_LOGIN_EXT_* */
+	__kernel_uid_r_t uid_r;			/* with KSMBD_LOGIN_EXT_ID_R */
+	__kernel_gid_r_t gid_r;
+	__s8	reserved[84];			/* Reserved room */
 	__s8	____payload[];
 };
 
+#define KSMBD_LOGIN_EXT_ID_R		0x1
+#define KSMBD_LOGIN_EXT_GROUPS_R	0x2
+
 /*
  * IPC request to fetch net share config.
  */
diff --git a/fs/smb/server/mgmt/user_config.c b/fs/smb/server/mgmt/user_config.c
index 5efc3d7455..cb175a4c78 100644
--- a/fs/smb/server/mgmt/user_config.c
+++ b/fs/smb/server/mgmt/user_config.c
@@ -56,6 +56,8 @@ struct ksmbd_user *ksmbd_alloc_user(struct ksmbd_login_response *resp,
 	user->flags = resp->status;
 	user->gid = resp->gid;
 	user->uid = resp->uid;
+	user->kuid = make_kuid(&init_user_ns, resp->uid);
+	user->kgid = make_kgid(&init_user_ns, resp->gid);
 	user->passkey_sz = resp->hash_sz;
 	user->passkey = kmalloc(resp->hash_sz, KSMBD_DEFAULT_GFP);
 	if (user->passkey)
@@ -68,12 +70,38 @@ struct ksmbd_user *ksmbd_alloc_user(struct ksmbd_login_response *resp,
 		goto err_free;
 
 	if (resp_ext) {
-		user->sgid = kmemdup(resp_ext->____payload,
-				     resp_ext->ngroups * sizeof(gid_t),
+		int i;
+
+		if (resp_ext->flags & KSMBD_LOGIN_EXT_ID_R) {
+			/* the user's ids may be UUIDs or GUIDs */
+			user->kuid = make_kuid_r(&init_user_ns, &resp_ext->uid_r);
+			user->kgid = make_kgid_r(&init_user_ns, &resp_ext->gid_r);
+			if (!uid_valid(user->kuid) || !gid_valid(user->kgid))
+				goto err_free;
+			user->uid = from_kuid_munged(&init_user_ns, user->kuid);
+			user->gid = from_kgid_munged(&init_user_ns, user->kgid);
+		}
+
+		user->sgid = kcalloc(resp_ext->ngroups, sizeof(kgid_t),
 				     KSMBD_DEFAULT_GFP);
-		if (!user->sgid)
+		if (!user->sgid && resp_ext->ngroups)
 			goto err_free;
 
+		for (i = 0; i < resp_ext->ngroups; i++) {
+			if (resp_ext->flags & KSMBD_LOGIN_EXT_GROUPS_R) {
+				const __kernel_gid_r_t *g = (const __kernel_gid_r_t *)
+					resp_ext->____payload + i;
+
+				user->sgid[i] = make_kgid_r(&init_user_ns, g);
+			} else {
+				const gid_t *g = (const gid_t *)resp_ext->____payload + i;
+
+				user->sgid[i] = make_kgid(&init_user_ns, *g);
+			}
+			if (!gid_valid(user->sgid[i]))
+				goto err_free;
+		}
+
 		user->ngroups = resp_ext->ngroups;
 		ksmbd_debug(SMB, "supplementary groups : %d\n", user->ngroups);
 	}
@@ -81,6 +109,7 @@ struct ksmbd_user *ksmbd_alloc_user(struct ksmbd_login_response *resp,
 	return user;
 
 err_free:
+	kfree(user->sgid);
 	kfree(user->name);
 	kfree_sensitive(user->passkey);
 	kfree(user);
diff --git a/fs/smb/server/mgmt/user_config.h b/fs/smb/server/mgmt/user_config.h
index cc460b4ff7..e55470e008 100644
--- a/fs/smb/server/mgmt/user_config.h
+++ b/fs/smb/server/mgmt/user_config.h
@@ -13,13 +13,15 @@ struct ksmbd_user {
 
 	unsigned int		uid;
 	unsigned int		gid;
+	kuid_t			kuid;	/* the user: uid, or a UUID or GUID */
+	kgid_t			kgid;
 
 	char			*name;
 
 	size_t			passkey_sz;
 	char			*passkey;
 	int			ngroups;
-	gid_t			*sgid;
+	kgid_t			*sgid;
 };
 
 static inline bool user_guest(struct ksmbd_user *user)
diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
index 6b8809f67b..ba29f9436e 100644
--- a/fs/smb/server/smb2pdu.c
+++ b/fs/smb/server/smb2pdu.c
@@ -4577,14 +4577,14 @@ int smb2_open(struct ksmbd_work *work)
 	if (file_present && !(req->CreateOptions & FILE_DELETE_ON_CLOSE_LE)) {
 		rc = smb_check_perm_dacl(conn, &path, &daccess,
 					 req->DesiredAccess,
-					 sess->user->uid, false);
+					 sess->user->kuid, false);
 		if (rc)
 			goto err_out;
 
 		if (maximal_access_ctxt) {
 			maximal_access = FILE_MAXIMAL_ACCESS_LE;
 			rc = smb_check_perm_dacl(conn, &path, &maximal_access,
-						 0, sess->user->uid, false);
+						 0, sess->user->kuid, false);
 			if (rc)
 				goto err_out;
 
@@ -4776,8 +4776,8 @@ int smb2_open(struct ksmbd_work *work)
 		if (rc == -ENOENT) {
 			if (test_share_config_flag(work->tcon->share_conf,
 						   KSMBD_SHARE_FLAG_ACL_XATTR)) {
-				rc = smb_inherit_dacl(conn, &path, sess->user->uid,
-						      sess->user->gid);
+				rc = smb_inherit_dacl(conn, &path, sess->user->kuid,
+						      sess->user->kgid);
 			}
 			if (rc) {
 				if (posix_acl_rc)
@@ -5837,7 +5837,7 @@ static int process_query_dir_entries(struct smb2_query_dir_private *priv)
 			path.dentry = dent;
 			rc = smb_check_perm_dacl(priv->work->conn, &path,
 						 &daccess, daccess,
-						 priv->work->sess->user->uid,
+						 priv->work->sess->user->kuid,
 						 true);
 			if (rc) {
 				dput(dent);
diff --git a/fs/smb/server/smb_common.c b/fs/smb/server/smb_common.c
index 4c2da65510..ace3421e57 100644
--- a/fs/smb/server/smb_common.c
+++ b/fs/smb/server/smb_common.c
@@ -797,23 +797,23 @@ int __ksmbd_override_fsids(struct ksmbd_work *work,
 	struct ksmbd_user *user = sess->user;
 	struct cred *cred;
 	struct group_info *gi;
-	unsigned int uid;
-	unsigned int gid;
+	kuid_t uid;
+	kgid_t gid;
 	int i;
 
-	uid = user_uid(user);
-	gid = user_gid(user);
+	uid = user->kuid;
+	gid = user->kgid;
 	if (share->force_uid != KSMBD_SHARE_INVALID_UID)
-		uid = share->force_uid;
+		uid = make_kuid(&init_user_ns, share->force_uid);
 	if (share->force_gid != KSMBD_SHARE_INVALID_GID)
-		gid = share->force_gid;
+		gid = make_kgid(&init_user_ns, share->force_gid);
 
 	cred = prepare_kernel_cred(&init_task);
 	if (!cred)
 		return -ENOMEM;
 
-	cred->fsuid = make_kuid(&init_user_ns, uid);
-	cred->fsgid = make_kgid(&init_user_ns, gid);
+	cred->fsuid = uid;
+	cred->fsgid = gid;
 
 	gi = groups_alloc(user->ngroups);
 	if (!gi) {
@@ -822,7 +822,7 @@ int __ksmbd_override_fsids(struct ksmbd_work *work,
 	}
 
 	for (i = 0; i < user->ngroups; i++)
-		gi->gid[i] = make_kgid(&init_user_ns, user->sgid[i]);
+		gi->gid[i] = user->sgid[i];
 
 	if (user->ngroups)
 		groups_sort(gi);
diff --git a/fs/smb/server/smbacl.c b/fs/smb/server/smbacl.c
index 1fad6ccf3a..126264cc07 100644
--- a/fs/smb/server/smbacl.c
+++ b/fs/smb/server/smbacl.c
@@ -7,6 +7,7 @@
  */
 
 #include <linux/fs.h>
+#include <linux/unaligned.h>
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/mnt_idmapping.h>
@@ -257,6 +258,67 @@ void id_to_sid(unsigned int cid, uint sidtype, struct smb_sid *ssid)
 	ssid->num_subauth++;
 }
 
+/*
+ * UUID and GUID users and groups (Documentation/userspace-api/uid_r.rst)
+ * have no RID: they are S-1-22-<kind>-w0-w1-w2-w3, the 16 bytes of the id
+ * as four big endian words, next to S-1-22-1-<uid> and S-1-22-2-<gid>.
+ */
+#define SID_UNIX_UUID_USER	3
+#define SID_UNIX_UUID_GROUP	4
+#define SID_UNIX_GUID_USER	5
+#define SID_UNIX_GUID_GROUP	6
+
+static void id_r_to_sid(u32 kind, const u8 *id, struct smb_sid *ssid)
+{
+	int i;
+
+	smb_copy_sid(ssid, &sid_unix_users);
+	ssid->sub_auth[0] = cpu_to_le32(kind);
+	for (i = 0; i < 4; i++)
+		ssid->sub_auth[1 + i] = cpu_to_le32(get_unaligned_be32(id + 4 * i));
+	ssid->num_subauth = 5;
+}
+
+/* the kind (SID_UNIX_*) and 16 bytes of a UUID or GUID SID, or 0 */
+static u32 sid_to_id_r(const struct smb_sid *psid, u8 *id)
+{
+	u32 kind;
+	int i;
+
+	if (psid->num_subauth != 5 || psid->revision != sid_unix_users.revision ||
+	    memcmp(psid->authority, sid_unix_users.authority, NUM_AUTHS))
+		return 0;
+	kind = le32_to_cpu(psid->sub_auth[0]);
+	if (kind < SID_UNIX_UUID_USER || kind > SID_UNIX_GUID_GROUP)
+		return 0;
+	for (i = 0; i < 4; i++)
+		put_unaligned_be32(le32_to_cpu(psid->sub_auth[1 + i]), id + 4 * i);
+	return kind;
+}
+
+/* id_to_sid() for any kuid: a classic one gets the usual SIDs */
+void ksmbd_uid_to_sid(kuid_t uid, uint sidtype, struct smb_sid *ssid)
+{
+	if (uid_is_legacy(uid) || sidtype == SIDCREATOR_OWNER ||
+	    sidtype == SIDCREATOR_GROUP)
+		id_to_sid(from_kuid_munged(&init_user_ns, uid), sidtype, ssid);
+	else if (uid.type == KID_UUID)
+		id_r_to_sid(SID_UNIX_UUID_USER, uid.uuid.b, ssid);
+	else
+		id_r_to_sid(SID_UNIX_GUID_USER, uid.guid.b, ssid);
+}
+
+void ksmbd_gid_to_sid(kgid_t gid, uint sidtype, struct smb_sid *ssid)
+{
+	if (gid_is_legacy(gid) || sidtype == SIDCREATOR_OWNER ||
+	    sidtype == SIDCREATOR_GROUP)
+		id_to_sid(from_kgid_munged(&init_user_ns, gid), sidtype, ssid);
+	else if (gid.type == KID_UUID)
+		id_r_to_sid(SID_UNIX_UUID_GROUP, gid.uuid.b, ssid);
+	else
+		id_r_to_sid(SID_UNIX_GUID_GROUP, gid.guid.b, ssid);
+}
+
 static int sid_to_id(struct mnt_idmap *idmap,
 		     struct smb_sid *psid, uint sidtype,
 		     struct smb_fattr *fattr)
@@ -279,6 +341,42 @@ static int sid_to_id(struct mnt_idmap *idmap,
 		return -EIO;
 	}
 
+	{
+		u8 id[16];
+		u32 kind = sid_to_id_r(psid, id);
+
+		if (kind && sidtype == SIDOWNER &&
+		    (kind == SID_UNIX_UUID_USER || kind == SID_UNIX_GUID_USER)) {
+			kuid_t uid;
+
+			if (kind == SID_UNIX_UUID_USER)
+				uid = KUIDT_INIT_UUID(*(uuid_t *)id);
+			else
+				uid = KUIDT_INIT_GUID(*(guid_t *)id);
+			uid = from_vfsuid(idmap, &init_user_ns, VFSUIDT_INIT(uid));
+			if (!uid_valid(uid))
+				return -EINVAL;
+			fattr->cf_uid = uid;
+			return 0;
+		}
+		if (kind && sidtype != SIDOWNER &&
+		    (kind == SID_UNIX_UUID_GROUP || kind == SID_UNIX_GUID_GROUP)) {
+			kgid_t gid;
+
+			if (kind == SID_UNIX_UUID_GROUP)
+				gid = KGIDT_INIT_UUID(*(uuid_t *)id);
+			else
+				gid = KGIDT_INIT_GUID(*(guid_t *)id);
+			gid = from_vfsgid(idmap, &init_user_ns, VFSGIDT_INIT(gid));
+			if (!gid_valid(gid))
+				return -EINVAL;
+			fattr->cf_gid = gid;
+			return 0;
+		}
+		if (kind)
+			return -EINVAL;
+	}
+
 	if (sidtype == SIDOWNER) {
 		kuid_t uid;
 		uid_t id;
@@ -643,18 +741,18 @@ static void set_posix_acl_entries_dacl(struct mnt_idmap *idmap,
 			break;
 
 		if (pace->e_tag == ACL_USER) {
-			uid_t uid;
+			kuid_t uid;
 			unsigned int sid_type = SIDOWNER;
 
-			uid = posix_acl_uid_translate(idmap, pace);
-			if (!uid)
+			uid = posix_acl_kuid_translate(idmap, pace);
+			if (uid_eq(uid, GLOBAL_ROOT_UID))
 				sid_type = SIDUNIX_USER;
-			id_to_sid(uid, sid_type, sid);
+			ksmbd_uid_to_sid(uid, sid_type, sid);
 		} else if (pace->e_tag == ACL_GROUP) {
-			gid_t gid;
+			kgid_t gid;
 
-			gid = posix_acl_gid_translate(idmap, pace);
-			id_to_sid(gid, SIDUNIX_GROUP, sid);
+			gid = posix_acl_kgid_translate(idmap, pace);
+			ksmbd_gid_to_sid(gid, SIDUNIX_GROUP, sid);
 		} else if (pace->e_tag == ACL_OTHER && !had_nt_aces) {
 			smb_copy_sid(sid, &sid_everyone);
 		} else {
@@ -816,7 +914,7 @@ static void set_mode_dacl(struct mnt_idmap *idmap,
 	u16 num_aces = 0;
 	u16 size = 0, ace_size = 0;
 	uid_t uid;
-	const struct smb_sid *sid;
+	struct smb_sid owner_sid, group_sid;
 
 	pace = pndace = (struct smb_ace *)((char *)pndacl + sizeof(struct smb_acl));
 
@@ -826,25 +924,20 @@ static void set_mode_dacl(struct mnt_idmap *idmap,
 		goto out;
 	}
 
-	/* owner RID */
+	/* owner: RID, or a UUID or GUID SID */
 	uid = from_kuid(&init_user_ns, fattr->cf_uid);
-	if (uid)
-		sid = &server_conf.domain_sid;
-	else
-		sid = &sid_unix_users;
-	ace_size = fill_ace_for_sid(pace, sid, ACCESS_ALLOWED, 0,
+	ksmbd_uid_to_sid(fattr->cf_uid, uid ? SIDOWNER : SIDUNIX_USER, &owner_sid);
+	ace_size = fill_ace_for_sid(pace, &owner_sid, ACCESS_ALLOWED, 0,
 				    fattr->cf_mode, 0700);
-	pace->sid.sub_auth[pace->sid.num_subauth++] = cpu_to_le32(uid);
-	pace->size = cpu_to_le16(ace_size + 4);
+	pace->size = cpu_to_le16(ace_size);
 	size += le16_to_cpu(pace->size);
 	pace = (struct smb_ace *)((char *)pndace + size);
 
-	/* Group RID */
-	ace_size = fill_ace_for_sid(pace, &sid_unix_groups,
+	/* Group: RID, or a UUID or GUID SID */
+	ksmbd_gid_to_sid(fattr->cf_gid, SIDUNIX_GROUP, &group_sid);
+	ace_size = fill_ace_for_sid(pace, &group_sid,
 				    ACCESS_ALLOWED, 0, fattr->cf_mode, 0070);
-	pace->sid.sub_auth[pace->sid.num_subauth++] =
-		cpu_to_le32(from_kgid(&init_user_ns, fattr->cf_gid));
-	pace->size = cpu_to_le16(ace_size + 4);
+	pace->size = cpu_to_le16(ace_size);
 	size += le16_to_cpu(pace->size);
 	pace = (struct smb_ace *)((char *)pndace + size);
 	num_aces = 3;
@@ -1041,7 +1134,6 @@ int build_sec_desc(struct mnt_idmap *idmap,
 	struct smb_sid *nowner_sid_ptr, *ngroup_sid_ptr;
 	struct smb_acl *dacl_ptr = NULL; /* no need for SACL ptr */
 	uid_t uid;
-	gid_t gid;
 	unsigned int sid_type = SIDOWNER;
 
 	nowner_sid_ptr = kmalloc_obj(struct smb_sid, KSMBD_DEFAULT_GFP);
@@ -1051,7 +1143,7 @@ int build_sec_desc(struct mnt_idmap *idmap,
 	uid = from_kuid(&init_user_ns, fattr->cf_uid);
 	if (!uid)
 		sid_type = SIDUNIX_USER;
-	id_to_sid(uid, sid_type, nowner_sid_ptr);
+	ksmbd_uid_to_sid(fattr->cf_uid, sid_type, nowner_sid_ptr);
 
 	ngroup_sid_ptr = kmalloc_obj(struct smb_sid, KSMBD_DEFAULT_GFP);
 	if (!ngroup_sid_ptr) {
@@ -1059,8 +1151,7 @@ int build_sec_desc(struct mnt_idmap *idmap,
 		return -ENOMEM;
 	}
 
-	gid = from_kgid(&init_user_ns, fattr->cf_gid);
-	id_to_sid(gid, SIDUNIX_GROUP, ngroup_sid_ptr);
+	ksmbd_gid_to_sid(fattr->cf_gid, SIDUNIX_GROUP, ngroup_sid_ptr);
 
 	offset = sizeof(struct smb_ntsd);
 	pntsd->sacloffset = 0;
@@ -1188,7 +1279,7 @@ static int smb_validate_ntsd_sid(struct smb_ntsd *pntsd, size_t pntsd_size,
 
 int smb_inherit_dacl(struct ksmbd_conn *conn,
 		     const struct path *path,
-		     unsigned int uid, unsigned int gid)
+		     kuid_t uid, kgid_t gid)
 {
 	const struct smb_sid *psid, *creator = NULL;
 	struct smb_ace *parent_aces, *aces;
@@ -1295,11 +1386,11 @@ int smb_inherit_dacl(struct ksmbd_conn *conn,
 
 		if (!compare_sids(&creator_owner, &parent_aces->sid)) {
 			creator = &creator_owner;
-			id_to_sid(uid, SIDOWNER, &owner_sid);
+			ksmbd_uid_to_sid(uid, SIDOWNER, &owner_sid);
 			psid = &owner_sid;
 		} else if (!compare_sids(&creator_group, &parent_aces->sid)) {
 			creator = &creator_group;
-			id_to_sid(gid, SIDUNIX_GROUP, &group_sid);
+			ksmbd_gid_to_sid(gid, SIDUNIX_GROUP, &group_sid);
 			psid = &group_sid;
 		} else {
 			creator = NULL;
@@ -1448,7 +1539,7 @@ bool smb_inherit_flags(int flags, bool is_dir)
 }
 
 int smb_check_perm_dacl(struct ksmbd_conn *conn, const struct path *path,
-			__le32 *pdaccess, __le32 raw_daccess, int uid,
+			__le32 *pdaccess, __le32 raw_daccess, kuid_t uid,
 			bool strict)
 {
 	struct mnt_idmap *idmap = mnt_idmap(path->mnt);
@@ -1499,11 +1590,11 @@ int smb_check_perm_dacl(struct ksmbd_conn *conn, const struct path *path,
 		goto err_out;
 	}
 
-	if (!uid)
+	if (uid_eq(uid, GLOBAL_ROOT_UID))
 		sid_type = SIDUNIX_USER;
-	id_to_sid(uid, sid_type, &sid);
+	ksmbd_uid_to_sid(uid, sid_type, &sid);
 	vfsuid = i_uid_into_vfsuid(idmap, d_inode(path->dentry));
-	is_owner = uid == from_kuid(&init_user_ns, vfsuid_into_kuid(vfsuid));
+	is_owner = uid_eq(uid, vfsuid_into_kuid(vfsuid));
 
 	if (*pdaccess & FILE_MAXIMAL_ACCESS_LE) {
 		ace = (struct smb_ace *)((char *)pdacl + sizeof(struct smb_acl));
@@ -1596,18 +1687,27 @@ int smb_check_perm_dacl(struct ksmbd_conn *conn, const struct path *path,
 	if (IS_ENABLED(CONFIG_FS_POSIX_ACL)) {
 		posix_acls = get_inode_acl(d_inode(path->dentry), ACL_TYPE_ACCESS);
 		if (!IS_ERR_OR_NULL(posix_acls) && !found && !others_ace) {
-			unsigned int id = -1;
+			kuid_t pa_uid;
+			bool match;
 
 			pa_entry = posix_acls->a_entries;
 			for (i = 0; i < posix_acls->a_count; i++, pa_entry++) {
-				if (pa_entry->e_tag == ACL_USER)
-					id = posix_acl_uid_translate(idmap, pa_entry);
-				else if (pa_entry->e_tag == ACL_GROUP)
-					id = posix_acl_gid_translate(idmap, pa_entry);
-				else
+				/*
+				 * A group entry matches a gid equal to the uid,
+				 * as it always has.
+				 */
+				if (pa_entry->e_tag == ACL_USER) {
+					pa_uid = posix_acl_kuid_translate(idmap, pa_entry);
+					match = uid_eq(pa_uid, uid);
+				} else if (pa_entry->e_tag == ACL_GROUP) {
+					match = uid_is_legacy(uid) &&
+						posix_acl_gid_translate(idmap, pa_entry) ==
+						from_kuid(&init_user_ns, uid);
+				} else {
 					continue;
+				}
 
-				if (id == uid) {
+				if (match) {
 					mode_to_access_flags(pa_entry->e_perm,
 							     0777,
 							     &access_bits);
diff --git a/fs/smb/server/smbacl.h b/fs/smb/server/smbacl.h
index 01810c16cc..b6a01f0d45 100644
--- a/fs/smb/server/smbacl.h
+++ b/fs/smb/server/smbacl.h
@@ -93,18 +93,33 @@ void posix_state_to_acl(struct posix_acl_state *state,
 int compare_sids(const struct smb_sid *ctsid, const struct smb_sid *cwsid);
 bool smb_inherit_flags(int flags, bool is_dir);
 int smb_inherit_dacl(struct ksmbd_conn *conn, const struct path *path,
-		     unsigned int uid, unsigned int gid);
+		     kuid_t uid, kgid_t gid);
 int smb_check_perm_dacl(struct ksmbd_conn *conn, const struct path *path,
-			__le32 *pdaccess, __le32 raw_daccess, int uid,
+			__le32 *pdaccess, __le32 raw_daccess, kuid_t uid,
 			bool strict);
 int set_info_sec(struct ksmbd_conn *conn, struct ksmbd_tree_connect *tcon,
 		 const struct path *path, struct smb_ntsd *pntsd, int ntsd_len,
 		 bool type_check, bool get_write);
 void id_to_sid(unsigned int cid, uint sidtype, struct smb_sid *ssid);
+void ksmbd_uid_to_sid(kuid_t uid, uint sidtype, struct smb_sid *ssid);
+void ksmbd_gid_to_sid(kgid_t gid, uint sidtype, struct smb_sid *ssid);
 void ksmbd_init_domain(u32 *sub_auth);
 size_t smb_acl_sec_desc_scratch_len(struct smb_fattr *fattr,
 		struct smb_ntsd *ppntsd, int ppntsd_size, int addition_info);
 
+/* the owner of an ACL entry as a kuid (also a UUID or GUID) */
+static inline kuid_t posix_acl_kuid_translate(struct mnt_idmap *idmap,
+					      struct posix_acl_entry *pace)
+{
+	return vfsuid_into_kuid(make_vfsuid(idmap, &init_user_ns, pace->e_uid));
+}
+
+static inline kgid_t posix_acl_kgid_translate(struct mnt_idmap *idmap,
+					      struct posix_acl_entry *pace)
+{
+	return vfsgid_into_kgid(make_vfsgid(idmap, &init_user_ns, pace->e_gid));
+}
+
 static inline uid_t posix_acl_uid_translate(struct mnt_idmap *idmap,
 					    struct posix_acl_entry *pace)
 {
diff --git a/fs/smb/server/transport_ipc.c b/fs/smb/server/transport_ipc.c
index e550aa41ad..71270c780d 100644
--- a/fs/smb/server/transport_ipc.c
+++ b/fs/smb/server/transport_ipc.c
@@ -564,7 +564,9 @@ static int ipc_validate_msg(struct ipc_msg_table_entry *entry)
 				return -EINVAL;
 			}
 			msg_sz = sizeof(struct ksmbd_login_response_ext) +
-					resp->ngroups * sizeof(gid_t);
+					resp->ngroups *
+					(resp->flags & KSMBD_LOGIN_EXT_GROUPS_R ?
+					 sizeof(__kernel_gid_r_t) : sizeof(gid_t));
 		}
 	}
 	}
diff --git a/fs/smb/server/vfs_cache.c b/fs/smb/server/vfs_cache.c
index fd2c595f04..89686cfc67 100644
--- a/fs/smb/server/vfs_cache.c
+++ b/fs/smb/server/vfs_cache.c
@@ -1715,8 +1715,8 @@ int ksmbd_vfs_set_durable_owner(struct ksmbd_file *fp,
 
 	spin_lock(&fp->f_lock);
 	old_name = fp->owner.name;
-	fp->owner.uid = user->uid;
-	fp->owner.gid = user->gid;
+	fp->owner.uid = user->kuid;
+	fp->owner.gid = user->kgid;
 	fp->owner.name = name;
 	spin_unlock(&fp->f_lock);
 	kfree(old_name);
@@ -1747,7 +1747,7 @@ bool ksmbd_vfs_compare_durable_owner(struct ksmbd_file *fp,
 		goto out;
 
 	/* Check if the UID and GID match first (fast path) */
-	if (fp->owner.uid != user->uid || fp->owner.gid != user->gid)
+	if (!uid_eq(fp->owner.uid, user->kuid) || !gid_eq(fp->owner.gid, user->kgid))
 		goto out;
 
 	/* Validate the account name to ensure the same SecurityContext */
@@ -1953,7 +1953,8 @@ int ksmbd_reopen_durable_fd(struct ksmbd_work *work, struct ksmbd_file *fp)
 	up_write(&ci->m_lock);
 
 	spin_lock(&fp->f_lock);
-	fp->owner.uid = fp->owner.gid = 0;
+	fp->owner.uid = GLOBAL_ROOT_UID;
+	fp->owner.gid = GLOBAL_ROOT_GID;
 	kfree(fp->owner.name);
 	fp->owner.name = NULL;
 	spin_unlock(&fp->f_lock);
diff --git a/fs/smb/server/vfs_cache.h b/fs/smb/server/vfs_cache.h
index 1884f6deb9..396e11f88c 100644
--- a/fs/smb/server/vfs_cache.h
+++ b/fs/smb/server/vfs_cache.h
@@ -77,8 +77,8 @@ enum {
 
 /* Owner information for durable handle reconnect */
 struct durable_owner {
-	unsigned int uid;
-	unsigned int gid;
+	kuid_t		uid;
+	kgid_t		gid;
 	char *name;
 };
 
-- 
2.56.0




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