--- old/usr/src/uts/common/fs/zfs/zfs_acl.c	Mon Aug  5 17:27:09 2019
+++ new/usr/src/uts/common/fs/zfs/zfs_acl.c	Mon Aug  5 17:27:09 2019
@@ -21,7 +21,7 @@
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
  * Copyright (c) 2013 by Delphix. All rights reserved.
- * Copyright 2017 Nexenta Systems, Inc.  All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
  */
 
 #include <sys/types.h>
@@ -54,6 +54,8 @@
 #include <sys/sa.h>
 #include "fs/fs_subr.h"
 #include <acl/acl_common.h>
+#include <c2/audit.h>
+#include <c2/audit_kernel.h>
 
 #define	ALLOW	ACE_ACCESS_ALLOWED_ACE_TYPE
 #define	DENY	ACE_ACCESS_DENIED_ACE_TYPE
@@ -1188,7 +1190,6 @@
 	sa_bulk_attr_t		bulk[5];
 	uint64_t		ctime[2];
 	int			count = 0;
-	zfs_acl_phys_t		acl_phys;
 
 	mode = zp->z_mode;
 
@@ -1235,6 +1236,7 @@
 	} else { /* Painful legacy way */
 		zfs_acl_node_t *aclnode;
 		uint64_t off = 0;
+		zfs_acl_phys_t acl_phys;
 		uint64_t aoid;
 
 		if ((error = sa_lookup(zp->z_sa_hdl, SA_ZPL_ZNODE_ACL(zfsvfs),
@@ -1337,12 +1339,12 @@
 	uint64_t	who;
 	int		new_count, new_bytes;
 	int		ace_size;
-	int 		entry_type;
+	int		entry_type;
 	uint16_t	iflags, type;
 	uint32_t	access_mask;
 	zfs_acl_node_t	*newnode;
-	size_t 		abstract_size = aclp->z_ops.ace_abstract_size();
-	void 		*zacep;
+	size_t		abstract_size = aclp->z_ops.ace_abstract_size();
+	void		*zacep;
 	boolean_t	isdir;
 	trivial_acl_t	masks;
 
@@ -2083,24 +2085,22 @@
  */
 static int
 zfs_zaccess_aces_check(znode_t *zp, uint32_t *working_mode,
-    boolean_t anyaccess, cred_t *cr)
+    boolean_t anyaccess, cred_t *cr, boolean_t audit)
 {
 	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;
+	uint32_t	sys_smask = 0;
+	uint32_t	sys_fmask = 0;
 	zfs_ace_hdr_t	*acep = NULL;
-	boolean_t	checkit;
-	uid_t		gowner;
-	uid_t		fowner;
+	boolean_t	checkit;	/* ACE ID matches */
+	t_audit_data_t *tad;
 
-	zfs_fuid_map_ids(zp, cr, &fowner, &gowner);
-
 	mutex_enter(&zp->z_acl_lock);
 
 	error = zfs_acl_node_read(zp, B_FALSE, &aclp, B_FALSE);
@@ -2123,8 +2123,10 @@
 
 		/* Skip ACE if it does not affect any AoI */
 		mask_matched = (access_mask & *working_mode);
-		if (!mask_matched)
+		if ((type == DENY || type == ALLOW) && !mask_matched)
 			continue;
+		if (!audit && type != DENY && type != ALLOW)
+			continue;
 
 		entry_type = (iflags & ACE_TYPE_FLAGS);
 
@@ -2132,11 +2134,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);
@@ -2145,31 +2149,39 @@
 			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) {
-			if (type == DENY) {
+			switch (type) {
+			case DENY:
 				DTRACE_PROBE3(zfs__ace__denies,
 				    znode_t *, zp,
 				    zfs_ace_hdr_t *, acep,
 				    uint32_t, mask_matched);
 				deny_mask |= mask_matched;
-			} else {
+				*working_mode &= ~mask_matched;
+				break;
+			case ACE_SYSTEM_AUDIT_ACE_TYPE:
+			case ACE_SYSTEM_ALARM_ACE_TYPE:
+				DTRACE_PROBE3(zfs__ace__audit,
+				    znode_t *, zp,
+				    zfs_ace_hdr_t *, acep,
+				    uint32_t, access_mask);
+				if ((iflags &
+				    ACE_SUCCESSFUL_ACCESS_ACE_FLAG) != 0)
+					sys_smask |= access_mask;
+				if ((iflags & ACE_FAILED_ACCESS_ACE_FLAG) != 0)
+					sys_fmask |= access_mask;
+				break;
+			case ALLOW:
+			default:
 				DTRACE_PROBE3(zfs__ace__allows,
 				    znode_t *, zp,
 				    zfs_ace_hdr_t *, acep,
@@ -2178,17 +2190,27 @@
 					mutex_exit(&zp->z_acl_lock);
 					return (0);
 				}
+				*working_mode &= ~mask_matched;
+				break;
 			}
-			*working_mode &= ~mask_matched;
 		}
 
-		/* Are we done? */
-		if (*working_mode == 0)
+		/*
+		 * Are we done? If auditing, process the entire list
+		 * to gather all audit ACEs
+		 */
+		if (!audit && *working_mode == 0)
 			break;
 	}
 
 	mutex_exit(&zp->z_acl_lock);
 
+	if (audit) {
+		tad = T2A(curthread);
+		tad->tad_sacl_mask.tas_smask = sys_smask;
+		tad->tad_sacl_mask.tas_fmask = sys_fmask;
+	}
+
 	/* Put the found 'denies' back on the working mode */
 	if (deny_mask) {
 		*working_mode |= deny_mask;
@@ -2209,7 +2231,7 @@
 {
 	uint32_t have = ACE_ALL_PERMS;
 
-	if (zfs_zaccess_aces_check(zp, &have, B_TRUE, cr) != 0) {
+	if (zfs_zaccess_aces_check(zp, &have, B_TRUE, cr, B_FALSE) != 0) {
 		uid_t owner;
 
 		owner = zfs_fuid_map_id(zp->z_zfsvfs, zp->z_uid, cr, ZFS_OWNER);
@@ -2224,6 +2246,7 @@
 {
 	zfsvfs_t *zfsvfs = zp->z_zfsvfs;
 	int err;
+	boolean_t audit = B_FALSE;
 
 	*working_mode = v4_mode;
 	*check_privs = B_TRUE;
@@ -2269,7 +2292,16 @@
 		return (SET_ERROR(EPERM));
 	}
 
-	return (zfs_zaccess_aces_check(zp, working_mode, B_FALSE, cr));
+	if (cr != zone_kcred() && AU_ZONE_AUDITING(NULL)) {
+		t_audit_data_t *tad = T2A(curthread);
+		if (tad->tad_sacl_ctrl != SACL_AUDIT_NONE &&
+		    auditev(AUE_SACL, cr) != 0) {
+			audit = B_TRUE;
+			tad->tad_sacl_ctrl = SACL_AUDIT_NONE;
+		}
+	}
+
+	return (zfs_zaccess_aces_check(zp, working_mode, B_FALSE, cr, audit));
 }
 
 static int
@@ -2442,6 +2474,10 @@
 	}
 
 	if (error && (flags & V_APPEND)) {
+		/*
+		 * If zfs_zaccess_common checked aces, then we won't audit here.
+		 * Otherwise, we'll try and get audit masks here.
+		 */
 		error = zfs_zaccess_append(zp, &working_mode, &check_privs, cr);
 	}
 
@@ -2608,6 +2644,7 @@
 	int dzp_error, zp_error;
 	boolean_t dzpcheck_privs;
 	boolean_t zpcheck_privs;
+	t_audit_data_t *tad;
 
 	if (zp->z_pflags & (ZFS_IMMUTABLE | ZFS_NOUNLINK))
 		return (SET_ERROR(EPERM));
@@ -2648,6 +2685,11 @@
 	wanted_dirperms = ACE_DELETE_CHILD;
 	if (zfs_write_implies_delete_child)
 		wanted_dirperms |= ACE_WRITE_DATA;
+	/* never audit the parent directory access check */
+	if (AU_ZONE_AUDITING(NULL)) {
+		tad = T2A(curthread);
+		tad->tad_sacl_ctrl = SACL_AUDIT_NONE;
+	}
 	dzp_error = zfs_zaccess_common(dzp, wanted_dirperms,
 	    &dzp_working_mode, &dzpcheck_privs, B_FALSE, cr);
 	if (dzp_error == EACCES) {
@@ -2734,6 +2776,8 @@
 {
 	int add_perm;
 	int error;
+	t_audit_data_t *tad;
+	sacl_audit_ctrl_t do_audit;
 
 	if (szp->z_pflags & ZFS_AV_QUARANTINED)
 		return (SET_ERROR(EACCES));
@@ -2741,6 +2785,14 @@
 	add_perm = (ZTOV(szp)->v_type == VDIR) ?
 	    ACE_ADD_SUBDIRECTORY : ACE_ADD_FILE;
 
+	if (AU_ZONE_AUDITING(NULL)) {
+		tad = T2A(curthread);
+		do_audit = tad->tad_sacl_ctrl;
+	} else {
+		tad = NULL;
+		do_audit = SACL_AUDIT_NONE;
+	}
+
 	/*
 	 * Rename permissions are combination of delete permission +
 	 * add file/subdir permission.
@@ -2752,15 +2804,35 @@
 	 * If that succeeds then check for add_file/add_subdir permissions
 	 */
 
-	if (error = zfs_zaccess_delete(sdzp, szp, cr))
+	if (do_audit == SACL_AUDIT_NO_SRC)
+		tad->tad_sacl_ctrl = SACL_AUDIT_NONE;
+	error = zfs_zaccess_delete(sdzp, szp, cr);
+
+	if (do_audit == SACL_AUDIT_ALL) {
+		tad->tad_sacl_mask_src = tad->tad_sacl_mask;
+		tad->tad_sacl_mask.tas_smask = 0;
+		tad->tad_sacl_mask.tas_fmask = 0;
+	}
+	if (error != 0)
 		return (error);
 
+	if (do_audit != SACL_AUDIT_NONE)
+		tad->tad_sacl_ctrl = do_audit;
+
 	/*
 	 * If we have a tzp, see if we can delete it?
 	 */
 	if (tzp) {
-		if (error = zfs_zaccess_delete(tdzp, tzp, cr))
+		error = zfs_zaccess_delete(tdzp, tzp, cr);
+		if (do_audit != SACL_AUDIT_NONE) {
+			tad->tad_sacl_mask_dest = tad->tad_sacl_mask;
+			tad->tad_sacl_mask.tas_smask = 0;
+			tad->tad_sacl_mask.tas_fmask = 0;
+		}
+		if (error != 0)
 			return (error);
+		if (do_audit != SACL_AUDIT_NONE)
+			tad->tad_sacl_ctrl = do_audit;
 	}
 
 	/*
@@ -2768,5 +2840,7 @@
 	 */
 	error = zfs_zaccess(tdzp, add_perm, 0, B_FALSE, cr);
 
+	/* do_audit: leave directory audit info in sacl_mask. */
+
 	return (error);
 }
