]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/miscfs/nullfs/null_vnops.c
xnu-7195.50.7.100.1.tar.gz
[apple/xnu.git] / bsd / miscfs / nullfs / null_vnops.c
index 6afadbfab808bd2253271253f6f39636808e0b98..a351309c3c6e5f355076d51973106da91bb89a9e 100644 (file)
@@ -77,6 +77,7 @@
 #include <sys/ubc.h>
 #include <sys/types.h>
 #include <sys/dirent.h>
+#include <sys/kauth.h>
 
 #include "nullfs.h"
 
@@ -118,6 +119,25 @@ nullfs_checkspecialvp(struct vnode* vp)
        return result;
 }
 
+vfs_context_t
+nullfs_get_patched_context(struct null_mount * null_mp, vfs_context_t ctx)
+{
+       struct vfs_context* ectx = ctx;
+       if ((null_mp->nullm_flags & NULLM_UNVEIL) == NULLM_UNVEIL) {
+               ectx = vfs_context_create(ctx);
+               ectx->vc_ucred = kauth_cred_setuidgid(ectx->vc_ucred, null_mp->uid, null_mp->gid);
+       }
+       return ectx;
+}
+
+void
+nullfs_cleanup_patched_context(struct null_mount * null_mp, vfs_context_t ctx)
+{
+       if ((null_mp->nullm_flags & NULLM_UNVEIL) == NULLM_UNVEIL) {
+               vfs_context_rele(ctx);
+       }
+}
+
 static int
 nullfs_default(__unused struct vnop_generic_args * args)
 {
@@ -134,6 +154,7 @@ nullfs_special_getattr(struct vnop_getattr_args * args)
        ino_t ino = NULL_ROOT_INO;
        struct vnode_attr covered_rootattr;
        vnode_t checkvp = null_mp->nullm_lowerrootvp;
+       vfs_context_t ectx = nullfs_get_patched_context(null_mp, args->a_context);
 
        VATTR_INIT(&covered_rootattr);
        VATTR_WANTED(&covered_rootattr, va_uid);
@@ -147,16 +168,18 @@ nullfs_special_getattr(struct vnop_getattr_args * args)
        if (vnode_getwithvid(checkvp, null_mp->nullm_lowerrootvid)) {
                checkvp = vfs_vnodecovered(mp);
                if (checkvp == NULL) {
+                       nullfs_cleanup_patched_context(null_mp, ectx);
                        return EIO;
                }
        }
 
-       int error = vnode_getattr(checkvp, &covered_rootattr, args->a_context);
+       int error = vnode_getattr(checkvp, &covered_rootattr, ectx);
 
        vnode_put(checkvp);
        if (error) {
                /* we should have been able to get attributes fore one of the two choices so
                 * fail if we didn't */
+               nullfs_cleanup_patched_context(null_mp, ectx);
                return error;
        }
 
@@ -175,7 +198,12 @@ nullfs_special_getattr(struct vnop_getattr_args * args)
        VATTR_RETURN(args->a_vap, va_iosize, vfs_statfs(mp)->f_iosize);
        VATTR_RETURN(args->a_vap, va_fileid, ino);
        VATTR_RETURN(args->a_vap, va_linkid, ino);
-       VATTR_RETURN(args->a_vap, va_fsid, vfs_statfs(mp)->f_fsid.val[0]); // return the fsid of the mount point
+       if (VATTR_IS_ACTIVE(args->a_vap, va_fsid)) {
+               VATTR_RETURN(args->a_vap, va_fsid, vfs_statfs(mp)->f_fsid.val[0]); // return the fsid of the mount point
+       }
+       if (VATTR_IS_ACTIVE(args->a_vap, va_fsid64)) {
+               VATTR_RETURN(args->a_vap, va_fsid64, vfs_statfs(mp)->f_fsid);
+       }
        VATTR_RETURN(args->a_vap, va_filerev, 0);
        VATTR_RETURN(args->a_vap, va_gen, 0);
        VATTR_RETURN(args->a_vap, va_flags, UF_HIDDEN); /* mark our fake directories as hidden. People
@@ -216,6 +244,7 @@ nullfs_special_getattr(struct vnop_getattr_args * args)
                args->a_vap->va_modify_time.tv_nsec = covered_rootattr.va_access_time.tv_nsec;
        }
 
+       nullfs_cleanup_patched_context(null_mp, ectx);
        return 0;
 }
 
@@ -224,6 +253,7 @@ nullfs_getattr(struct vnop_getattr_args * args)
 {
        int error;
        struct null_mount * null_mp = MOUNTTONULLMOUNT(vnode_mount(args->a_vp));
+       kauth_cred_t cred = vfs_context_ucred(args->a_context);
        NULLFSDEBUG("%s %p\n", __FUNCTION__, args->a_vp);
 
        lck_mtx_lock(&null_mp->nullm_lock);
@@ -236,18 +266,57 @@ nullfs_getattr(struct vnop_getattr_args * args)
 
        /* this will return a different inode for third than read dir will */
        struct vnode * lowervp = NULLVPTOLOWERVP(args->a_vp);
-
+       vfs_context_t ectx = nullfs_get_patched_context(null_mp, args->a_context);
        error = vnode_getwithref(lowervp);
+
        if (error == 0) {
-               error = VNOP_GETATTR(lowervp, args->a_vap, args->a_context);
+               error = VNOP_GETATTR(lowervp, args->a_vap, ectx);
                vnode_put(lowervp);
 
                if (error == 0) {
                        /* fix up fsid so it doesn't say the underlying fs*/
-                       VATTR_RETURN(args->a_vap, va_fsid, vfs_statfs(vnode_mount(args->a_vp))->f_fsid.val[0]);
+                       if (VATTR_IS_ACTIVE(args->a_vap, va_fsid)) {
+                               VATTR_RETURN(args->a_vap, va_fsid, vfs_statfs(vnode_mount(args->a_vp))->f_fsid.val[0]);
+                       }
+                       if (VATTR_IS_ACTIVE(args->a_vap, va_fsid64)) {
+                               VATTR_RETURN(args->a_vap, va_fsid64, vfs_statfs(vnode_mount(args->a_vp))->f_fsid);
+                       }
+
+                       /* Conjure up permissions */
+                       if ((null_mp->nullm_flags & NULLM_UNVEIL) == NULLM_UNVEIL) {
+                               if (VATTR_IS_ACTIVE(args->a_vap, va_mode)) {
+                                       mode_t mode = args->a_vap->va_mode; // We will take away permisions if we don't have them
+
+                                       // Check for authorizations
+                                       // If we can read:
+                                       if (vnode_authorize(lowervp, NULL, KAUTH_VNODE_GENERIC_READ_BITS, ectx) == 0) {
+                                               mode |= S_IRUSR;
+                                       } else {
+                                               mode &= ~S_IRUSR;
+                                       }
+
+                                       // Or execute
+                                       // Directories need an execute bit...
+                                       if (vnode_authorize(lowervp, NULL, KAUTH_VNODE_GENERIC_EXECUTE_BITS, ectx) == 0) {
+                                               mode |= S_IXUSR;
+                                       } else {
+                                               mode &= ~S_IXUSR;
+                                       }
+
+                                       NULLFSDEBUG("Settings bits to %d\n", mode);
+                                       VATTR_RETURN(args->a_vap, va_mode, mode);
+                               }
+                               if (VATTR_IS_ACTIVE(args->a_vap, va_uid)) {
+                                       VATTR_RETURN(args->a_vap, va_uid, kauth_cred_getuid(cred));
+                               }
+                               if (VATTR_IS_ACTIVE(args->a_vap, va_gid)) {
+                                       VATTR_RETURN(args->a_vap, va_gid, kauth_cred_getgid(cred));
+                               }
+                       }
                }
        }
 
+       nullfs_cleanup_patched_context(null_mp, ectx);
        return error;
 }
 
