]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/vfs/kpi_vfs.c
xnu-792.13.8.tar.gz
[apple/xnu.git] / bsd / vfs / kpi_vfs.c
index 7f72472a95468b11a0674cef47151762ffc587de..b357a58a3b482f7cfcf331f1c8dec8efb6fd8461 100644 (file)
@@ -1,23 +1,31 @@
 /*
  * Copyright (c) 2000-2005 Apple Computer, Inc. All rights reserved.
  *
 /*
  * Copyright (c) 2000-2005 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * @APPLE_LICENSE_OSREFERENCE_HEADER_START@
  * 
  * 
- * The contents of this file constitute Original Code as defined in and
- * are subject to the Apple Public Source License Version 1.1 (the
- * "License").  You may not use this file except in compliance with the
- * License.  Please obtain a copy of the License at
- * http://www.apple.com/publicsource and read it before using this file.
- * 
- * This Original Code and all software distributed under the License are
- * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
- * License for the specific language governing rights and limitations
- * under the License.
- * 
- * @APPLE_LICENSE_HEADER_END@
+ * This file contains Original Code and/or Modifications of Original Code 
+ * as defined in and that are subject to the Apple Public Source License 
+ * Version 2.0 (the 'License'). You may not use this file except in 
+ * compliance with the License.  The rights granted to you under the 
+ * License may not be used to create, or enable the creation or 
+ * redistribution of, unlawful or unlicensed copies of an Apple operating 
+ * system, or to circumvent, violate, or enable the circumvention or 
+ * violation of, any terms of an Apple operating system software license 
+ * agreement.
+ *
+ * Please obtain a copy of the License at 
+ * http://www.opensource.apple.com/apsl/ and read it before using this 
+ * file.
+ *
+ * The Original Code and all software distributed under the License are 
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 
+ * Please see the License for the specific language governing rights and 
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
  */
 /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
 /*
  */
 /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
 /*
 #include <kern/assert.h>
 #include <kern/kalloc.h>
 
 #include <kern/assert.h>
 #include <kern/kalloc.h>
 
+#include <libkern/OSByteOrder.h>
+
 #include <miscfs/specfs/specdev.h>
 
 #include <mach/mach_types.h>
 #include <miscfs/specfs/specdev.h>
 
 #include <mach/mach_types.h>
@@ -1505,6 +1515,39 @@ current_rootdir(void)
        return vp;
 }
 
        return vp;
 }
 
+/*
+ * Get a filesec and optional acl contents from an extended attribute.
+ * Function will attempt to retrive ACL, UUID, and GUID information using a
+ * read of a named extended attribute (KAUTH_FILESEC_XATTR).
+ *
+ * Parameters: vp                      The vnode on which to operate.
+ *             fsecp                   The filesec (and ACL, if any) being
+ *                                     retrieved.
+ *             ctx                     The vnode context in which the
+ *                                     operation is to be attempted.
+ *
+ * Returns:    0                       Success
+ *             !0                      errno value
+ *
+ * Notes:      The kauth_filesec_t in '*fsecp', if retrieved, will be in
+ *             host byte order, as will be the ACL contents, if any.
+ *             Internally, we will cannonize these values from network (PPC)
+ *             byte order after we retrieve them so that the on-disk contents
+ *             of the extended attribute are identical for both PPC and Intel
+ *             (if we were not being required to provide this service via
+ *             fallback, this would be the job of the filesystem
+ *             'VNOP_GETATTR' call).
+ *
+ *             We use ntohl() because it has a transitive property on Intel
+ *             machines and no effect on PPC mancines.  This guarantees us
+ *
+ * XXX:                Deleting rather than ignoreing a corrupt security structure is
+ *             probably the only way to reset it without assistance from an
+ *             file system integrity checking tool.  Right now we ignore it.
+ *
+ * XXX:                We should enummerate the possible errno values here, and where
+ *             in the code they originated.
+ */
 static int
 vnode_get_filesec(vnode_t vp, kauth_filesec_t *fsecp, vfs_context_t ctx)
 {
 static int
 vnode_get_filesec(vnode_t vp, kauth_filesec_t *fsecp, vfs_context_t ctx)
 {
@@ -1513,6 +1556,9 @@ vnode_get_filesec(vnode_t vp, kauth_filesec_t *fsecp, vfs_context_t ctx)
        size_t  fsec_size;
        size_t  xsize, rsize;
        int     error;
        size_t  fsec_size;
        size_t  xsize, rsize;
        int     error;
+       int     i;
+       uint32_t        host_fsec_magic;
+       uint32_t        host_acl_entrycount;
 
        fsec = NULL;
        fsec_uio = NULL;
 
        fsec = NULL;
        fsec_uio = NULL;
@@ -1556,28 +1602,38 @@ vnode_get_filesec(vnode_t vp, kauth_filesec_t *fsecp, vfs_context_t ctx)
        }
 
        /*
        }
 
        /*
-        * Validate security structure.  If it's corrupt, we will
-        * just ignore it.
+        * Validate security structure; the validation must take place in host
+        * byte order.  If it's corrupt, we will just ignore it.
         */
         */
+
+       /* Validate the size before trying to convert it */
        if (rsize < KAUTH_FILESEC_SIZE(0)) {
                KAUTH_DEBUG("ACL - DATA TOO SMALL (%d)", rsize);
                goto out;
        }
        if (rsize < KAUTH_FILESEC_SIZE(0)) {
                KAUTH_DEBUG("ACL - DATA TOO SMALL (%d)", rsize);
                goto out;
        }
-       if (fsec->fsec_magic != KAUTH_FILESEC_MAGIC) {
-               KAUTH_DEBUG("ACL - BAD MAGIC %x", fsec->fsec_magic);
-               goto out;
-       }
-       if ((fsec->fsec_acl.acl_entrycount != KAUTH_FILESEC_NOACL) &&
-           (fsec->fsec_acl.acl_entrycount > KAUTH_ACL_MAX_ENTRIES)) {
-               KAUTH_DEBUG("ACL - BAD ENTRYCOUNT %x", fsec->fsec_entrycount);
+
+       /* Validate the magic number before trying to convert it */
+       host_fsec_magic = ntohl(KAUTH_FILESEC_MAGIC);
+       if (fsec->fsec_magic != host_fsec_magic) {
+               KAUTH_DEBUG("ACL - BAD MAGIC %x", host_fsec_magic);
                goto out;
        }
                goto out;
        }
-       if ((fsec->fsec_acl.acl_entrycount != KAUTH_FILESEC_NOACL) &&
-           (KAUTH_FILESEC_SIZE(fsec->fsec_acl.acl_entrycount) > rsize)) {
-               KAUTH_DEBUG("ACL - BUFFER OVERFLOW (%d entries too big for %d)", fsec->fsec_acl.acl_entrycount, rsize);
-               goto out;
+
+       /* Validate the entry count before trying to convert it. */
+       host_acl_entrycount = ntohl(fsec->fsec_acl.acl_entrycount);
+       if (host_acl_entrycount != KAUTH_FILESEC_NOACL) {
+               if (host_acl_entrycount > KAUTH_ACL_MAX_ENTRIES) {
+                       KAUTH_DEBUG("ACL - BAD ENTRYCOUNT %x", host_acl_entrycount);
+                       goto out;
+               }
+               if (KAUTH_FILESEC_SIZE(host_acl_entrycount) > rsize) {
+                       KAUTH_DEBUG("ACL - BUFFER OVERFLOW (%d entries too big for %d)", host_acl_entrycount, rsize);
+                       goto out;
+               }
        }
 
        }
 
+       kauth_filesec_acl_setendian(KAUTH_ENDIAN_HOST, fsec, NULL);
+
        *fsecp = fsec;
        fsec = NULL;
        error = 0;
        *fsecp = fsec;
        fsec = NULL;
        error = 0;
@@ -1591,11 +1647,44 @@ out:
        return(error);
 }
 
        return(error);
 }
 
