changeset 21396:a1dd191628fc

10991 Allow user ACE in ACL to match SID in token extra SIDs Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com> Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com> Reviewed by: Evan Layton <evan.layton@nexenta.com> Reviewed by: Rick McNeal <rick.mcneal@nexenta.com> Reviewed by: Joyce McIntosh <joyce.mcintosh@nexenta.com> Reviewed by: Garrett D'Amore <garrett@damore.org> Reviewed by: Gergő Doma <domag02@gmail.com> Approved by: Dan McDonald <danmcd@joyent.com>
author Gordon Ross <gwr@nexenta.com>
date Tue, 17 Oct 2017 10:04:43 -0400
parents b2bf0d068923
children cc6857011980
files usr/src/uts/common/fs/zfs/sys/zfs_fuid.h usr/src/uts/common/fs/zfs/zfs_acl.c usr/src/uts/common/fs/zfs/zfs_fuid.c
diffstat 3 files changed, 72 insertions(+), 28 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/uts/common/fs/zfs/sys/zfs_fuid.h	Thu May 23 22:54:25 2019 +0000
+++ b/usr/src/uts/common/fs/zfs/sys/zfs_fuid.h	Tue Oct 17 10:04:43 2017 -0400
@@ -21,6 +21,8 @@
 /*
  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
+ *
+ * Copyright 2017 Nexenta Systems, Inc.  All rights reserved.
  */
 
 #ifndef	_SYS_FS_ZFS_FUID_H
@@ -70,8 +72,8 @@
  * Used for mapping ephemeral uid/gid during ACL setting to FUIDs
  */
 typedef struct zfs_fuid {
-	list_node_t 	z_next;
-	uint64_t 	z_id;		/* uid/gid being converted to fuid */
+	list_node_t	z_next;
+	uint64_t	z_id;		/* uid/gid being converted to fuid */
 	uint64_t	z_domidx;	/* index in AVL domain table */
 	uint64_t	z_logfuid;	/* index for domain in log */
 } zfs_fuid_t;
@@ -111,6 +113,7 @@
     uid_t *uid, uid_t *gid);
 extern zfs_fuid_info_t *zfs_fuid_info_alloc(void);
 extern void zfs_fuid_info_free(zfs_fuid_info_t *);