@@ -256,21 +325,24 @@ nullfs_open(struct vnop_open_args * args)
 {
        int error;
        struct vnode *vp, *lvp;
-
+       mount_t mp                  = vnode_mount(args->a_vp);
+       struct null_mount * null_mp = MOUNTTONULLMOUNT(mp);
        NULLFSDEBUG("%s %p\n", __FUNCTION__, args->a_vp);
 
        if (nullfs_checkspecialvp(args->a_vp)) {
                return 0; /* nothing extra needed */
        }
 
+       vfs_context_t ectx = nullfs_get_patched_context(null_mp, args->a_context);
        vp    = args->a_vp;
        lvp   = NULLVPTOLOWERVP(vp);
        error = vnode_getwithref(lvp);
        if (error == 0) {
-               error = VNOP_OPEN(lvp, args->a_mode, args->a_context);
+               error = VNOP_OPEN(lvp, args->a_mode, ectx);
                vnode_put(lvp);
        }
 
+       nullfs_cleanup_patched_context(null_mp, ectx);
        return error;
 }
 
@@ -279,6 +351,8 @@ nullfs_close(struct vnop_close_args * args)
 {
        int error;
        struct vnode *vp, *lvp;
+       mount_t mp                  = vnode_mount(args->a_vp);
+       struct null_mount * null_mp = MOUNTTONULLMOUNT(mp);
 
        NULLFSDEBUG("%s %p\n", __FUNCTION__, args->a_vp);
 
@@ -286,14 +360,17 @@ nullfs_close(struct vnop_close_args * args)
                return 0; /* nothing extra needed */
        }
 