+/*
+ * Set a filesec and optional acl contents into an extended attribute.
+ * function will attempt to store ACL, UUID, and GUID information using a
+ * write to a named extended attribute (KAUTH_FILESEC_XATTR).  The 'acl'
+ * may or may not point to the `fsec->fsec_acl`, depending on whether the
+ * original caller supplied an acl.
+ *
+ * Parameters: vp                      The vnode on which to operate.
+ *             fsec                    The filesec being set.
+ *             acl                     The acl to be associated with 'fsec'.
+ *             ctx                     The vnode context in which the
+ *                                     operation is to be attempted.
+ *
+ * Returns:    0                       Success
+ *             !0                      errno value
+ *
+ * Notes:      Both the fsec and the acl are always valid.
+ *
+ *             The kauth_filesec_t in 'fsec', if any, is in host byte order,
+ *             as are the acl contents, if they are used.  Internally, we will
+ *             cannonize these values into network (PPC) byte order before we
+ *             attempt to write them so that the on-disk contents of the
+ *             extended attribute are identical for both PPC and Intel (if we
+ *             were not being required to provide this service via fallback,
+ *             this would be the job of the filesystem 'VNOP_SETATTR' call).
+ *             We reverse this process on the way out, so we leave with the
+ *             same byte order we started with.
+ *
+ * XXX:                We should enummerate the possible errno values here, and where
+ *             in the code they originated.
+ */
 static int
 vnode_set_filesec(vnode_t vp, kauth_filesec_t fsec, kauth_acl_t acl, vfs_context_t ctx)
 {
 static int
 vnode_set_filesec(vnode_t vp, kauth_filesec_t fsec, kauth_acl_t acl, vfs_context_t ctx)
 {
-       uio_t   fsec_uio;
-       int     error;
+       uio_t           fsec_uio;
+       int             error;
+       int             i;
+       uint32_t        saved_acl_copysize;
 
        fsec_uio = NULL;
        
 
        fsec_uio = NULL;
        
@@ -1604,8 +1693,16 @@ vnode_set_filesec(vnode_t vp, kauth_filesec_t fsec, kauth_acl_t acl, vfs_context
                error = ENOMEM;
                goto out;
        }
                error = ENOMEM;
                goto out;
        }
+       /*
+        * Save the pre-converted ACL copysize, because it gets swapped too
+        * if we are running with the wrong endianness.
+        */
+       saved_acl_copysize = KAUTH_ACL_COPYSIZE(acl);
+
+       kauth_filesec_acl_setendian(KAUTH_ENDIAN_DISK, fsec, acl);
+
        uio_addiov(fsec_uio, CAST_USER_ADDR_T(fsec), sizeof(struct kauth_filesec) - sizeof(struct kauth_acl));
        uio_addiov(fsec_uio, CAST_USER_ADDR_T(fsec), sizeof(struct kauth_filesec) - sizeof(struct kauth_acl));
-       uio_addiov(fsec_uio, CAST_USER_ADDR_T(acl), KAUTH_ACL_COPYSIZE(acl));
+       uio_addiov(fsec_uio, CAST_USER_ADDR_T(acl), saved_acl_copysize);
        error = vn_setxattr(vp,
            KAUTH_FILESEC_XATTR,
            fsec_uio,
        error = vn_setxattr(vp,
            KAUTH_FILESEC_XATTR,
            fsec_uio,
@@ -1613,6 +1710,8 @@ vnode_set_filesec(vnode_t vp, kauth_filesec_t fsec, kauth_acl_t acl, vfs_context
            ctx);
        VFS_DEBUG(ctx, vp, "SETATTR - set ACL returning %d", error);
 
            ctx);
        VFS_DEBUG(ctx, vp, "SETATTR - set ACL returning %d", error);
 
+       kauth_filesec_acl_setendian(KAUTH_ENDIAN_HOST, fsec, acl);
+
 out:
        if (fsec_uio != NULL)
                uio_free(fsec_uio);
 out:
        if (fsec_uio != NULL)
                uio_free(fsec_uio);
@@ -1826,6 +1925,28 @@ out:
        return(error);
 }
 
        return(error);
 }
 