+extern boolean_t zfs_user_in_cred(zfsvfs_t *, uint64_t, cred_t *);
 extern boolean_t zfs_groupmember(zfsvfs_t *, uint64_t, cred_t *);
 void zfs_fuid_sync(zfsvfs_t *, dmu_tx_t *);
 extern int zfs_fuid_find_by_domain(zfsvfs_t *, const char *domain,
--- a/usr/src/uts/common/fs/zfs/zfs_acl.c	Thu May 23 22:54:25 2019 +0000
+++ b/usr/src/uts/common/fs/zfs/zfs_acl.c	Tue Oct 17 10:04:43 2017 -0400
@@ -2106,18 +2106,13 @@
 	zfsvfs_t	*zfsvfs = zp->z_zfsvfs;
 	zfs_acl_t	*aclp;
 	int		error;
-	uid_t		uid = crgetuid(cr);
-	uint64_t	who;
+	uint64_t	who;		/* FUID from the ACE */
 	uint16_t	type, iflags;
 	uint16_t	entry_type;
 	uint32_t	access_mask;
 	uint32_t	deny_mask = 0;
 	zfs_ace_hdr_t	*acep = NULL;
-	boolean_t	checkit;
-	uid_t		gowner;
-	uid_t		fowner;
-
-	zfs_fuid_map_ids(zp, cr, &fowner, &gowner);
+	boolean_t	checkit;	/* ACE ID matches */
 
 	mutex_enter(&zp->z_acl_lock);
 
@@ -2150,11 +2145,13 @@
 
 		switch (entry_type) {
 		case ACE_OWNER:
-			if (uid == fowner)
-				checkit = B_TRUE;
+			who = zp->z_uid;
+			/*FALLTHROUGH*/
+		case 0:	/* USER Entry */
+			checkit = zfs_user_in_cred(zfsvfs, who, cr);
 			break;
 		case OWNING_GROUP:
-			who = gowner;
+			who = zp->z_gid;
 			/*FALLTHROUGH*/
 		case ACE_IDENTIFIER_GROUP:
 			checkit = zfs_groupmember(zfsvfs, who, cr);
@@ -2163,21 +2160,13 @@
 			checkit = B_TRUE;
 			break;
 
-		/* USER Entry */
 		default:
-			if (entry_type == 0) {
-				uid_t newid;
-
-				newid = zfs_fuid_map_id(zfsvfs, who, cr,
-				    ZFS_ACE_USER);
-				if (newid != IDMAP_WK_CREATOR_OWNER_UID &&
-				    uid == newid)
-					checkit = B_TRUE;
-				break;
-			} else {
-				mutex_exit(&zp->z_acl_lock);
-				return (SET_ERROR(EIO));
-			}
+			/*
+			 * The zfs_acl_valid_ace_type check above
+			 * should make this case impossible.
+			 */
+			mutex_exit(&zp->z_acl_lock);
+			return (SET_ERROR(EIO));
 		}
 
 		if (checkit) {
--- a/usr/src/uts/common/fs/zfs/zfs_fuid.c	Thu May 23 22:54:25 2019 +0000
+++ b/usr/src/uts/common/fs/zfs/zfs_fuid.c	Tue Oct 17 10:04:43 2017 -0400
@@ -20,6 +20,7 @@
  */
 /*
  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
  */
 
 #include <sys/zfs_context.h>
@@ -492,7 +493,7 @@
 	uint64_t	idx;
 	ksid_t		*ksid;
 	uint32_t	rid;
-	char 		*kdomain;
+	char		*kdomain;
 	const char	*domain;
 	uid_t		id;
 
@@ -685,6 +686,57 @@
 }
 
 /*
+ * Check to see if user ID is in the list of SIDs in CR.
+ */
+boolean_t
+zfs_user_in_cred(zfsvfs_t *zfsvfs, uint64_t id, cred_t *cr)
+{
+	ksid_t		*ksid = crgetsid(cr, KSID_USER);
+	ksidlist_t	*ksidlist = crgetsidlist(cr);
+	uid_t		uid;
+
+	/* Check for match with cred->cr_uid */
+	uid = zfs_fuid_map_id(zfsvfs, id, cr, ZFS_ACE_USER);
+	if (uid != IDMAP_WK_CREATOR_OWNER_UID &&
+	    uid == crgetuid(cr))
+		return (B_TRUE);
+
+	/* Check for any match in the ksidlist */
+	if (ksid && ksidlist) {
+		int		i;
+		ksid_t		*ksid_vec;
+		uint32_t	idx = FUID_INDEX(id);
+		uint32_t	rid = FUID_RID(id);
+		const char	*domain;
+
+		if (idx == 0) {
+			/*
+			 * The ID passed in has idx zero, which means
+			 * it's just a Unix UID.  That can never match
+			 * anything in ksid_vec[] because those all
+			 * have ksid->ks_id set to a Group ID.
+			 */
+			return (B_FALSE);
+		}
+
+		domain = zfs_fuid_find_by_idx(zfsvfs, idx);
+		ASSERT(domain != NULL);
+
+		if (strcmp(domain, IDMAP_WK_CREATOR_SID_AUTHORITY) == 0)
+			return (B_FALSE);
+
+		ksid_vec = ksidlist->ksl_sids;
+		for (i = 0; i != ksidlist->ksl_nsid; i++) {
+			if ((strcmp(domain,
+			    ksid_vec[i].ks_domain->kd_name) == 0) &&
+			    rid == ksid_vec[i].ks_rid)
+				return (B_TRUE);
+		}
+	}
+	return (B_FALSE);
+}
+
+/*
  * Check to see if id is a groupmember.  If cred
  * has ksid info then sidlist is checked first
  * and if still not found then POSIX groups are checked
@@ -699,7 +751,7 @@
 	uid_t		gid;
 
 	if (ksid && ksidlist) {
-		int 		i;
+		int		i;
 		ksid_t		*ksid_groups;
 		uint32_t	idx = FUID_INDEX(id);
 		uint32_t	rid = FUID_RID(id);