Skip to content

Commit 235a856

Browse files
pbhensonbehlendorf
authored andcommitted
OpenZFS 6762 - POSIX write should imply DELETE_CHILD on directories
- and some additional considerations Authored by: Kevin Crowe <kevin.crowe@nexenta.com> Reviewed by: Gordon Ross <gwr@nexenta.com> Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com> Reviewed by: Brian Behlendorf <behlendorf1@llnl.gov> Approved by: Richard Lowe <richlowe@richlowe.net> Ported-by: Paul B. Henson <henson@acm.org> OpenZFS-issue: https://www.illumos.org/issues/6762 OpenZFS-commit: openzfs/openzfs@1eb4e906ec Closes #10266
1 parent 99495ba commit 235a856

File tree

1 file changed

+147
-80
lines changed

1 file changed

+147
-80
lines changed

module/os/linux/zfs/zfs_acl.c

+147-80
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@
2020
*/
2121
/*
2222
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
23-
* Copyright 2011 Nexenta Systems, Inc. All rights reserved.
2423
* Copyright (c) 2013 by Delphix. All rights reserved.
24+
* Copyright 2014 Nexenta Systems, Inc. All rights reserved.
2525
*/
2626

2727

@@ -2681,47 +2681,30 @@ zfs_zaccess_unix(znode_t *zp, mode_t mode, cred_t *cr)
26812681
return (zfs_zaccess(zp, v4_mode, 0, B_FALSE, cr));
26822682
}
26832683

2684-
static int
2685-
zfs_delete_final_check(znode_t *zp, znode_t *dzp,
2686-
mode_t available_perms, cred_t *cr)
2687-
{
2688-
int error;
2689-
uid_t downer;
2690-
2691-
downer = zfs_fuid_map_id(ZTOZSB(dzp), KUID_TO_SUID(ZTOI(dzp)->i_uid),
2692-
cr, ZFS_OWNER);
2693-
2694-
error = secpolicy_vnode_access2(cr, ZTOI(dzp),
2695-
downer, available_perms, S_IWUSR|S_IXUSR);
2696-
2697-
if (error == 0)
2698-
error = zfs_sticky_remove_access(dzp, zp, cr);
2699-
2700-
return (error);
2701-
}
2684+
/* See zfs_zaccess_delete() */
2685+
int zfs_write_implies_delete_child = 1;
27022686

