Date: Wed, 28 Oct 2009 18:34:09 GMT From: Edward Tomasz Napierala <trasz@FreeBSD.org> To: Perforce Change Reviews <perforce@freebsd.org> Subject: PERFORCE change 169898 for review Message-ID: <200910281834.n9SIY9Wl029702@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://p4web.freebsd.org/chv.cgi?CH=169898 Change 169898 by trasz@trasz_victim on 2009/10/28 18:33:48 Move code specific to UFS from the syscall layer (sys/kern/vfs_acl.c) to UFS itself. Not very pretty, as it makes it neccessary for the code in ufs_vnops.c to use private UFS functions instead of calling VOP_SETACL() and VOP_GETACL(), but correct. XXX: Note that there is still one bug here - if we deny ACL_READ_ACL, retrieving the ACL is denied as it should be, but stat(2) is not. Affected files ... .. //depot/projects/soc2008/trasz_nfs4acl/sys/kern/vfs_acl.c#22 edit .. //depot/projects/soc2008/trasz_nfs4acl/sys/ufs/ufs/acl.h#4 edit .. //depot/projects/soc2008/trasz_nfs4acl/sys/ufs/ufs/ufs_acl.c#22 edit Differences ... ==== //depot/projects/soc2008/trasz_nfs4acl/sys/kern/vfs_acl.c#22 (text+ko) ==== @@ -215,18 +215,6 @@ error = acl_copyin(aclp, inkernelacl, type); if (error != 0) goto out; - - /* - * With NFSv4 ACLs, chmod(2) may need to add additional entries. - * Make sure it has enough room for that - splitting every entry - * into two and appending "canonical six" entries at the end. - */ - if (type == ACL_TYPE_NFS4 && - inkernelacl->acl_cnt > (ACL_MAX_ENTRIES - 6) / 2) { - error = ENOSPC; - goto out; - } - error = vn_start_write(vp, &mp, V_WAIT | PCATCH); if (error != 0) goto out; @@ -265,14 +253,12 @@ if (error != 0) goto out; #endif - error = VOP_ACCESSX(vp, VREAD_ACL, td->td_ucred, td); - if (error != 0) - goto out; - error = VOP_GETACL(vp, acl_type_unold(type), inkernelacl, td->td_ucred, td); +#ifdef MAC out: +#endif VOP_UNLOCK(vp, 0); if (error == 0) error = acl_copyout(inkernelacl, aclp, type); @@ -321,18 +307,6 @@ error = acl_copyin(aclp, inkernelacl, type); if (error != 0) goto out; - - /* - * With NFSv4 ACLs, chmod(2) may need to add additional entries. - * Make sure it has enough room for that - splitting every entry - * into two and appending "canonical six" entries at the end. - */ - if (type == ACL_TYPE_NFS4 && - inkernelacl->acl_cnt > (ACL_MAX_ENTRIES - 6) / 2) { - error = ENOSPC; - goto out; - } - error = VOP_ACLCHECK(vp, acl_type_unold(type), inkernelacl, td->td_ucred, td); out: ==== //depot/projects/soc2008/trasz_nfs4acl/sys/ufs/ufs/acl.h#4 (text+ko) ==== @@ -37,6 +37,8 @@ #ifdef _KERNEL +int ufs_getacl_nfs4_internal(struct vnode *vp, struct acl *aclp, struct thread *td); +int ufs_setacl_nfs4_internal(struct vnode *vp, struct acl *aclp, struct thread *td); void ufs_sync_acl_from_inode(struct inode *ip, struct acl *acl); void ufs_sync_inode_from_acl(struct acl *acl, struct inode *ip); ==== //depot/projects/soc2008/trasz_nfs4acl/sys/ufs/ufs/ufs_acl.c#22 (text+ko) ==== @@ -140,29 +140,31 @@ DIP_SET(ip, i_mode, ip->i_mode); } -static int -ufs_getacl_nfs4(struct vop_getacl_args *ap) +/* + * Retrieve NFSv4 ACL, skipping access checks. Must be used in UFS code + * instead of VOP_GETACL() when we don't want to be restricted by the user + * not having ACL_READ_ACL permission, e.g. when calculating inherited ACL + * or in ufs_vnops.c:ufs_accessx(). + */ +int +ufs_getacl_nfs4_internal(struct vnode *vp, struct acl *aclp, struct thread *td) { int error, len; - struct inode *ip = VTOI(ap->a_vp); + struct inode *ip = VTOI(vp); - if ((ap->a_vp->v_mount->mnt_flag & MNT_NFS4ACLS) == 0) - return (EINVAL); + len = sizeof(*aclp); + bzero(aclp, len); - len = sizeof(*ap->a_aclp); - bzero(ap->a_aclp, len); - - error = vn_extattr_get(ap->a_vp, IO_NODELOCKED, - NFS4_ACL_EXTATTR_NAMESPACE, - NFS4_ACL_EXTATTR_NAME, &len, (char *) ap->a_aclp, - ap->a_td); - ap->a_aclp->acl_maxcnt = ACL_MAX_ENTRIES; + error = vn_extattr_get(vp, IO_NODELOCKED, + NFS4_ACL_EXTATTR_NAMESPACE, NFS4_ACL_EXTATTR_NAME, + &len, (char *) aclp, td); + aclp->acl_maxcnt = ACL_MAX_ENTRIES; if (error == ENOATTR) { /* * Legitimately no ACL set on object, purely * emulate it through the inode. */ - acl_nfs4_sync_acl_from_mode(ap->a_aclp, ip->i_mode, ip->i_uid); + acl_nfs4_sync_acl_from_mode(aclp, ip->i_mode, ip->i_uid); return (0); } @@ -170,7 +172,7 @@ if (error) return (error); - if (len != sizeof(*ap->a_aclp)) { + if (len != sizeof(*aclp)) { /* * A short (or long) read, meaning that for * some reason the ACL is corrupted. Return @@ -184,7 +186,7 @@ return (EPERM); } - error = acl_nfs4_check(ap->a_aclp, ap->a_vp->v_type == VDIR); + error = acl_nfs4_check(aclp, vp->v_type == VDIR); if (error) { printf("ufs_getacl_nfs4(): Loaded invalid ACL " "(failed acl_nfs4_check), inumber %d on %s\n", @@ -196,6 +198,23 @@ return (0); } +static int +ufs_getacl_nfs4(struct vop_getacl_args *ap) +{ + int error; + + if ((ap->a_vp->v_mount->mnt_flag & MNT_NFS4ACLS) == 0) + return (EINVAL); + + error = VOP_ACCESSX(ap->a_vp, VREAD_ACL, ap->a_td->td_ucred, ap->a_td); + if (error) + return (error); + + error = ufs_getacl_nfs4_internal(ap->a_vp, ap->a_aclp, ap->a_td); + + return (error); +} + /* * Read POSIX.1e ACL from an EA. Return error if its not found * or if any other error has occured. @@ -347,11 +366,67 @@ return (ufs_getacl_posix1e(ap)); } +/* + * Set NFSv4 ACL without doing any access checking. This is required + * e.g. by the UFS code that implements ACL inheritance, or from + * ufs_vnops.c:ufs_chmod(), as some of the checks have to be skipped + * in that case, and others are redundant. + */ +int +ufs_setacl_nfs4_internal(struct vnode *vp, struct acl *aclp, struct thread *td) +{ + int error; + mode_t mode; + struct inode *ip = VTOI(vp); + + KASSERT(acl_nfs4_check(aclp, vp->v_type == VDIR) == 0, + ("invalid ACL passed to ufs_setacl_nfs4_internal")); + + if (acl_nfs4_is_trivial(aclp, ip->i_uid)) { + error = vn_extattr_rm(vp, IO_NODELOCKED, + NFS4_ACL_EXTATTR_NAMESPACE, NFS4_ACL_EXTATTR_NAME, td); + + /* + * An attempt to remove ACL from a file that didn't have + * any extended entries is not an error. + */ + if (error == ENOATTR) + error = 0; + + } else { + error = vn_extattr_set(vp, IO_NODELOCKED, + NFS4_ACL_EXTATTR_NAMESPACE, NFS4_ACL_EXTATTR_NAME, + sizeof(*aclp), (char *) aclp, td); + } + + /* + * Map lack of attribute definition in UFS_EXTATTR into lack of + * support for ACLs on the filesystem. + */ + if (error == ENOATTR) + return (EOPNOTSUPP); + + if (error) + return (error); + + mode = ip->i_mode; + + acl_nfs4_sync_mode_from_acl(&mode, aclp); + + ip->i_mode &= ACL_PRESERVE_MASK; + ip->i_mode |= mode; + DIP_SET(ip, i_mode, ip->i_mode); + ip->i_flag |= IN_CHANGE; + + VN_KNOTE_UNLOCKED(vp, NOTE_ATTRIB); + + return (0); +} + static int ufs_setacl_nfs4(struct vop_setacl_args *ap) { int error; - mode_t mode; struct inode *ip = VTOI(ap->a_vp); if ((ap->a_vp->v_mount->mnt_flag & MNT_NFS4ACLS) == 0) @@ -380,47 +455,16 @@ if ((error = VOP_ACCESSX(ap->a_vp, VWRITE_ACL, ap->a_cred, ap->a_td))) return (error); - if (acl_nfs4_is_trivial(ap->a_aclp, ip->i_uid)) { - error = vn_extattr_rm(ap->a_vp, IO_NODELOCKED, - NFS4_ACL_EXTATTR_NAMESPACE, - NFS4_ACL_EXTATTR_NAME, ap->a_td); - - /* - * An attempt to remove ACL from a file that didn't have - * any extended entries is not an error. - */ - if (error == ENOATTR) - error = 0; - - } else { - error = vn_extattr_set(ap->a_vp, IO_NODELOCKED, - NFS4_ACL_EXTATTR_NAMESPACE, - NFS4_ACL_EXTATTR_NAME, - sizeof(*ap->a_aclp), - (char *) ap->a_aclp, ap->a_td); - } - /* - * Map lack of attribute definition in UFS_EXTATTR into lack of - * support for ACLs on the filesystem. + * With NFSv4 ACLs, chmod(2) may need to add additional entries. + * Make sure it has enough room for that - splitting every entry + * into two and appending "canonical six" entries at the end. */ - if (error == ENOATTR) - return (EOPNOTSUPP); + if (ap->a_aclp->acl_cnt > (ACL_MAX_ENTRIES - 6) / 2) + return (ENOSPC); - if (error) - return (error); - - mode = ip->i_mode; - - acl_nfs4_sync_mode_from_acl(&mode, ap->a_aclp); - - ip->i_mode &= ACL_PRESERVE_MASK; - ip->i_mode |= mode; - DIP_SET(ip, i_mode, ip->i_mode); - ip->i_flag |= IN_CHANGE; + error = ufs_setacl_nfs4_internal(ap->a_vp, ap->a_aclp, ap->a_td); - VN_KNOTE_UNLOCKED(ap->a_vp, NOTE_ATTRIB); - return (0); } @@ -578,6 +622,14 @@ if ((ap->a_vp->v_mount->mnt_flag & MNT_NFS4ACLS) == 0) return (EINVAL); + /* + * With NFSv4 ACLs, chmod(2) may need to add additional entries. + * Make sure it has enough room for that - splitting every entry + * into two and appending "canonical six" entries at the end. + */ + if (ap->a_aclp->acl_cnt > (ACL_MAX_ENTRIES - 6) / 2) + return (ENOSPC); + if (ap->a_vp->v_type == VDIR) is_directory = 1;
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200910281834.n9SIY9Wl029702>
