summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/cddl/contrib/opensolaris/common/acl/acl_common.c16
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_acl.c234
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/sys/acl.h67
3 files changed, 111 insertions, 206 deletions
diff --git a/sys/cddl/contrib/opensolaris/common/acl/acl_common.c b/sys/cddl/contrib/opensolaris/common/acl/acl_common.c
index d729f36..a681905 100644
--- a/sys/cddl/contrib/opensolaris/common/acl/acl_common.c
+++ b/sys/cddl/contrib/opensolaris/common/acl/acl_common.c
@@ -20,7 +20,7 @@
*/
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
*/
#include <sys/types.h>
@@ -1580,8 +1580,7 @@ acl_trivial_access_masks(mode_t mode, boolean_t isdir, trivial_acl_t *masks)
uint32_t write_mask = ACE_WRITE_DATA|ACE_APPEND_DATA;
uint32_t execute_mask = ACE_EXECUTE;
- if (isdir)
- write_mask |= ACE_DELETE_CHILD;
+ (void) isdir; /* will need this later */
masks->deny1 = 0;
if (!(mode & S_IRUSR) && (mode & (S_IRGRP|S_IROTH)))
@@ -1725,17 +1724,10 @@ ace_trivial_common(void *acep, int aclcnt,
return (1);
/*
- * Delete permission is never set by default
- */
- if (mask & ACE_DELETE)
- return (1);
-
- /*
- * Child delete permission should be accompanied by write
+ * Delete permissions are never set by default
*/
- if ((mask & ACE_DELETE_CHILD) && !(mask & ACE_WRITE_DATA))
+ if (mask & (ACE_DELETE|ACE_DELETE_CHILD))
return (1);
-
/*
* only allow owner@ to have
* write_acl/write_owner/write_attributes/write_xattr/
diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_acl.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_acl.c
index 9fc8d73..3e4c70d 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_acl.c
+++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_acl.c
@@ -20,8 +20,8 @@
*/
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2013 by Delphix. All rights reserved.
- * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
*/
#include <sys/types.h>
@@ -2085,7 +2085,7 @@ zfs_zaccess_dataset_check(znode_t *zp, uint32_t v4_mode)
* placed into the working_mode, giving the caller a mask of denied
* accesses. Returns:
* 0 if all AoI granted
- * EACCES if the denied mask is non-zero
+ * EACCESS if the denied mask is non-zero
* other error if abnormal failure (e.g., IO error)
*
* A secondary usage of the function is to determine if any of the
@@ -2532,32 +2532,46 @@ zfs_zaccess_unix(znode_t *zp, mode_t mode, cred_t *cr)
return (zfs_zaccess(zp, v4_mode, 0, B_FALSE, cr));
}
-/* See zfs_zaccess_delete() */
-int zfs_write_implies_delete_child = 1;
+static int
+zfs_delete_final_check(znode_t *zp, znode_t *dzp,
+ mode_t available_perms, cred_t *cr)
+{
+ int error;
+ uid_t downer;
+
+ downer = zfs_fuid_map_id(dzp->z_zfsvfs, dzp->z_uid, cr, ZFS_OWNER);
+
+ error = secpolicy_vnode_access2(cr, ZTOV(dzp),
+ downer, available_perms, VWRITE|VEXEC);
+
+ if (error == 0)
+ error = zfs_sticky_remove_access(dzp, zp, cr);
+
+ return (error);
+}
/*
- * Determine whether delete access should be granted.
+ * Determine whether Access should be granted/deny, without
+ * consulting least priv subsystem.
*
- * The following chart outlines how we handle delete permissions which is
- * how recent versions of windows (Windows 2008) handles it. The efficiency
- * comes from not having to check the parent ACL where the object itself grants
- * delete:
+ * The following chart is the recommended NFSv4 enforcement for
+ * ability to delete an object.
*
* -------------------------------------------------------
- * | Parent Dir | Target Object Permissions |
+ * | Parent Dir | Target Object Permissions |
* | permissions | |
* -------------------------------------------------------
* | | ACL Allows | ACL Denies| Delete |
* | | Delete | Delete | unspecified|
* -------------------------------------------------------
- * | ACL Allows | Permit | Deny * | Permit |
- * | DELETE_CHILD | | | |
+ * | ACL Allows | Permit | Permit | Permit |
+ * | DELETE_CHILD | |
* -------------------------------------------------------
- * | ACL Denies | Permit | Deny | Deny |
- * | DELETE_CHILD | | | |
+ * | ACL Denies | Permit | Deny | Deny |
+ * | DELETE_CHILD | | | |
* -------------------------------------------------------
* | ACL specifies | | | |
- * | only allow | Permit | Deny * | Permit |
+ * | only allow | Permit | Permit | Permit |
* | write and | | | |
* | execute | | | |
* -------------------------------------------------------
@@ -2567,171 +2581,91 @@ int zfs_write_implies_delete_child = 1;
* -------------------------------------------------------
* ^
* |
- * Re. execute permission on the directory: if that's missing,
- * the vnode lookup of the target will fail before we get here.
- *
- * Re [*] in the table above: NFSv4 would normally Permit delete for
- * these two cells of the matrix.
- * See acl.h for notes on which ACE_... flags should be checked for which
- * operations. Specifically, the NFSv4 committee recommendation is in
- * conflict with the Windows interpretation of DENY ACEs, where DENY ACEs
- * should take precedence ahead of ALLOW ACEs.
- *
- * This implementation always consults the target object's ACL first.
- * If a DENY ACE is present on the target object that specifies ACE_DELETE,
- * delete access is denied. If an ALLOW ACE with ACE_DELETE is present on
- * the target object, access is allowed. If and only if no entries with
- * ACE_DELETE are present in the object's ACL, check the container's ACL
- * for entries with ACE_DELETE_CHILD.
- *
- * A summary of the logic implemented from the table above is as follows:
+ * No search privilege, can't even look up file?
*
- * First check for DENY ACEs that apply.
- * If either target or container has a deny, EACCES.
- *
- * Delete access can then be summarized as follows:
- * 1: The object to be deleted grants ACE_DELETE, or
- * 2: The containing directory grants ACE_DELETE_CHILD.
- * In a Windows system, that would be the end of the story.
- * In this system, (2) has some complications...
- * 2a: "sticky" bit on a directory adds restrictions, and
- * 2b: existing ACEs from previous versions of ZFS may
- * not carry ACE_DELETE_CHILD where they should, so we
- * also allow delete when ACE_WRITE_DATA is granted.
- *
- * Note: 2b is technically a work-around for a prior bug,
- * which hopefully can go away some day. For those who
- * no longer need the work around, and for testing, this
- * work-around is made conditional via the tunable:
- * zfs_write_implies_delete_child
*/
int
zfs_zaccess_delete(znode_t *dzp, znode_t *zp, cred_t *cr)
{
- uint32_t wanted_dirperms;
uint32_t dzp_working_mode = 0;
uint32_t zp_working_mode = 0;
int dzp_error, zp_error;
- boolean_t dzpcheck_privs;
- boolean_t zpcheck_privs;
-
- if (zp->z_pflags & (ZFS_IMMUTABLE | ZFS_NOUNLINK))
- return (SET_ERROR(EPERM));
+ mode_t available_perms;
+ boolean_t dzpcheck_privs = B_TRUE;
+ boolean_t zpcheck_privs = B_TRUE;
/*
- * Case 1:
- * If target object grants ACE_DELETE then we are done. This is
- * indicated by a return value of 0. For this case we don't worry
- * about the sticky bit because sticky only applies to the parent
- * directory and this is the child access result.
+ * We want specific DELETE permissions to
+ * take precedence over WRITE/EXECUTE. We don't
+ * want an ACL such as this to mess us up.
+ * user:joe:write_data:deny,user:joe:delete:allow
+ *
+ * However, deny permissions may ultimately be overridden
+ * by secpolicy_vnode_access().
*
- * If we encounter a DENY ACE here, we're also done (EACCES).
- * Note that if we hit a DENY ACE here (on the target) it should
- * take precedence over a DENY ACE on the container, so that when
- * we have more complete auditing support we will be able to
- * report an access failure against the specific target.
- * (This is part of why we're checking the target first.)
+ * We will ask for all of the necessary permissions and then
+ * look at the working modes from the directory and target object
+ * to determine what was found.
*/
- zp_error = zfs_zaccess_common(zp, ACE_DELETE, &zp_working_mode,
- &zpcheck_privs, B_FALSE, cr);
- if (zp_error == EACCES) {
- /* We hit a DENY ACE. */
- if (!zpcheck_privs)
- return (SET_ERROR(zp_error));
- return (secpolicy_vnode_remove(ZTOV(dzp), cr)); /* XXXPJD: s/dzp/zp/ ? */
- }
- if (zp_error == 0)
- return (0);
+ if (zp->z_pflags & (ZFS_IMMUTABLE | ZFS_NOUNLINK))
+ return (SET_ERROR(EPERM));
/*
- * Case 2:
- * If the containing directory grants ACE_DELETE_CHILD,
- * or we're in backward compatibility mode and the
- * containing directory has ACE_WRITE_DATA, allow.
- * Case 2b is handled with wanted_dirperms.
+ * First row
+ * If the directory permissions allow the delete, we are done.
*/
- wanted_dirperms = ACE_DELETE_CHILD;
- if (zfs_write_implies_delete_child)
- wanted_dirperms |= ACE_WRITE_DATA;
- dzp_error = zfs_zaccess_common(dzp, wanted_dirperms,
- &dzp_working_mode, &dzpcheck_privs, B_FALSE, cr);
- if (dzp_error == EACCES) {
- /* We hit a DENY ACE. */
- if (!dzpcheck_privs)
- return (SET_ERROR(dzp_error));
- return (secpolicy_vnode_remove(ZTOV(dzp), cr)); /* XXXPJD: s/dzp/zp/ ? */
- }
+ if ((dzp_error = zfs_zaccess_common(dzp, ACE_DELETE_CHILD,
+ &dzp_working_mode, &dzpcheck_privs, B_FALSE, cr)) == 0)
+ return (0);
/*
- * Cases 2a, 2b (continued)
- *
- * Note: dzp_working_mode now contains any permissions
- * that were NOT granted. Therefore, if any of the
- * wanted_dirperms WERE granted, we will have:
- * dzp_working_mode != wanted_dirperms
- * We're really asking if ANY of those permissions
- * were granted, and if so, grant delete access.
+ * If target object has delete permission then we are done
*/
- if (dzp_working_mode != wanted_dirperms)
- dzp_error = 0;
+ if ((zp_error = zfs_zaccess_common(zp, ACE_DELETE, &zp_working_mode,
+ &zpcheck_privs, B_FALSE, cr)) == 0)
+ return (0);
+
+ ASSERT(dzp_error && zp_error);
+
+ if (!dzpcheck_privs)
+ return (dzp_error);
+ if (!zpcheck_privs)
+ return (zp_error);
/*
- * dzp_error is 0 if the container granted us permissions to "modify".
- * If we do not have permission via one or more ACEs, our current
- * privileges may still permit us to modify the container.
+ * Second row
*
- * dzpcheck_privs is false when i.e. the FS is read-only.
- * Otherwise, do privilege checks for the container.
+ * If directory returns EACCES then delete_child was denied
+ * due to deny delete_child. In this case send the request through
+ * secpolicy_vnode_remove(). We don't use zfs_delete_final_check()
+ * since that *could* allow the delete based on write/execute permission
+ * and we want delete permissions to override write/execute.
*/
- if (dzp_error != 0 && dzpcheck_privs) {
- uid_t owner;
- /*
- * The secpolicy call needs the requested access and
- * the current access mode of the container, but it
- * only knows about Unix-style modes (VEXEC, VWRITE),
- * so this must condense the fine-grained ACE bits into
- * Unix modes.
- *
- * The VEXEC flag is easy, because we know that has
- * always been checked before we get here (during the
- * lookup of the target vnode). The container has not
- * granted us permissions to "modify", so we do not set
- * the VWRITE flag in the current access mode.
- */
- owner = zfs_fuid_map_id(dzp->z_zfsvfs, dzp->z_uid, cr,
- ZFS_OWNER);
- dzp_error = secpolicy_vnode_access2(cr, ZTOV(dzp),
- owner, VEXEC, VWRITE|VEXEC);
- }
- if (dzp_error != 0) {
- /*
- * Note: We may have dzp_error = -1 here (from
- * zfs_zacess_common). Don't return that.
- */
- return (SET_ERROR(EACCES));
- }
+ if (dzp_error == EACCES)
+ return (secpolicy_vnode_remove(ZTOV(dzp), cr)); /* XXXPJD: s/dzp/zp/ ? */
/*
- * At this point, we know that the directory permissions allow
- * us to modify, but we still need to check for the additional
- * restrictions that apply when the "sticky bit" is set.
- *
- * Yes, zfs_sticky_remove_access() also checks this bit, but
- * checking it here and skipping the call below is nice when
- * you're watching all of this with dtrace.
+ * Third Row
+ * only need to see if we have write/execute on directory.
*/
- if ((dzp->z_mode & S_ISVTX) == 0)
- return (0);
+
+ dzp_error = zfs_zaccess_common(dzp, ACE_EXECUTE|ACE_WRITE_DATA,
+ &dzp_working_mode, &dzpcheck_privs, B_FALSE, cr);
+
+ if (dzp_error != 0 && !dzpcheck_privs)
+ return (dzp_error);
/*
- * zfs_sticky_remove_access will succeed if:
- * 1. The sticky bit is absent.
- * 2. We pass the sticky bit restrictions.
- * 3. We have privileges that always allow file removal.
+ * Fourth row
*/
- return (zfs_sticky_remove_access(dzp, zp, cr));
+
+ available_perms = (dzp_working_mode & ACE_WRITE_DATA) ? 0 : VWRITE;
+ available_perms |= (dzp_working_mode & ACE_EXECUTE) ? 0 : VEXEC;
+
+ return (zfs_delete_final_check(zp, dzp, available_perms, cr));
+
}
int
diff --git a/sys/cddl/contrib/opensolaris/uts/common/sys/acl.h b/sys/cddl/contrib/opensolaris/uts/common/sys/acl.h
index 83c85ba..58ef69e 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/sys/acl.h
+++ b/sys/cddl/contrib/opensolaris/uts/common/sys/acl.h
@@ -23,8 +23,6 @@
*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
- *
- * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _SYS_ACL_H
@@ -90,55 +88,37 @@ typedef struct acl_info acl_t;
/*
* The following are defined for ace_t.
- *
- * Note, these are intentionally the same as the Windows
- * "File Access Rights Constants" you can find on MSDN.
- * (See also: "Standard Access Rights" on MSDN).
- *
- * The equivalent Windows names for these are just like
- * those show below, with FILE_ in place of ACE_, except
- * as noted below. Also note that Windows uses a special
- * privilege: BYPASS_TRAVERSE_CHECKING, normally granted
- * to everyone, that causes the absence of ACE_TRAVERSE
- * to be ignored.
- */
-#define ACE_READ_DATA 0x00000001 /* file: read data */
-#define ACE_LIST_DIRECTORY 0x00000001 /* dir: list files */
-#define ACE_WRITE_DATA 0x00000002 /* file: write data */
-#define ACE_ADD_FILE 0x00000002 /* dir: create file */
-#define ACE_APPEND_DATA 0x00000004 /* file: append data */
-#define ACE_ADD_SUBDIRECTORY 0x00000004 /* dir: create subdir */
-#define ACE_READ_NAMED_ATTRS 0x00000008 /* FILE_READ_EA */
-#define ACE_WRITE_NAMED_ATTRS 0x00000010 /* FILE_WRITE_EA */
-#define ACE_EXECUTE 0x00000020 /* file: execute */
-#define ACE_TRAVERSE 0x00000020 /* dir: lookup name */
-#define ACE_DELETE_CHILD 0x00000040 /* dir: unlink child */
-#define ACE_READ_ATTRIBUTES 0x00000080 /* (all) stat, etc. */
-#define ACE_WRITE_ATTRIBUTES 0x00000100 /* (all) utimes, etc. */
-#define ACE_DELETE 0x00010000 /* (all) unlink self */
-#define ACE_READ_ACL 0x00020000 /* (all) getsecattr */
-#define ACE_WRITE_ACL 0x00040000 /* (all) setsecattr */
-#define ACE_WRITE_OWNER 0x00080000 /* (all) chown */
-#define ACE_SYNCHRONIZE 0x00100000 /* (all) see MSDN */
-
-/*
- * Some of the following are the same as Windows uses. (but NOT ALL!)
- * See the "ACE_HEADER" structure description on MSDN for details.
- * Comments show relations to the MSDN names.
*/
-#define ACE_FILE_INHERIT_ACE 0x0001 /* = OBJECT_INHERIT_ACE */
-#define ACE_DIRECTORY_INHERIT_ACE 0x0002 /* = CONTAINER_INHERIT_ACE */
-#define ACE_NO_PROPAGATE_INHERIT_ACE 0x0004 /* = NO_PROPAGATE_INHERIT_ACE */
-#define ACE_INHERIT_ONLY_ACE 0x0008 /* = INHERIT_ONLY_ACE */
+#define ACE_READ_DATA 0x00000001
+#define ACE_LIST_DIRECTORY 0x00000001
+#define ACE_WRITE_DATA 0x00000002
+#define ACE_ADD_FILE 0x00000002
+#define ACE_APPEND_DATA 0x00000004
+#define ACE_ADD_SUBDIRECTORY 0x00000004
+#define ACE_READ_NAMED_ATTRS 0x00000008
+#define ACE_WRITE_NAMED_ATTRS 0x00000010
+#define ACE_EXECUTE 0x00000020
+#define ACE_DELETE_CHILD 0x00000040
+#define ACE_READ_ATTRIBUTES 0x00000080
+#define ACE_WRITE_ATTRIBUTES 0x00000100
+#define ACE_DELETE 0x00010000
+#define ACE_READ_ACL 0x00020000
+#define ACE_WRITE_ACL 0x00040000
+#define ACE_WRITE_OWNER 0x00080000
+#define ACE_SYNCHRONIZE 0x00100000
+
+#define ACE_FILE_INHERIT_ACE 0x0001
+#define ACE_DIRECTORY_INHERIT_ACE 0x0002
+#define ACE_NO_PROPAGATE_INHERIT_ACE 0x0004
+#define ACE_INHERIT_ONLY_ACE 0x0008
#define ACE_SUCCESSFUL_ACCESS_ACE_FLAG 0x0010
#define ACE_FAILED_ACCESS_ACE_FLAG 0x0020
#define ACE_IDENTIFIER_GROUP 0x0040
-#define ACE_INHERITED_ACE 0x0080 /* INHERITED_ACE, 0x10 on NT */
+#define ACE_INHERITED_ACE 0x0080
#define ACE_OWNER 0x1000
#define ACE_GROUP 0x2000
#define ACE_EVERYONE 0x4000
-/* These four are the same as Windows, but with an ACE_ prefix added. */
#define ACE_ACCESS_ALLOWED_ACE_TYPE 0x0000
#define ACE_ACCESS_DENIED_ACE_TYPE 0x0001
#define ACE_SYSTEM_AUDIT_ACE_TYPE 0x0002
@@ -154,7 +134,6 @@ typedef struct acl_info acl_t;
/*
* These are only applicable in a CIFS context.
- * Here again, same as Windows, but with an ACE_ prefix added.
*/
#define ACE_ACCESS_ALLOWED_COMPOUND_ACE_TYPE 0x04
#define ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE 0x05
OpenPOWER on IntegriCloud