+       vfs_context_t ectx = nullfs_get_patched_context(null_mp, args->a_context);
        vp  = args->a_vp;
        lvp = NULLVPTOLOWERVP(vp);
 
        error = vnode_getwithref(lvp);
        if (error == 0) {
-               error = VNOP_CLOSE(lvp, args->a_fflag, args->a_context);
+               error = VNOP_CLOSE(lvp, args->a_fflag, ectx);
                vnode_put(lvp);
        }
+
+       nullfs_cleanup_patched_context(null_mp, ectx);
        return error;
 }
 
@@ -350,6 +427,7 @@ null_special_lookup(struct vnop_lookup_args * ap)
        struct mount * mp           = vnode_mount(dvp);
        struct null_mount * null_mp = MOUNTTONULLMOUNT(mp);
        int error                   = ENOENT;
+       vfs_context_t ectx     = nullfs_get_patched_context(null_mp, ap->a_context);
 
        if (dvp == null_mp->nullm_rootvp) {
                /* handle . and .. */
@@ -411,10 +489,10 @@ null_special_lookup(struct vnop_lookup_args * ap)
                 *  so we got a match
                 *   4. Anything else results in ENOENT.
                 */
-               error = null_get_lowerparent(null_mp->nullm_lowerrootvp, &ldvp, ap->a_context);
+               error = null_get_lowerparent(null_mp->nullm_lowerrootvp, &ldvp, ectx);
 
                if (error == 0) {
-                       error = VNOP_LOOKUP(ldvp, &lvp, cnp, ap->a_context);
+                       error = VNOP_LOOKUP(ldvp, &lvp, cnp, ectx);
                        vnode_put(ldvp);
 
                        if (error == 0) {
@@ -437,6 +515,7 @@ null_special_lookup(struct vnop_lookup_args * ap)
        }
 
 end:
+       nullfs_cleanup_patched_context(null_mp, ectx);
        if (error == 0) {
                *ap->a_vpp = vp;
        }
@@ -457,6 +536,7 @@ null_lookup(struct vnop_lookup_args * ap)
        struct mount * mp;
        struct null_mount * null_mp;
        int error;
+       vfs_context_t ectx;
 
        NULLFSDEBUG("%s parent: %p component: %.*s\n", __FUNCTION__, ap->a_dvp, cnp->cn_namelen, cnp->cn_nameptr);
 
@@ -467,6 +547,7 @@ null_lookup(struct vnop_lookup_args * ap)
        }
        null_mp = MOUNTTONULLMOUNT(mp);
 
+
        lck_mtx_lock(&null_mp->nullm_lock);
        if (nullfs_isspecialvp(dvp)) {
                error = null_special_lookup(ap);
@@ -496,6 +577,7 @@ null_lookup(struct vnop_lookup_args * ap)
        }
 
 notdot:
+       ectx = nullfs_get_patched_context(null_mp, ap->a_context);
        ldvp = NULLVPTOLOWERVP(dvp);
        vp = lvp = NULL;
 
@@ -505,10 +587,11 @@ notdot:
         */
        error = vnode_getwithref(ldvp);
        if (error) {
+               nullfs_cleanup_patched_context(null_mp, ectx);
                return error;
        }
 
-       error = VNOP_LOOKUP(ldvp, &lvp, cnp, ap->a_context);
+       error = VNOP_LOOKUP(ldvp, &lvp, cnp, ectx);
 
        vnode_put(ldvp);
 
@@ -529,6 +612,7 @@ notdot:
                vnode_put(lvp);
        }
 
+       nullfs_cleanup_patched_context(null_mp, ectx);
        return error;
 }
 
@@ -725,14 +809,16 @@ nullfs_readdir(struct vnop_readdir_args * ap)
        }
        lck_mtx_unlock(&null_mp->nullm_lock);
 
+       vfs_context_t ectx = nullfs_get_patched_context(null_mp, ap->a_context);
        vp    = ap->a_vp;
        lvp   = NULLVPTOLOWERVP(vp);
        error = vnode_getwithref(lvp);
        if (error == 0) {
-               error = VNOP_READDIR(lvp, ap->a_uio, ap->a_flags, ap->a_eofflag, ap->a_numdirent, ap->a_context);
+               error = VNOP_READDIR(lvp, ap->a_uio, ap->a_flags, ap->a_eofflag, ap->a_numdirent, ectx);
                vnode_put(lvp);
        }
 