+/*
+ * Set the attributes on a vnode in a vnode context.
+ *
+ * Parameters: vp                      The vnode whose attributes to set.
+ *             vap                     A pointer to the attributes to set.
+ *             ctx                     The vnode context in which the
+ *                                     operation is to be attempted.
+ *
+ * Returns:    0                       Success
+ *             !0                      errno value
+ *
+ * Notes:      The kauth_filesec_t in 'vap', if any, is in host byte order.
+ *
+ *             The contents of the data area pointed to by 'vap' may be
+ *             modified if the vnode is on a filesystem which has been
+ *             mounted with ingore ownership flags, or by the underlyng
+ *             VFS itself, or by the fallback code, if the underlying VFS
+ *             does not support ACL, UUID, or GUUID attributes directly.
+ *
+ * XXX:                We should enummerate the possible errno values here, and where
+ *             in the code they originated.
+ */
 int
 vnode_setattr(vnode_t vp, struct vnode_attr *vap, vfs_context_t ctx)
 {
 int
 vnode_setattr(vnode_t vp, struct vnode_attr *vap, vfs_context_t ctx)
 {
@@ -1835,8 +1956,10 @@ vnode_setattr(vnode_t vp, struct vnode_attr *vap, vfs_context_t ctx)
         * Make sure the filesystem is mounted R/W.
         * If not, return an error.
         */
         * Make sure the filesystem is mounted R/W.
         * If not, return an error.
         */
-       if (vfs_isrdonly(vp->v_mount))
-               return(EROFS);
+       if (vfs_isrdonly(vp->v_mount)) {
+               error = EROFS;
+               goto out;
+       }
        
        /*
         * If ownership is being ignored on this volume, we silently discard
        
        /*
         * If ownership is being ignored on this volume, we silently discard
@@ -1858,7 +1981,8 @@ vnode_setattr(vnode_t vp, struct vnode_attr *vap, vfs_context_t ctx)
        if (!vfs_extendedsecurity(vnode_mount(vp)) &&
            (VATTR_IS_ACTIVE(vap, va_acl) || VATTR_IS_ACTIVE(vap, va_uuuid) || VATTR_IS_ACTIVE(vap, va_guuid))) {
                KAUTH_DEBUG("SETATTR - returning ENOTSUP to request to set extended security");
        if (!vfs_extendedsecurity(vnode_mount(vp)) &&
            (VATTR_IS_ACTIVE(vap, va_acl) || VATTR_IS_ACTIVE(vap, va_uuuid) || VATTR_IS_ACTIVE(vap, va_guuid))) {
                KAUTH_DEBUG("SETATTR - returning ENOTSUP to request to set extended security");
-               return(ENOTSUP);
+               error = ENOTSUP;
+               goto out;
        }
 
        error = VNOP_SETATTR(vp, vap, ctx);
        }
 
        error = VNOP_SETATTR(vp, vap, ctx);
@@ -1889,13 +2013,35 @@ vnode_setattr(vnode_t vp, struct vnode_attr *vap, vfs_context_t ctx)
                        add_fsevent(FSE_CHOWN, ctx, FSE_ARG_VNODE, vp, FSE_ARG_DONE);
            }
        }
                        add_fsevent(FSE_CHOWN, ctx, FSE_ARG_VNODE, vp, FSE_ARG_DONE);
            }
        }
+
+out:
        return(error);
 }
 
 /*
        return(error);
 }
 
 /*
- * Following an operation which sets attributes (setattr, create, etc.) we may
- * need to perform fallback operations to get attributes saved.
- */ 
+ * Fallback for setting the attributes on a vnode in a vnode context.  This
+ * Function will attempt to store ACL, UUID, and GUID information utilizing
+ * a read/modify/write operation against an EA used as a backing store for
+ * the object.
+ *
+ * Parameters: vp                      The vnode whose attributes to set.
+ *             vap                     A pointer to the attributes to set.
+ *             ctx                     The vnode context in which the
+ *                                     operation is to be attempted.
+ *
+ * Returns:    0                       Success
+ *             !0                      errno value
+ *
+ * Notes:      The kauth_filesec_t in 'vap', if any, is in host byte order,
+ *             as are the fsec and lfsec, if they are used.
+ *
+ *             The contents of the data area pointed to by 'vap' may be
+ *             modified to indicate that the attribute is supported for
+ *             any given requested attribute.
+ *
+ * XXX:                We should enummerate the possible errno values here, and where
+ *             in the code they originated.
+ */
 int
 vnode_setattr_fallback(vnode_t vp, struct vnode_attr *vap, vfs_context_t ctx)
 {
 int
 vnode_setattr_fallback(vnode_t vp, struct vnode_attr *vap, vfs_context_t ctx)
 {
@@ -1909,7 +2055,8 @@ vnode_setattr_fallback(vnode_t vp, struct vnode_attr *vap, vfs_context_t ctx)
        /*
         * Extended security fallback via extended attributes.
         *
        /*
         * Extended security fallback via extended attributes.
         *
-        * Note that we do not free the filesec; the caller is expected to do this.
+        * Note that we do not free the filesec; the caller is expected to
+        * do this.
         */
        if (VATTR_NOT_RETURNED(vap, va_acl) ||
            VATTR_NOT_RETURNED(vap, va_uuuid) ||
         */
        if (VATTR_NOT_RETURNED(vap, va_acl) ||
            VATTR_NOT_RETURNED(vap, va_uuuid) ||
@@ -1917,7 +2064,8 @@ vnode_setattr_fallback(vnode_t vp, struct vnode_attr *vap, vfs_context_t ctx)
                VFS_DEBUG(ctx, vp, "SETATTR - doing filesec fallback");
 
                /*
                VFS_DEBUG(ctx, vp, "SETATTR - doing filesec fallback");
 
                /*
-                * Fail for file types that we don't permit extended security to be set on.
+                * Fail for file types that we don't permit extended security
+                * to be set on.
                 */
                if ((vp->v_type != VDIR) && (vp->v_type != VLNK) && (vp->v_type != VREG)) {
                        VFS_DEBUG(ctx, vp, "SETATTR - Can't write ACL to file type %d", vnode_vtype(vp));
                 */
                if ((vp->v_type != VDIR) && (vp->v_type != VLNK) && (vp->v_type != VREG)) {
                        VFS_DEBUG(ctx, vp, "SETATTR - Can't write ACL to file type %d", vnode_vtype(vp));
@@ -1926,8 +2074,9 @@ vnode_setattr_fallback(vnode_t vp, struct vnode_attr *vap, vfs_context_t ctx)
                }
 
                /*
                }
 
                /*
-                * If we don't have all the extended security items, we need to fetch the existing
-                * data to perform a read-modify-write operation.
+                * If we don't have all the extended security items, we need
+                * to fetch the existing data to perform a read-modify-write
+                * operation.
                 */
                fsec = NULL;
                if (!VATTR_IS_ACTIVE(vap, va_acl) ||
                 */
                fsec = NULL;
                if (!VATTR_IS_ACTIVE(vap, va_acl) ||
@@ -1982,7 +2131,8 @@ vnode_setattr_fallback(vnode_t vp, struct vnode_attr *vap, vfs_context_t ctx)
                }
                
                /*
                }
                
                /*
-                * If the filesec data is all invalid, we can just remove the EA completely.
+                * If the filesec data is all invalid, we can just remove
+                * the EA completely.
                 */
                if ((facl->acl_entrycount == KAUTH_FILESEC_NOACL) &&
                    kauth_guid_equal(&fsec->fsec_owner, &kauth_null_guid) &&
                 */
                if ((facl->acl_entrycount == KAUTH_FILESEC_NOACL) &&
                    kauth_guid_equal(&fsec->fsec_owner, &kauth_null_guid) &&