27032687
/*
2704-
* Determine whether Access should be granted/deny, without
2705-
* consulting least priv subsystem.
2688+
* Determine whether delete access should be granted.
27062689
*
27072690
* The following chart is the recommended NFSv4 enforcement for
27082691
* ability to delete an object.
27092692
*
27102693
* -------------------------------------------------------
2711-
* | Parent Dir | Target Object Permissions |
2694+
* | Parent Dir | Target Object Permissions |
27122695
* | permissions | |
27132696
* -------------------------------------------------------
27142697
* | | ACL Allows | ACL Denies| Delete |
27152698
* | | Delete | Delete | unspecified|
27162699
* -------------------------------------------------------
2717-
* | ACL Allows | Permit | Permit | Permit |
2718-
* | DELETE_CHILD | |
2700+
* | ACL Allows | Permit | Permit * | Permit |
2701+
* | DELETE_CHILD | | | |
27192702
* -------------------------------------------------------
2720-
* | ACL Denies | Permit | Deny | Deny |
2703+
* | ACL Denies | Permit * | Deny | Deny |
27212704
* | DELETE_CHILD | | | |
27222705
* -------------------------------------------------------
27232706
* | ACL specifies | | | |
2724-
* | only allow | Permit | Permit | Permit |
2707+
* | only allow | Permit | Permit * | Permit |
27252708
* | write and | | | |
27262709
* | execute | | | |
27272710
* -------------------------------------------------------
@@ -2731,91 +2714,175 @@ zfs_delete_final_check(znode_t *zp, znode_t *dzp,
27312714
* -------------------------------------------------------
27322715
* ^
27332716
* |
2734-
* No search privilege, can't even look up file?
2717+
* Re. execute permission on the directory: if that's missing,
2718+
* the vnode lookup of the target will fail before we get here.
2719+
*
2720+
* Re [*] in the table above: We are intentionally disregarding the
2721+
* NFSv4 committee recommendation for these three cells of the matrix
2722+
* because that recommendation conflicts with the behavior expected
2723+
* by Windows clients for ACL evaluation. See acl.h for notes on
2724+
* which ACE_... flags should be checked for which operations.
2725+
* Specifically, the NFSv4 committee recommendation is in conflict
2726+
* with the Windows interpretation of DENY ACEs, where DENY ACEs
2727+
* should take precedence ahead of ALLOW ACEs.
2728+
*
2729+
* This implementation takes a conservative approach by checking for
2730+
* DENY ACEs on both the target object and it's container; checking
2731+
* the ACE_DELETE on the target object, and ACE_DELETE_CHILD on the
2732+
* container. If a DENY ACE is found for either of those, delete
2733+
* access is denied. (Note that DENY ACEs are very rare.)
27352734
*
2735+
* Note that after these changes, entire the second row and the
2736+
* entire middle column of the table above change to Deny.
2737+
* Accordingly, the logic here is somewhat simplified.
2738+
*
2739+
* First check for DENY ACEs that apply.
2740+
* If either target or container has a deny, EACCES.
2741+
*
2742+
* Delete access can then be summarized as follows:
2743+
* 1: The object to be deleted grants ACE_DELETE, or
2744+
* 2: The containing directory grants ACE_DELETE_CHILD.
2745+
* In a Windows system, that would be the end of the story.
2746+
* In this system, (2) has some complications...
2747+
* 2a: "sticky" bit on a directory adds restrictions, and
2748+
* 2b: existing ACEs from previous versions of ZFS may
2749+
* not carry ACE_DELETE_CHILD where they should, so we
2750+
* also allow delete when ACE_WRITE_DATA is granted.
2751+
*
2752+
* Note: 2b is technically a work-around for a prior bug,
2753+
* which hopefully can go away some day. For those who
2754+
* no longer need the work around, and for testing, this
2755+
* work-around is made conditional via the tunable:
2756+
* zfs_write_implies_delete_child
27362757
*/
27372758
int
27382759
zfs_zaccess_delete(znode_t *dzp, znode_t *zp, cred_t *cr)
27392760
{
2761+
uint32_t wanted_dirperms;
27402762
uint32_t dzp_working_mode = 0;
27412763
uint32_t zp_working_mode = 0;
27422764
int dzp_error, zp_error;
2743-
mode_t available_perms;
2744-
boolean_t dzpcheck_privs = B_TRUE;
2745-
boolean_t zpcheck_privs = B_TRUE;
2746-
2747-
/*
2748-
* We want specific DELETE permissions to
2749-
* take precedence over WRITE/EXECUTE. We don't
2750-
* want an ACL such as this to mess us up.
2751-
* user:joe:write_data:deny,user:joe:delete:allow
2752-
*
2753-
* However, deny permissions may ultimately be overridden
2754-
* by secpolicy_vnode_access().
2755-
*
2756-
* We will ask for all of the necessary permissions and then
2757-
* look at the working modes from the directory and target object
2758-
* to determine what was found.
2759-
*/
2765+
boolean_t dzpcheck_privs;
2766+
boolean_t zpcheck_privs;
27602767

27612768
if (zp->z_pflags & (ZFS_IMMUTABLE | ZFS_NOUNLINK))
27622769
return (SET_ERROR(EPERM));
27632770

27642771
/*
2765-
* First row
2766-
* If the directory permissions allow the delete, we are done.
2772+
* Case 1:
2773+
* If target object grants ACE_DELETE then we are done. This is
2774+
* indicated by a return value of 0. For this case we don't worry
2775+
* about the sticky bit because sticky only applies to the parent
2776+
* directory and this is the child access result.
2777+
*
2778+
* If we encounter a DENY ACE here, we're also done (EACCES).
2779+
* Note that if we hit a DENY ACE here (on the target) it should
2780+
* take precedence over a DENY ACE on the container, so that when
2781+
* we have more complete auditing support we will be able to
2782+
* report an access failure against the specific target.
2783+
* (This is part of why we're checking the target first.)
27672784
*/
2768-
if ((dzp_error = zfs_zaccess_common(dzp, ACE_DELETE_CHILD,
2769-
&dzp_working_mode, &dzpcheck_privs, B_FALSE, cr)) == 0)
2785+
zp_error = zfs_zaccess_common(zp, ACE_DELETE, &zp_working_mode,
2786+
&zpcheck_privs, B_FALSE, cr);
2787+
if (zp_error == EACCES) {
2788+
/* We hit a DENY ACE. */
2789+
if (!zpcheck_privs)
2790+
return (SET_ERROR(zp_error));
2791+
return (secpolicy_vnode_remove(cr));
2792+
2793+
}
2794+
if (zp_error == 0)
27702795
return (0);
27712796

27722797
/*
2773-
* If target object has delete permission then we are done
2798+
* Case 2:
2799+
* If the containing directory grants ACE_DELETE_CHILD,
2800+
* or we're in backward compatibility mode and the
2801+
* containing directory has ACE_WRITE_DATA, allow.
2802+
* Case 2b is handled with wanted_dirperms.
27742803
*/
2775-
if ((zp_error = zfs_zaccess_common(zp, ACE_DELETE, &zp_working_mode,
2776-
&zpcheck_privs, B_FALSE, cr)) == 0)
2777-
return (0);
2778-
2779-
ASSERT(dzp_error && zp_error);
2780-
2781-
if (!dzpcheck_privs)
2782-
return (dzp_error);
2783-
if (!zpcheck_privs)
2784-
return (zp_error);
2804+
wanted_dirperms = ACE_DELETE_CHILD;
2805+
if (zfs_write_implies_delete_child)
2806+
wanted_dirperms |= ACE_WRITE_DATA;
2807+
dzp_error = zfs_zaccess_common(dzp, wanted_dirperms,
2808+
&dzp_working_mode, &dzpcheck_privs, B_FALSE, cr);
2809+
if (dzp_error == EACCES) {
2810+
/* We hit a DENY ACE. */
2811+
if (!dzpcheck_privs)
2812+
return (SET_ERROR(dzp_error));
2813+
return (secpolicy_vnode_remove(cr));
2814+
}
27852815

27862816
/*
2787-
* Second row
2817+
* Cases 2a, 2b (continued)
27882818
*
2789-
* If directory returns EACCES then delete_child was denied
2790-
* due to deny delete_child. In this case send the request through
2791-
* secpolicy_vnode_remove(). We don't use zfs_delete_final_check()
2792-
* since that *could* allow the delete based on write/execute permission
2793-
* and we want delete permissions to override write/execute.
2819+
* Note: dzp_working_mode now contains any permissions
2820+
* that were NOT granted. Therefore, if any of the
2821+
* wanted_dirperms WERE granted, we will have:
2822+
* dzp_working_mode != wanted_dirperms
2823+
* We're really asking if ANY of those permissions
2824+
* were granted, and if so, grant delete access.
27942825
*/
2795-
2796-
if (dzp_error == EACCES)
2797-
return (secpolicy_vnode_remove(cr));
2826+
if (dzp_working_mode != wanted_dirperms)
2827+
dzp_error = 0;
27982828

27992829
/*
2800-
* Third Row
2801-
* only need to see if we have write/execute on directory.
2830+
* dzp_error is 0 if the container granted us permissions to "modify".
2831+
* If we do not have permission via one or more ACEs, our current
2832+
* privileges may still permit us to modify the container.
2833+
*
2834+
* dzpcheck_privs is false when i.e. the FS is read-only.
2835+
* Otherwise, do privilege checks for the container.
28022836
*/
2837+
if (dzp_error != 0 && dzpcheck_privs) {
2838+
uid_t owner;
28032839

2804-
dzp_error = zfs_zaccess_common(dzp, ACE_EXECUTE|ACE_WRITE_DATA,
2805-
&dzp_working_mode, &dzpcheck_privs, B_FALSE, cr);
2840+
/*
2841+
* The secpolicy call needs the requested access and
2842+
* the current access mode of the container, but it
2843+
* only knows about Unix-style modes (VEXEC, VWRITE),
2844+
* so this must condense the fine-grained ACE bits into
2845+
* Unix modes.
2846+
*
2847+
* The VEXEC flag is easy, because we know that has
2848+
* always been checked before we get here (during the
2849+
* lookup of the target vnode). The container has not
2850+
* granted us permissions to "modify", so we do not set
2851+
* the VWRITE flag in the current access mode.
2852+
*/
2853+
owner = zfs_fuid_map_id(ZTOZSB(dzp),
2854+
KUID_TO_SUID(ZTOI(dzp)->i_uid), cr, ZFS_OWNER);
2855+
dzp_error = secpolicy_vnode_access2(cr, ZTOI(dzp),
2856+
owner, S_IXUSR, S_IWUSR|S_IXUSR);
2857+
}
2858+
if (dzp_error != 0) {
2859+
/*
2860+
* Note: We may have dzp_error = -1 here (from
2861+
* zfs_zacess_common). Don't return that.
2862+
*/
2863+
return (SET_ERROR(EACCES));
2864+
}
28062865

2807-
if (dzp_error != 0 && !dzpcheck_privs)
2808-
return (dzp_error);
28092866

28102867
/*
2811-
* Fourth row
2868+
* At this point, we know that the directory permissions allow
2869+
* us to modify, but we still need to check for the additional
2870+
* restrictions that apply when the "sticky bit" is set.
2871+
*
2872+
* Yes, zfs_sticky_remove_access() also checks this bit, but
2873+
* checking it here and skipping the call below is nice when
2874+
* you're watching all of this with dtrace.
28122875
*/
2876+
if ((dzp->z_mode & S_ISVTX) == 0)
2877+
return (0);
28132878

2814-
available_perms = (dzp_working_mode & ACE_WRITE_DATA) ? 0 : S_IWUSR;
2815-
available_perms |= (dzp_working_mode & ACE_EXECUTE) ? 0 : S_IXUSR;
2816-
2817-
return (zfs_delete_final_check(zp, dzp, available_perms, cr));
2818-
2879+
/*
2880+
* zfs_sticky_remove_access will succeed if:
2881+
* 1. The sticky bit is absent.
2882+
* 2. We pass the sticky bit restrictions.
2883+
* 3. We have privileges that always allow file removal.
2884+
*/
2885+
return (zfs_sticky_remove_access(dzp, zp, cr));
28192886
}
28202887

28212888
int

0 commit comments

Comments
 (0)