+       nullfs_cleanup_patched_context(null_mp, ectx);
        return error;
 }
 
@@ -742,17 +828,19 @@ nullfs_readlink(struct vnop_readlink_args * ap)
        NULLFSDEBUG("%s %p\n", __FUNCTION__, ap->a_vp);
        int error;
        struct vnode *vp, *lvp;
+       struct null_mount * null_mp = MOUNTTONULLMOUNT(vnode_mount(ap->a_vp));
 
        if (nullfs_checkspecialvp(ap->a_vp)) {
                return ENOTSUP; /* the special vnodes aren't links */
        }
 
+       vfs_context_t ectx = nullfs_get_patched_context(null_mp, ap->a_context);
        vp  = ap->a_vp;
        lvp = NULLVPTOLOWERVP(vp);
 
        error = vnode_getwithref(lvp);
        if (error == 0) {
-               error = VNOP_READLINK(lvp, ap->a_uio, ap->a_context);
+               error = VNOP_READLINK(lvp, ap->a_uio, ectx);
                vnode_put(lvp);
 
                if (error) {
@@ -760,6 +848,7 @@ nullfs_readlink(struct vnop_readlink_args * ap)
                }
        }
 
+       nullfs_cleanup_patched_context(null_mp, ectx);
        return error;
 }
 
@@ -782,6 +871,7 @@ nullfs_mmap(struct vnop_mmap_args * args)
 {
        int error;
        struct vnode *vp, *lvp;
+       struct null_mount * null_mp = MOUNTTONULLMOUNT(vnode_mount(args->a_vp));
 
        NULLFSDEBUG("%s %p\n", __FUNCTION__, args->a_vp);
 
@@ -789,14 +879,16 @@ nullfs_mmap(struct vnop_mmap_args * args)
                return 0; /* nothing extra needed */
        }
 
+       vfs_context_t ectx = nullfs_get_patched_context(null_mp, args->a_context);
        vp    = args->a_vp;
        lvp   = NULLVPTOLOWERVP(vp);
        error = vnode_getwithref(lvp);
        if (error == 0) {
-               error = VNOP_MMAP(lvp, args->a_fflags, args->a_context);
+               error = VNOP_MMAP(lvp, args->a_fflags, ectx);
                vnode_put(lvp);
        }
 
+       nullfs_cleanup_patched_context(null_mp, ectx);
        return error;
 }
 
@@ -805,6 +897,7 @@ nullfs_mnomap(struct vnop_mnomap_args * args)
 {
        int error;
        struct vnode *vp, *lvp;
+       struct null_mount * null_mp = MOUNTTONULLMOUNT(vnode_mount(args->a_vp));
 
        NULLFSDEBUG("%s %p\n", __FUNCTION__, args->a_vp);
 
@@ -812,14 +905,16 @@ nullfs_mnomap(struct vnop_mnomap_args * args)
                return 0; /* nothing extra needed */
        }
 
+       vfs_context_t ectx = nullfs_get_patched_context(null_mp, args->a_context);
        vp    = args->a_vp;
        lvp   = NULLVPTOLOWERVP(vp);
        error = vnode_getwithref(lvp);
        if (error == 0) {
-               error = VNOP_MNOMAP(lvp, args->a_context);
+               error = VNOP_MNOMAP(lvp, ectx);
                vnode_put(lvp);
        }
 
+       nullfs_cleanup_patched_context(null_mp, ectx);
        return error;
 }
 
@@ -828,6 +923,7 @@ nullfs_getxattr(struct vnop_getxattr_args * args)
 {
        int error;
        struct vnode *vp, *lvp;
+       struct null_mount * null_mp = MOUNTTONULLMOUNT(vnode_mount(args->a_vp));
 
        NULLFSDEBUG("%s %p\n", __FUNCTION__, args->a_vp);
 
@@ -835,14 +931,16 @@ nullfs_getxattr(struct vnop_getxattr_args * args)
                return ENOATTR; /* no xattrs on the special vnodes */
        }
 
+       vfs_context_t ectx = nullfs_get_patched_context(null_mp, args->a_context);
        vp    = args->a_vp;
        lvp   = NULLVPTOLOWERVP(vp);
        error = vnode_getwithref(lvp);
        if (error == 0) {
-               error = VNOP_GETXATTR(lvp, args->a_name, args->a_uio, args->a_size, args->a_options, args->a_context);
+               error = VNOP_GETXATTR(lvp, args->a_name, args->a_uio, args->a_size, args->a_options, ectx);
                vnode_put(lvp);
        }
 
+       nullfs_cleanup_patched_context(null_mp, ectx);
        return error;
 }
 
@@ -851,6 +949,7 @@ nullfs_listxattr(struct vnop_listxattr_args * args)
 {
        int error;
        struct vnode *vp, *lvp;
+       struct null_mount * null_mp = MOUNTTONULLMOUNT(vnode_mount(args->a_vp));
 
        NULLFSDEBUG("%s %p\n", __FUNCTION__, args->a_vp);
 
@@ -858,14 +957,16 @@ nullfs_listxattr(struct vnop_listxattr_args * args)
                return 0; /* no xattrs on the special vnodes */
        }
 
+       vfs_context_t ectx = nullfs_get_patched_context(null_mp, args->a_context);
        vp    = args->a_vp;
        lvp   = NULLVPTOLOWERVP(vp);
        error = vnode_getwithref(lvp);
        if (error == 0) {
-               error = VNOP_LISTXATTR(lvp, args->a_uio, args->a_size, args->a_options, args->a_context);
+               error = VNOP_LISTXATTR(lvp, args->a_uio, args->a_size, args->a_options, ectx);
                vnode_put(lvp);
        }
 
+       nullfs_cleanup_patched_context(null_mp, ectx);
        return error;
 }
 
@@ -875,7 +976,7 @@ nullfs_pagein(struct vnop_pagein_args * ap)
 {
        int error = EIO;
        struct vnode *vp, *lvp;
-
+       struct null_mount * null_mp = MOUNTTONULLMOUNT(vnode_mount(ap->a_vp));
        NULLFSDEBUG("%s %p\n", __FUNCTION__, ap->a_vp);
 
        vp  = ap->a_vp;
@@ -885,6 +986,7 @@ nullfs_pagein(struct vnop_pagein_args * ap)
                return ENOTSUP;
        }
 
+       vfs_context_t ectx = nullfs_get_patched_context(null_mp, ap->a_context);
        /*
         * Ask VM/UBC/VFS to do our bidding
         */
@@ -920,7 +1022,7 @@ nullfs_pagein(struct vnop_pagein_args * ap)
                        (void)ubc_setsize(vp, lowersize); /* ignore failures, nothing can be done */
                }
 
-               error = VNOP_READ(lvp, auio, ((ap->a_flags & UPL_IOSYNC) ? IO_SYNC : 0), ap->a_context);
+               error = VNOP_READ(lvp, auio, ((ap->a_flags & UPL_IOSYNC) ? IO_SYNC : 0), ectx);
 
                bytes_remaining = uio_resid(auio);
                if (bytes_remaining > 0 && bytes_remaining <= (user_ssize_t)ap->a_size) {
@@ -966,6 +1068,8 @@ exit_no_unmap:
        } else if ((ap->a_flags & UPL_NOCOMMIT) == 0) {
                ubc_upl_abort_range(ap->a_pl, ap->a_pl_offset, (upl_size_t)ap->a_size, UPL_ABORT_ERROR | UPL_ABORT_FREE_ON_EMPTY);
        }
+
+       nullfs_cleanup_patched_context(null_mp, ectx);
        return error;
 }
 
@@ -975,13 +1079,14 @@ nullfs_read(struct vnop_read_args * ap)
        int error = EIO;
 
        struct vnode *vp, *lvp;
-
+       struct null_mount * null_mp = MOUNTTONULLMOUNT(vnode_mount(ap->a_vp));
        NULLFSDEBUG("%s %p\n", __FUNCTION__, ap->a_vp);
 
        if (nullfs_checkspecialvp(ap->a_vp)) {
                return ENOTSUP; /* the special vnodes can't be read */
        }
 
+       vfs_context_t ectx = nullfs_get_patched_context(null_mp, ap->a_context);
        vp  = ap->a_vp;
        lvp = NULLVPTOLOWERVP(vp);
 
@@ -1003,13 +1108,15 @@ nullfs_read(struct vnop_read_args * ap)
                 * Now ask VM/UBC/VFS to do our bidding
                 */
 
-               error = VNOP_READ(lvp, ap->a_uio, ap->a_ioflag, ap->a_context);
+               error = VNOP_READ(lvp, ap->a_uio, ap->a_ioflag, ectx);
                if (error) {
                        NULLFSDEBUG("VNOP_READ failed: %d\n", error);
                }
 end:
                vnode_put(lvp);
        }
+
+       nullfs_cleanup_patched_context(null_mp, ectx);
        return error;
 }