]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/kern/kern_guarded.c
xnu-6153.121.1.tar.gz
[apple/xnu.git] / bsd / kern / kern_guarded.c
index ea583e9cf014a192c4833978152749c8ea796c52..c78c646733079f72da166751a21ef17c7df46ab1 100644 (file)
@@ -1,8 +1,8 @@
 /*
- * Copyright (c) 2015-2016 Apple Inc. All rights reserved.
+ * Copyright (c) 2018 Apple Inc. All rights reserved.
  *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
- * 
+ *
  * 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
  * 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,
@@ -22,7 +22,7 @@
  * 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_OSREFERENCE_LICENSE_HEADER_END@
  */
 
 #include <security/mac_policy.h>
 #include <pexpert/pexpert.h>
 #include <sys/sysctl.h>
+#include <sys/reason.h>
 #endif
 
 
 #define f_flag f_fglob->fg_flag
 #define f_type f_fglob->fg_ops->fo_type
 extern int dofilewrite(vfs_context_t ctx, struct fileproc *fp,
-                        user_addr_t bufp, user_size_t nbyte, off_t offset, 
-                        int flags, user_ssize_t *retval );
+    user_addr_t bufp, user_size_t nbyte, off_t offset,
+    int flags, user_ssize_t *retval );
 extern int wr_uio(struct proc *p, struct fileproc *fp, uio_t uio, user_ssize_t *retval);
 
 /*
@@ -68,7 +69,7 @@ extern int wr_uio(struct proc *p, struct fileproc *fp, uio_t uio, user_ssize_t *
  */
 
 kern_return_t task_exception_notify(exception_type_t exception,
-        mach_exception_data_type_t code, mach_exception_data_type_t subcode);
+    mach_exception_data_type_t code, mach_exception_data_type_t subcode);
 kern_return_t task_violated_guard(mach_exception_code_t, mach_exception_subcode_t, void *);
 
 /*
@@ -86,39 +87,48 @@ kern_return_t task_violated_guard(mach_exception_code_t, mach_exception_subcode_
 
 struct guarded_fileproc {
        struct fileproc gf_fileproc;
-       u_int           gf_magic;
-       u_int           gf_attrs;
-       guardid_t       gf_guard;
+       u_int           gf_magic;
+       u_int           gf_attrs;
+       guardid_t       gf_guard;
 };
 
-const size_t sizeof_guarded_fileproc = sizeof (struct guarded_fileproc);
+const size_t sizeof_guarded_fileproc = sizeof(struct guarded_fileproc);
 
-#define FP_TO_GFP(fp)  ((struct guarded_fileproc *)(fp))
-#define        GFP_TO_FP(gfp)  (&(gfp)->gf_fileproc)
+#define FP_TO_GFP(fp)   ((struct guarded_fileproc *)(fp))
+#define GFP_TO_FP(gfp)  (&(gfp)->gf_fileproc)
 
-#define GUARDED_FILEPROC_MAGIC 0x29083
+#define GUARDED_FILEPROC_MAGIC  0x29083
 
 struct gfp_crarg {
        guardid_t gca_guard;
        u_int gca_attrs;
 };
 
+#ifdef OS_REFCNT_DEBUG
+extern struct os_refgrp f_iocount_refgrp;
+#endif
+
 static struct fileproc *
 guarded_fileproc_alloc_init(void *crarg)
 {
        struct gfp_crarg *aarg = crarg;
        struct guarded_fileproc *gfp;
 
-       if ((gfp = kalloc(sizeof (*gfp))) == NULL)
-               return (NULL);
+       if ((gfp = kalloc(sizeof(*gfp))) == NULL) {
+               return NULL;
+       }
+
+       bzero(gfp, sizeof(*gfp));
+
+       struct fileproc *fp = &gfp->gf_fileproc;
+       os_ref_init(&fp->f_iocount, &f_iocount_refgrp);
+       fp->f_flags = FTYPE_GUARDED;
 
-       bzero(gfp, sizeof (*gfp));
-       gfp->gf_fileproc.f_flags = FTYPE_GUARDED;
        gfp->gf_magic = GUARDED_FILEPROC_MAGIC;
        gfp->gf_guard = aarg->gca_guard;
        gfp->gf_attrs = aarg->gca_attrs;
 
-       return (GFP_TO_FP(gfp));
+       return GFP_TO_FP(gfp);
 }
 
 void
@@ -127,10 +137,11 @@ guarded_fileproc_free(struct fileproc *fp)
        struct guarded_fileproc *gfp = FP_TO_GFP(fp);
 
        if (FILEPROC_TYPE(fp) != FTYPE_GUARDED ||
-           GUARDED_FILEPROC_MAGIC != gfp->gf_magic)
+           GUARDED_FILEPROC_MAGIC != gfp->gf_magic) {
                panic("%s: corrupt fp %p flags %x", __func__, fp, fp->f_flags);
+       }
 
-       kfree(gfp, sizeof (*gfp));
+       kfree(gfp, sizeof(*gfp));
 }
 
 static int
@@ -140,33 +151,36 @@ fp_lookup_guarded(proc_t p, int fd, guardid_t guard,
        struct fileproc *fp;
        int error;
 
-       if ((error = fp_lookup(p, fd, &fp, locked)) != 0)
-               return (error);
+       if ((error = fp_lookup(p, fd, &fp, locked)) != 0) {
+               return error;
+       }
        if (FILEPROC_TYPE(fp) != FTYPE_GUARDED) {
                (void) fp_drop(p, fd, fp, locked);
-               return (EINVAL);
+               return EINVAL;
        }
        struct guarded_fileproc *gfp = FP_TO_GFP(fp);
 
-       if (GUARDED_FILEPROC_MAGIC != gfp->gf_magic)
+       if (GUARDED_FILEPROC_MAGIC != gfp->gf_magic) {
                panic("%s: corrupt fp %p", __func__, fp);
+       }
 
        if (guard != gfp->gf_guard) {
                (void) fp_drop(p, fd, fp, locked);
-               return (EPERM); /* *not* a mismatch exception */
+               return EPERM; /* *not* a mismatch exception */
        }
-       if (gfpp)
+       if (gfpp) {
                *gfpp = gfp;
-       return (0);
+       }
+       return 0;
 }
 
 /*
  * Expected use pattern:
  *
  * if (FP_ISGUARDED(fp, GUARD_CLOSE)) {
- *     error = fp_guard_exception(p, fd, fp, kGUARD_EXC_CLOSE);
+ *      error = fp_guard_exception(p, fd, fp, kGUARD_EXC_CLOSE);
  *      proc_fdunlock(p);
- *      return (error);
+ *      return error;
  * }
  */
 
@@ -176,12 +190,13 @@ fp_isguarded(struct fileproc *fp, u_int attrs)
        if (FILEPROC_TYPE(fp) == FTYPE_GUARDED) {
                struct guarded_fileproc *gfp = FP_TO_GFP(fp);
 
-               if (GUARDED_FILEPROC_MAGIC != gfp->gf_magic)
+               if (GUARDED_FILEPROC_MAGIC != gfp->gf_magic) {
                        panic("%s: corrupt gfp %p flags %x",
                            __func__, gfp, fp->f_flags);
-               return ((attrs & gfp->gf_attrs) == attrs);
+               }
+               return (attrs & gfp->gf_attrs) == attrs;
        }
-       return (0);
+       return 0;
 }
 
 extern char *proc_name_address(void *p);
@@ -189,8 +204,9 @@ extern char *proc_name_address(void *p);
 int
 fp_guard_exception(proc_t p, int fd, struct fileproc *fp, u_int flavor)
 {
-       if (FILEPROC_TYPE(fp) != FTYPE_GUARDED)
+       if (FILEPROC_TYPE(fp) != FTYPE_GUARDED) {
                panic("%s corrupt fp %p flags %x", __func__, fp, fp->f_flags);
+       }
 
        struct guarded_fileproc *gfp = FP_TO_GFP(fp);
        /* all gfd fields protected via proc_fdlock() */
@@ -203,8 +219,8 @@ fp_guard_exception(proc_t p, int fd, struct fileproc *fp, u_int flavor)
        mach_exception_subcode_t subcode = gfp->gf_guard;
 
        thread_t t = current_thread();
-       thread_guard_violation(t, code, subcode);
-       return (EPERM);
+       thread_guard_violation(t, code, subcode, TRUE);
+       return EPERM;
 }
 
 /*
@@ -250,16 +266,18 @@ fd_guard_ast(
 int
 guarded_open_np(proc_t p, struct guarded_open_np_args *uap, int32_t *retval)
 {
-       if ((uap->flags & O_CLOEXEC) == 0)
-               return (EINVAL);
+       if ((uap->flags & O_CLOEXEC) == 0) {
+               return EINVAL;
+       }
 
 #define GUARD_REQUIRED (GUARD_DUP)
-#define GUARD_ALL      (GUARD_REQUIRED |       \
-                       (GUARD_CLOSE | GUARD_SOCKET_IPC | GUARD_FILEPORT | GUARD_WRITE))
+#define GUARD_ALL      (GUARD_REQUIRED |        \
+                       (GUARD_CLOSE | GUARD_SOCKET_IPC | GUARD_FILEPORT | GUARD_WRITE))
 
        if (((uap->guardflags & GUARD_REQUIRED) != GUARD_REQUIRED) ||
-           ((uap->guardflags & ~GUARD_ALL) != 0))
-               return (EINVAL);
+           ((uap->guardflags & ~GUARD_ALL) != 0)) {
+               return EINVAL;
+       }
 
        int error;
        struct gfp_crarg crarg = {
@@ -267,14 +285,16 @@ guarded_open_np(proc_t p, struct guarded_open_np_args *uap, int32_t *retval)
        };
 
        if ((error = copyin(uap->guard,
-           &(crarg.gca_guard), sizeof (crarg.gca_guard))) != 0)
-               return (error);
+           &(crarg.gca_guard), sizeof(crarg.gca_guard))) != 0) {
+               return error;
+       }
 
        /*
         * Disallow certain guard values -- is zero enough?
         */
-       if (crarg.gca_guard == 0)
-               return (EINVAL);
+       if (crarg.gca_guard == 0) {
+               return EINVAL;
+       }
 
        struct filedesc *fdp = p->p_fd;
        struct vnode_attr va;
@@ -287,10 +307,10 @@ guarded_open_np(proc_t p, struct guarded_open_np_args *uap, int32_t *retval)
        VATTR_SET(&va, va_mode, cmode & ACCESSPERMS);
 
        NDINIT(&nd, LOOKUP, OP_OPEN, FOLLOW | AUDITVNPATH1, UIO_USERSPACE,
-              uap->path, ctx);
+           uap->path, ctx);
 
-       return (open1(ctx, &nd, uap->flags | O_CLOFORK, &va,
-           guarded_fileproc_alloc_init, &crarg, retval));
+       return open1(ctx, &nd, uap->flags | O_CLOFORK, &va,
+                  guarded_fileproc_alloc_init, &crarg, retval);
 }
 
 /*
@@ -304,12 +324,14 @@ guarded_open_np(proc_t p, struct guarded_open_np_args *uap, int32_t *retval)
 int
 guarded_open_dprotected_np(proc_t p, struct guarded_open_dprotected_np_args *uap, int32_t *retval)
 {
-       if ((uap->flags & O_CLOEXEC) == 0)
-               return (EINVAL);
+       if ((uap->flags & O_CLOEXEC) == 0) {
+               return EINVAL;
+       }
 
        if (((uap->guardflags & GUARD_REQUIRED) != GUARD_REQUIRED) ||
-           ((uap->guardflags & ~GUARD_ALL) != 0))
-               return (EINVAL);
+           ((uap->guardflags & ~GUARD_ALL) != 0)) {
+               return EINVAL;
+       }
 
        int error;
        struct gfp_crarg crarg = {
@@ -317,14 +339,16 @@ guarded_open_dprotected_np(proc_t p, struct guarded_open_dprotected_np_args *uap
        };
 
        if ((error = copyin(uap->guard,
-           &(crarg.gca_guard), sizeof (crarg.gca_guard))) != 0)
-               return (error);
+           &(crarg.gca_guard), sizeof(crarg.gca_guard))) != 0) {
+               return error;
+       }
 
        /*
         * Disallow certain guard values -- is zero enough?
         */
-       if (crarg.gca_guard == 0)
-               return (EINVAL);
+       if (crarg.gca_guard == 0) {
+               return EINVAL;
+       }
 
        struct filedesc *fdp = p->p_fd;
        struct vnode_attr va;
@@ -337,33 +361,33 @@ guarded_open_dprotected_np(proc_t p, struct guarded_open_dprotected_np_args *uap
        VATTR_SET(&va, va_mode, cmode & ACCESSPERMS);
 
        NDINIT(&nd, LOOKUP, OP_OPEN, FOLLOW | AUDITVNPATH1, UIO_USERSPACE,
-              uap->path, ctx);
+           uap->path, ctx);
 
-       /* 
-        * Initialize the extra fields in vnode_attr to pass down dataprotection 
+       /*
+        * Initialize the extra fields in vnode_attr to pass down dataprotection
         * extra fields.
         * 1. target cprotect class.
-        * 2. set a flag to mark it as requiring open-raw-encrypted semantics. 
-        */ 
-       if (uap->flags & O_CREAT) {     
+        * 2. set a flag to mark it as requiring open-raw-encrypted semantics.
+        */
+       if (uap->flags & O_CREAT) {
                VATTR_SET(&va, va_dataprotect_class, uap->dpclass);
        }
-       
-       if (uap->dpflags & (O_DP_GETRAWENCRYPTED|O_DP_GETRAWUNENCRYPTED)) {
-               if ( uap->flags & (O_RDWR | O_WRONLY)) {
+
+       if (uap->dpflags & (O_DP_GETRAWENCRYPTED | O_DP_GETRAWUNENCRYPTED)) {
+               if (uap->flags & (O_RDWR | O_WRONLY)) {
                        /* Not allowed to write raw encrypted bytes */
-                       return EINVAL;          
-               }                       
+                       return EINVAL;
+               }
                if (uap->dpflags & O_DP_GETRAWENCRYPTED) {
-                   VATTR_SET(&va, va_dataprotect_flags, VA_DP_RAWENCRYPTED);
+                       VATTR_SET(&va, va_dataprotect_flags, VA_DP_RAWENCRYPTED);
                }
                if (uap->dpflags & O_DP_GETRAWUNENCRYPTED) {
-                   VATTR_SET(&va, va_dataprotect_flags, VA_DP_RAWUNENCRYPTED);
+                       VATTR_SET(&va, va_dataprotect_flags, VA_DP_RAWUNENCRYPTED);
                }
        }
 
-       return (open1(ctx, &nd, uap->flags | O_CLOFORK, &va,
-           guarded_fileproc_alloc_init, &crarg, retval));
+       return open1(ctx, &nd, uap->flags | O_CLOFORK, &va,
+                  guarded_fileproc_alloc_init, &crarg, retval);
 }
 
 /*
@@ -379,8 +403,9 @@ int
 guarded_kqueue_np(proc_t p, struct guarded_kqueue_np_args *uap, int32_t *retval)
 {
        if (((uap->guardflags & GUARD_REQUIRED) != GUARD_REQUIRED) ||
-           ((uap->guardflags & ~GUARD_ALL) != 0))
-               return (EINVAL);
+           ((uap->guardflags & ~GUARD_ALL) != 0)) {
+               return EINVAL;
+       }
 
        int error;
        struct gfp_crarg crarg = {
@@ -388,13 +413,15 @@ guarded_kqueue_np(proc_t p, struct guarded_kqueue_np_args *uap, int32_t *retval)
        };
 
        if ((error = copyin(uap->guard,
-           &(crarg.gca_guard), sizeof (crarg.gca_guard))) != 0)
-               return (error);
+           &(crarg.gca_guard), sizeof(crarg.gca_guard))) != 0) {
+               return error;
+       }
 
-       if (crarg.gca_guard == 0)
-               return (EINVAL);
+       if (crarg.gca_guard == 0) {
+               return EINVAL;
+       }
 
-       return (kqueue_body(p, guarded_fileproc_alloc_init, &crarg, retval));
+       return kqueue_internal(p, guarded_fileproc_alloc_init, &crarg, retval);
 }
 
 /*
@@ -411,17 +438,18 @@ guarded_close_np(proc_t p, struct guarded_close_np_args *uap,
 
        AUDIT_SYSCLOSE(p, fd);
 
-       if ((error = copyin(uap->guard, &uguard, sizeof (uguard))) != 0)
-               return (error);
+       if ((error = copyin(uap->guard, &uguard, sizeof(uguard))) != 0) {
+               return error;
+       }
 
        proc_fdlock(p);
        if ((error = fp_lookup_guarded(p, fd, uguard, &gfp, 1)) != 0) {
                proc_fdunlock(p);
-               return (error);
+               return error;
        }
        error = close_internal_locked(p, fd, GFP_TO_FP(gfp), 0);
        proc_fdunlock(p);
-       return (error);
+       return error;
 }
 
 /*
@@ -450,7 +478,7 @@ guarded_close_np(proc_t p, struct guarded_close_np_args *uap,
  * If 'nguard' is NULL, fd must be guarded at entry, <guard, guardflags>
  * must match with what's already guarding the descriptor, and the
  * result will be to completely remove the guard.  Note also that the
- * fdflags are copied to the descriptor from the incoming *fdflagsp argument. 
+ * fdflags are copied to the descriptor from the incoming *fdflagsp argument.
  *
  * If the descriptor is guarded, and neither 'guard' nor 'nguard' is NULL
  * and <guard, guardflags> matches what's already guarding the descriptor,
@@ -493,30 +521,30 @@ change_fdguard_np(proc_t p, struct change_fdguard_np_args *uap,
        int nfdflags = 0;
 
        if (0 != uap->guard &&
-           0 != (error = copyin(uap->guard, &oldg, sizeof (oldg))))
-               return (error); /* can't copyin current guard */
-
+           0 != (error = copyin(uap->guard, &oldg, sizeof(oldg)))) {
+               return error; /* can't copyin current guard */
+       }
        if (0 != uap->nguard &&
-           0 != (error = copyin(uap->nguard, &newg, sizeof (newg))))
-               return (error); /* can't copyin new guard */
-
+           0 != (error = copyin(uap->nguard, &newg, sizeof(newg)))) {
+               return error; /* can't copyin new guard */
+       }
        if (0 != uap->fdflagsp &&
-           0 != (error = copyin(uap->fdflagsp, &nfdflags, sizeof (nfdflags))))
-               return (error); /* can't copyin new fdflags */
-           
+           0 != (error = copyin(uap->fdflagsp, &nfdflags, sizeof(nfdflags)))) {
+               return error; /* can't copyin new fdflags */
+       }
        proc_fdlock(p);
 restart:
        if ((error = fp_lookup(p, fd, &fp, 1)) != 0) {
                proc_fdunlock(p);
-               return (error);
+               return error;
        }
 
        if (0 != uap->fdflagsp) {
                int ofdflags = FDFLAGS_GET(p, fd);
                int ofl = ((ofdflags & UF_EXCLOSE) ? FD_CLOEXEC : 0) |
-                       ((ofdflags & UF_FORKCLOSE) ? FD_CLOFORK : 0);
+                   ((ofdflags & UF_FORKCLOSE) ? FD_CLOFORK : 0);
                proc_fdunlock(p);
-               if (0 != (error = copyout(&ofl, uap->fdflagsp, sizeof (ofl)))) {
+               if (0 != (error = copyout(&ofl, uap->fdflagsp, sizeof(ofl)))) {
                        proc_fdlock(p);
                        goto dropout; /* can't copyout old fdflags */
                }
@@ -524,29 +552,34 @@ restart:
        }
 
        if (FILEPROC_TYPE(fp) == FTYPE_GUARDED) {
-               if (0 == uap->guard || 0 == uap->guardflags)
+               if (0 == uap->guard || 0 == uap->guardflags) {
                        error = EINVAL; /* missing guard! */
-               else if (0 == oldg)
+               } else if (0 == oldg) {
                        error = EPERM; /* guardids cannot be zero */
+               }
        } else {
-               if (0 != uap->guard || 0 != uap->guardflags)
+               if (0 != uap->guard || 0 != uap->guardflags) {
                        error = EINVAL; /* guard provided, but none needed! */
+               }
        }
 
-       if (0 != error)
+       if (0 != error) {
                goto dropout;
+       }
 
        if (0 != uap->nguard) {
                /*
                 * There's a new guard in town.
                 */
-               if (0 == newg)
+               if (0 == newg) {
                        error = EINVAL; /* guards cannot contain zero */
-               else if (((uap->nguardflags & GUARD_REQUIRED) != GUARD_REQUIRED) ||
-                   ((uap->nguardflags & ~GUARD_ALL) != 0))
+               else if (((uap->nguardflags & GUARD_REQUIRED) != GUARD_REQUIRED) ||
+                   ((uap->nguardflags & ~GUARD_ALL) != 0)) {
                        error = EINVAL; /* must have valid attributes too */
-               if (0 != error)
+               }
+               if (0 != error) {
                        goto dropout;
+               }
 
                if (FILEPROC_TYPE(fp) == FTYPE_GUARDED) {
                        /*
@@ -554,9 +587,10 @@ restart:
                         */
                        struct guarded_fileproc *gfp = FP_TO_GFP(fp);
 
-                       if (GUARDED_FILEPROC_MAGIC != gfp->gf_magic)
+                       if (GUARDED_FILEPROC_MAGIC != gfp->gf_magic) {
                                panic("%s: corrupt gfp %p flags %x",
-                                     __func__, gfp, fp->f_flags);
+                                   __func__, gfp, fp->f_flags);
+                       }
 
                        if (oldg == gfp->gf_guard &&
                            uap->guardflags == gfp->gf_attrs) {
@@ -566,12 +600,14 @@ restart:
                                 * fdflags "side-effects" as we go.   Note that
                                 * userland can request FD_CLOFORK semantics.
                                 */
-                               if (gfp->gf_attrs & GUARD_CLOSE)
+                               if (gfp->gf_attrs & GUARD_CLOSE) {
                                        FDFLAGS_CLR(p, fd, UF_FORKCLOSE);
+                               }
                                gfp->gf_guard = newg;
                                gfp->gf_attrs = uap->nguardflags;
-                               if (gfp->gf_attrs & GUARD_CLOSE)
+                               if (gfp->gf_attrs & GUARD_CLOSE) {
                                        FDFLAGS_SET(p, fd, UF_FORKCLOSE);
+                               }
                                FDFLAGS_SET(p, fd,
                                    (nfdflags & FD_CLOFORK) ? UF_FORKCLOSE : 0);
                                /* FG_CONFINED enforced regardless */
@@ -602,19 +638,20 @@ restart:
                                .gca_attrs = uap->nguardflags
                        };
                        struct fileproc *nfp =
-                               guarded_fileproc_alloc_init(&crarg);
+                           guarded_fileproc_alloc_init(&crarg);
                        struct guarded_fileproc *gfp;
 
                        proc_fdlock(p);
 
                        switch (error = fp_tryswap(p, fd, nfp)) {
-                       case 0: /* guarded-ness comes with side-effects */
+                       case 0: /* success; guarded-ness comes with side-effects */
+                               fp = NULL;
                                gfp = FP_TO_GFP(nfp);
-                               if (gfp->gf_attrs & GUARD_CLOSE)
+                               if (gfp->gf_attrs & GUARD_CLOSE) {
                                        FDFLAGS_SET(p, fd, UF_FORKCLOSE);
+                               }
                                FDFLAGS_SET(p, fd, UF_EXCLOSE);
                                (void) fp_drop(p, fd, nfp, 1);
-                               fileproc_free(fp);
                                break;
                        case EKEEPLOOKING: /* f_iocount indicates a collision */
                                (void) fp_drop(p, fd, fp, 1);
@@ -626,7 +663,7 @@ restart:
                                break;
                        }
                        proc_fdunlock(p);
-                       return (error);
+                       return error;
                }
        } else {
                /*
@@ -643,9 +680,10 @@ restart:
                                goto dropout;
                        }
 
-                       if (GUARDED_FILEPROC_MAGIC != gfp->gf_magic)
+                       if (GUARDED_FILEPROC_MAGIC != gfp->gf_magic) {
                                panic("%s: corrupt gfp %p flags %x",
-                                     __func__, gfp, fp->f_flags);
+                                   __func__, gfp, fp->f_flags);
+                       }
 
                        if (oldg != gfp->gf_guard ||
                            uap->guardflags != gfp->gf_attrs) {
@@ -658,7 +696,8 @@ restart:
                        proc_fdlock(p);
 
                        switch (error = fp_tryswap(p, fd, nfp)) {
-                       case 0: /* undo side-effects of guarded-ness */
+                       case 0: /* success; undo side-effects of guarded-ness */
+                               fp = NULL;
                                FDFLAGS_CLR(p, fd, UF_FORKCLOSE | UF_EXCLOSE);
                                FDFLAGS_SET(p, fd,
                                    (nfdflags & FD_CLOFORK) ? UF_FORKCLOSE : 0);
@@ -666,7 +705,6 @@ restart:
                                FDFLAGS_SET(p, fd,
                                    (nfdflags & FD_CLOEXEC) ? UF_EXCLOSE : 0);
                                (void) fp_drop(p, fd, nfp, 1);
-                               fileproc_free(fp);
                                break;
                        case EKEEPLOOKING: /* f_iocount indicates collision */
                                (void) fp_drop(p, fd, fp, 1);
@@ -678,7 +716,7 @@ restart:
                                break;
                        }
                        proc_fdunlock(p);
-                       return (error);
+                       return error;
                } else {
                        /*
                         * Not already guarded, and no new guard?
@@ -690,7 +728,7 @@ restart:
 dropout:
        (void) fp_drop(p, fd, fp, 1);
        proc_fdunlock(p);
-       return (error);
+       return error;
 }
 
 /*
@@ -702,7 +740,7 @@ dropout:
 int
 guarded_write_np(struct proc *p, struct guarded_write_np_args *uap, user_ssize_t *retval)
 {
-       int error;      
+       int error;
        int fd = uap->fd;
        guardid_t uguard;
        struct fileproc *fp;
@@ -711,30 +749,32 @@ guarded_write_np(struct proc *p, struct guarded_write_np_args *uap, user_ssize_t
 
        AUDIT_ARG(fd, fd);
 
-       if ((error = copyin(uap->guard, &uguard, sizeof (uguard))) != 0)
-               return (error);
+       if ((error = copyin(uap->guard, &uguard, sizeof(uguard))) != 0) {
+               return error;
+       }
 
        error = fp_lookup_guarded(p, fd, uguard, &gfp, 0);
-       if (error)
-               return(error);
+       if (error) {
+               return error;
+       }
 
        fp = GFP_TO_FP(gfp);
        if ((fp->f_flag & FWRITE) == 0) {
                error = EBADF;
        } else {
-
                struct vfs_context context = *(vfs_context_current());
                context.vc_ucred = fp->f_fglob->fg_cred;
 
                error = dofilewrite(&context, fp, uap->cbuf, uap->nbyte,
-                       (off_t)-1, 0, retval);
+                   (off_t)-1, 0, retval);
                wrote_some = *retval > 0;
        }
-       if (wrote_some)
-               fp_drop_written(p, fd, fp);
-       else
-               fp_drop(p, fd, fp, 0);
-       return(error);
+       if (wrote_some) {
+               fp_drop_written(p, fd, fp);
+       } else {
+               fp_drop(p, fd, fp, 0);
+       }
+       return error;
 }
 
 /*
@@ -743,11 +783,11 @@ guarded_write_np(struct proc *p, struct guarded_write_np_args *uap, user_ssize_t
  *
  * Initial implementation of guarded pwrites.
  */
- int
- guarded_pwrite_np(struct proc *p, struct guarded_pwrite_np_args *uap, user_ssize_t *retval)
- {
+int
+guarded_pwrite_np(struct proc *p, struct guarded_pwrite_np_args *uap, user_ssize_t *retval)
+{
        struct fileproc *fp;
-       int error; 
+       int error;
        int fd = uap->fd;
        vnode_t vp  = (vnode_t)0;
        guardid_t uguard;
@@ -756,12 +796,14 @@ guarded_write_np(struct proc *p, struct guarded_write_np_args *uap, user_ssize_t
 
        AUDIT_ARG(fd, fd);
 
-       if ((error = copyin(uap->guard, &uguard, sizeof (uguard))) != 0)
-               return (error);
+       if ((error = copyin(uap->guard, &uguard, sizeof(uguard))) != 0) {
+               return error;
+       }
 
        error = fp_lookup_guarded(p, fd, uguard, &gfp, 0);
-       if (error)
-               return(error);
+       if (error) {
+               return error;
+       }
 
        fp = GFP_TO_FP(gfp);
        if ((fp->f_flag & FWRITE) == 0) {
@@ -778,7 +820,7 @@ guarded_write_np(struct proc *p, struct guarded_write_np_args *uap, user_ssize_t
                if (vnode_isfifo(vp)) {
                        error = ESPIPE;
                        goto errout;
-               } 
+               }
                if ((vp->v_flag & VISTTY)) {
                        error = ENXIO;
                        goto errout;
@@ -789,19 +831,20 @@ guarded_write_np(struct proc *p, struct guarded_write_np_args *uap, user_ssize_t
                }
 
                error = dofilewrite(&context, fp, uap->buf, uap->nbyte,
-                       uap->offset, FOF_OFFSET, retval);
+                   uap->offset, FOF_OFFSET, retval);
                wrote_some = *retval > 0;
        }
 errout:
-       if (wrote_some)
-               fp_drop_written(p, fd, fp);
-       else
-               fp_drop(p, fd, fp, 0);
+       if (wrote_some) {
+               fp_drop_written(p, fd, fp);
+       } else {
+               fp_drop(p, fd, fp, 0);
+       }
 
        KERNEL_DEBUG_CONSTANT((BSDDBG_CODE(DBG_BSD_SC_EXTENDED_INFO, SYS_guarded_pwrite_np) | DBG_FUNC_NONE),
-             uap->fd, uap->nbyte, (unsigned int)((uap->offset >> 32)), (unsigned int)(uap->offset), 0);
-       
-        return(error);
+           uap->fd, uap->nbyte, (unsigned int)((uap->offset >> 32)), (unsigned int)(uap->offset), 0);
+
+       return error;
 }
 
 /*
@@ -825,14 +868,15 @@ guarded_writev_np(struct proc *p, struct guarded_writev_np_args *uap, user_ssize
        AUDIT_ARG(fd, uap->fd);
 
        /* Verify range bedfore calling uio_create() */
-       if (uap->iovcnt <= 0 || uap->iovcnt > UIO_MAXIOV)
-               return (EINVAL);
+       if (uap->iovcnt <= 0 || uap->iovcnt > UIO_MAXIOV) {
+               return EINVAL;
+       }
 
        /* allocate a uio large enough to hold the number of iovecs passed */
        auio = uio_create(uap->iovcnt, 0,
-                                 (IS_64BIT_PROCESS(p) ? UIO_USERSPACE64 : UIO_USERSPACE32),
-                                 UIO_WRITE);
-                                 
+           (IS_64BIT_PROCESS(p) ? UIO_USERSPACE64 : UIO_USERSPACE32),
+           UIO_WRITE);
+
        /* get location of iovecs within the uio.  then copyin the iovecs from
         * user space.
         */
@@ -842,25 +886,27 @@ guarded_writev_np(struct proc *p, struct guarded_writev_np_args *uap, user_ssize
                goto ExitThisRoutine;
        }
        error = copyin_user_iovec_array(uap->iovp,
-               IS_64BIT_PROCESS(p) ? UIO_USERSPACE64 : UIO_USERSPACE32,
-               uap->iovcnt, iovp);
+           IS_64BIT_PROCESS(p) ? UIO_USERSPACE64 : UIO_USERSPACE32,
+           uap->iovcnt, iovp);
        if (error) {
                goto ExitThisRoutine;
        }
-       
-       /* finalize uio_t for use and do the IO 
+
+       /* finalize uio_t for use and do the IO
         */
        error = uio_calculateresid(auio);
        if (error) {
                goto ExitThisRoutine;
        }
 
-       if ((error = copyin(uap->guard, &uguard, sizeof (uguard))) != 0)
+       if ((error = copyin(uap->guard, &uguard, sizeof(uguard))) != 0) {
                goto ExitThisRoutine;
+       }
 
        error = fp_lookup_guarded(p, uap->fd, uguard, &gfp, 0);
-       if (error)
+       if (error) {
                goto ExitThisRoutine;
+       }
 
        fp = GFP_TO_FP(gfp);
        if ((fp->f_flag & FWRITE) == 0) {
@@ -869,16 +915,17 @@ guarded_writev_np(struct proc *p, struct guarded_writev_np_args *uap, user_ssize
                error = wr_uio(p, fp, auio, retval);
                wrote_some = *retval > 0;
        }
-       
-       if (wrote_some)
-               fp_drop_written(p, uap->fd, fp);
-       else
-               fp_drop(p, uap->fd, fp, 0);
+
+       if (wrote_some) {
+               fp_drop_written(p, uap->fd, fp);
+       } else {
+               fp_drop(p, uap->fd, fp, 0);
+       }
 ExitThisRoutine:
        if (auio != NULL) {
                uio_free(auio);
        }
-       return (error);
+       return error;
 }
 
 /*
@@ -895,15 +942,16 @@ falloc_guarded(struct proc *p, struct fileproc **fp, int *fd,
        struct gfp_crarg crarg;
 
        if (((attrs & GUARD_REQUIRED) != GUARD_REQUIRED) ||
-           ((attrs & ~GUARD_ALL) != 0) || (*guard == 0))
-               return (EINVAL);
+           ((attrs & ~GUARD_ALL) != 0) || (*guard == 0)) {
+               return EINVAL;
+       }
 
-       bzero(&crarg, sizeof (crarg));
+       bzero(&crarg, sizeof(crarg));
        crarg.gca_guard = *guard;
        crarg.gca_attrs = attrs;
 
-       return (falloc_withalloc(p, fp, fd, ctx, guarded_fileproc_alloc_init,
-           &crarg));
+       return falloc_withalloc(p, fp, fd, ctx, guarded_fileproc_alloc_init,
+                  &crarg);
 }
 
 #if CONFIG_MACF && CONFIG_VNGUARD
@@ -950,7 +998,7 @@ struct vng_owner { /* lives on the fileglob label */
 static struct vng_info *
 new_vgi(unsigned attrs, guardid_t guard)
 {
-       struct vng_info *vgi = kalloc(sizeof (*vgi));
+       struct vng_info *vgi = kalloc(sizeof(*vgi));
        vgi->vgi_guard = guard;
        vgi->vgi_attrs = attrs;
        TAILQ_INIT(&vgi->vgi_owners);
@@ -960,8 +1008,8 @@ new_vgi(unsigned attrs, guardid_t guard)
 static struct vng_owner *
 new_vgo(proc_t p, struct fileglob *fg)
 {
-       struct vng_owner *vgo = kalloc(sizeof (*vgo));
-       memset(vgo, 0, sizeof (*vgo));
+       struct vng_owner *vgo = kalloc(sizeof(*vgo));
+       memset(vgo, 0, sizeof(*vgo));
        vgo->vgo_p = p;
        vgo->vgo_fg = fg;
        return vgo;
@@ -987,18 +1035,18 @@ free_vgi(struct vng_info *vgi)
 {
        assert(TAILQ_EMPTY(&vgi->vgi_owners));
 #if DEVELOP || DEBUG
-       memset(vgi, 0xbeadfade, sizeof (*vgi));
+       memset(vgi, 0xbeadfade, sizeof(*vgi));
 #endif
-       kfree(vgi, sizeof (*vgi));
+       kfree(vgi, sizeof(*vgi));
 }
 
 static void
 free_vgo(struct vng_owner *vgo)
 {
 #if DEVELOP || DEBUG
-       memset(vgo, 0x2bedf1d0, sizeof (*vgo));
+       memset(vgo, 0x2bedf1d0, sizeof(*vgo));
 #endif
-       kfree(vgo, sizeof (*vgo));
+       kfree(vgo, sizeof(*vgo));
 }
 
 static int label_slot;
@@ -1010,10 +1058,11 @@ vng_lbl_get(struct label *label)
 {
        lck_rw_assert(&llock, LCK_RW_ASSERT_HELD);
        void *data;
-       if (NULL == label)
+       if (NULL == label) {
                data = NULL;
-       else
+       } else {
                data = (void *)mac_label_get(label, label_slot);
+       }
        return data;
 }
 
@@ -1022,8 +1071,9 @@ vng_lbl_get_withattr(struct label *label, unsigned attrmask)
 {
        struct vng_info *vgi = vng_lbl_get(label);
        assert(NULL == vgi || (vgi->vgi_attrs & ~VNG_ALL) == 0);
-       if (NULL != vgi && 0 == (vgi->vgi_attrs & attrmask))
+       if (NULL != vgi && 0 == (vgi->vgi_attrs & attrmask)) {
                vgi = NULL;
+       }
        return vgi;
 }
 
@@ -1035,25 +1085,80 @@ vng_lbl_set(struct label *label, void *data)
        mac_label_set(label, label_slot, (intptr_t)data);
 }
 
+static int
+vnguard_sysc_getguardattr(proc_t p, struct vnguard_getattr *vga)
+{
+       const int fd = vga->vga_fd;
+
+       if (0 == vga->vga_guard) {
+               return EINVAL;
+       }
+
+       int error;
+       struct fileproc *fp;
+       if (0 != (error = fp_lookup(p, fd, &fp, 0))) {
+               return error;
+       }
+       do {
+               struct fileglob *fg = fp->f_fglob;
+               if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE) {
+                       error = EBADF;
+                       break;
+               }
+               struct vnode *vp = fg->fg_data;
+               if (!vnode_isreg(vp) || NULL == vp->v_mount) {
+                       error = EBADF;
+                       break;
+               }
+               error = vnode_getwithref(vp);
+               if (0 != error) {
+                       break;
+               }
+
+               vga->vga_attrs = 0;
+
+               lck_rw_lock_shared(&llock);
+
+               if (NULL != vp->v_label) {
+                       const struct vng_info *vgi = vng_lbl_get(vp->v_label);
+                       if (NULL != vgi) {
+                               if (vgi->vgi_guard != vga->vga_guard) {
+                                       error = EPERM;
+                               } else {
+                                       vga->vga_attrs = vgi->vgi_attrs;
+                               }
+                       }
+               }
+
+               lck_rw_unlock_shared(&llock);
+               vnode_put(vp);
+       } while (0);
+
+       fp_drop(p, fd, fp, 0);
+       return error;
+}
+
 static int
 vnguard_sysc_setguard(proc_t p, const struct vnguard_set *vns)
 {
        const int fd = vns->vns_fd;
 
        if ((vns->vns_attrs & ~VNG_ALL) != 0 ||
-           0 == vns->vns_attrs || 0 == vns->vns_guard)
+           0 == vns->vns_attrs || 0 == vns->vns_guard) {
                return EINVAL;
+       }
 
        int error;
        struct fileproc *fp;
-       if (0 != (error = fp_lookup(p, fd, &fp, 0)))
+       if (0 != (error = fp_lookup(p, fd, &fp, 0))) {
                return error;
+       }
        do {
                /*
                 * To avoid trivial DoS, insist that the caller
                 * has read/write access to the file.
                 */
-               if ((FREAD|FWRITE) != (fp->f_flag & (FREAD|FWRITE))) {
+               if ((FREAD | FWRITE) != (fp->f_flag & (FREAD | FWRITE))) {
                        error = EBADF;
                        break;
                }
@@ -1078,9 +1183,9 @@ vnguard_sysc_setguard(proc_t p, const struct vnguard_set *vns)
                }
                error = vnode_getwithref(vp);
                if (0 != error) {
-                       fp_drop(p, fd, fp, 0);
                        break;
                }
+
                /* Ensure the target vnode -has- a label */
                struct vfs_context *ctx = vfs_context_current();
                mac_vnode_label_update(ctx, vp, NULL);
@@ -1100,9 +1205,10 @@ vnguard_sysc_setguard(proc_t p, const struct vnguard_set *vns)
 
                        if (NULL == vgi) {
                                /* vnode unguarded, add the first guard */
-                               if (NULL != vgo)
+                               if (NULL != vgo) {
                                        panic("vnguard label on fileglob "
-                                             "but not vnode");
+                                           "but not vnode");
+                               }
                                /* add a kusecount so we can unlabel later */
                                error = vnode_ref_ext(vp, O_EVTONLY, 0);
                                if (0 == error) {
@@ -1117,10 +1223,20 @@ vnguard_sysc_setguard(proc_t p, const struct vnguard_set *vns)
                        } else {
                                /* vnode already guarded */
                                free_vgi(nvgi);
-                               if (vgi->vgi_guard != vns->vns_guard)
+                               if (vgi->vgi_guard != vns->vns_guard) {
                                        error = EPERM; /* guard mismatch */
-                               else if (vgi->vgi_attrs != vns->vns_attrs)
-                                       error = EACCES; /* attr mismatch */
+                               } else if (vgi->vgi_attrs != vns->vns_attrs) {
+                                       /*
+                                        * Temporary workaround for older versions of SQLite:
+                                        * allow newer guard attributes to be silently cleared.
+                                        */
+                                       const unsigned mask = ~(VNG_WRITE_OTHER | VNG_TRUNC_OTHER);
+                                       if ((vgi->vgi_attrs & mask) == (vns->vns_attrs & mask)) {
+                                               vgi->vgi_attrs &= vns->vns_attrs;
+                                       } else {
+                                               error = EACCES; /* attr mismatch */
+                                       }
+                               }
                                if (0 != error || NULL != vgo) {
                                        free_vgo(nvgo);
                                        break;
@@ -1146,21 +1262,36 @@ vng_policy_syscall(proc_t p, int cmd, user_addr_t arg)
 
        switch (cmd) {
        case VNG_SYSC_PING:
-               if (0 == arg)
+               if (0 == arg) {
                        error = 0;
+               }
                break;
        case VNG_SYSC_SET_GUARD: {
                struct vnguard_set vns;
-               error = copyin(arg, (void *)&vns, sizeof (vns));
-               if (error)
+               error = copyin(arg, (void *)&vns, sizeof(vns));
+               if (error) {
                        break;
+               }
                error = vnguard_sysc_setguard(p, &vns);
                break;
        }
+       case VNG_SYSC_GET_ATTR: {
+               struct vnguard_getattr vga;
+               error = copyin(arg, (void *)&vga, sizeof(vga));
+               if (error) {
+                       break;
+               }
+               error = vnguard_sysc_getguardattr(p, &vga);
+               if (error) {
+                       break;
+               }
+               error = copyout((void *)&vga, arg, sizeof(vga));
+               break;
+       }
        default:
                break;
        }
-       return (error);
+       return error;
 }
 
 /*
@@ -1202,11 +1333,45 @@ vng_file_label_destroy(struct label *label)
        lck_rw_unlock_exclusive(&llock);
 }
 
+static os_reason_t
+vng_reason_from_pathname(const char *path, uint32_t pathlen)
+{
+       os_reason_t r = os_reason_create(OS_REASON_GUARD, GUARD_REASON_VNODE);
+       if (NULL == r) {
+               return r;
+       }
+       /*
+        * If the pathname is very long, just keep the trailing part
+        */
+       const uint32_t pathmax = 3 * EXIT_REASON_USER_DESC_MAX_LEN / 4;
+       if (pathlen > pathmax) {
+               path += (pathlen - pathmax);
+               pathlen = pathmax;
+       }
+       uint32_t rsize = kcdata_estimate_required_buffer_size(1, pathlen);
+       if (0 == os_reason_alloc_buffer(r, rsize)) {
+               struct kcdata_descriptor *kcd = &r->osr_kcd_descriptor;
+               mach_vm_address_t addr;
+               if (kcdata_get_memory_addr(kcd,
+                   EXIT_REASON_USER_DESC, pathlen, &addr) == KERN_SUCCESS) {
+                       kcdata_memcpy(kcd, addr, path, pathlen);
+                       return r;
+               }
+       }
+       os_reason_free(r);
+       return OS_REASON_NULL;
+}
+
 static int vng_policy_flags;
 
+/*
+ * Note: if an EXC_GUARD is generated, llock will be dropped and
+ * subsequently reacquired by this routine. Data derived from
+ * any label in the caller should be regenerated.
+ */
 static int
 vng_guard_violation(const struct vng_info *vgi,
-    unsigned opval, const char *nm)
+    unsigned opval, vnode_t vp)
 {
        int retval = 0;
 
@@ -1215,7 +1380,7 @@ vng_guard_violation(const struct vng_info *vgi,
                retval = EPERM;
        }
 
-       if (vng_policy_flags & kVNG_POLICY_LOGMSG) {
+       if (vng_policy_flags & (kVNG_POLICY_LOGMSG | kVNG_POLICY_UPRINTMSG)) {
                /* log a message */
                const char *op;
                switch (opval) {
@@ -1244,19 +1409,37 @@ vng_guard_violation(const struct vng_info *vgi,
                        op = "(unknown)";
                        break;
                }
+
+               const char *nm = vnode_getname(vp);
                proc_t p = current_proc();
                const struct vng_owner *vgo;
                TAILQ_FOREACH(vgo, &vgi->vgi_owners, vgo_link) {
-                       printf("%s[%d]: %s%s: '%s' guarded by %s[%d] (0x%llx)\n",
-                           proc_name_address(p), proc_pid(p), op,
-                           0 != retval ? " denied" : "",
-                           NULL != nm ? nm : "(unknown)",
-                           proc_name_address(vgo->vgo_p), proc_pid(vgo->vgo_p),
-                           vgi->vgi_guard);
+                       const char fmt[] =
+                           "%s[%d]: %s%s: '%s' guarded by %s[%d] (0x%llx)\n";
+
+                       if (vng_policy_flags & kVNG_POLICY_LOGMSG) {
+                               printf(fmt,
+                                   proc_name_address(p), proc_pid(p), op,
+                                   0 != retval ? " denied" : "",
+                                   NULL != nm ? nm : "(unknown)",
+                                   proc_name_address(vgo->vgo_p),
+                                   proc_pid(vgo->vgo_p), vgi->vgi_guard);
+                       }
+                       if (vng_policy_flags & kVNG_POLICY_UPRINTMSG) {
+                               uprintf(fmt,
+                                   proc_name_address(p), proc_pid(p), op,
+                                   0 != retval ? " denied" : "",
+                                   NULL != nm ? nm : "(unknown)",
+                                   proc_name_address(vgo->vgo_p),
+                                   proc_pid(vgo->vgo_p), vgi->vgi_guard);
+                       }
+               }
+               if (NULL != nm) {
+                       vnode_putname(nm);
                }
        }
 
-       if (vng_policy_flags & (kVNG_POLICY_EXC|kVNG_POLICY_EXC_CORPSE)) {
+       if (vng_policy_flags & (kVNG_POLICY_EXC | kVNG_POLICY_EXC_CORPSE)) {
                /* EXC_GUARD exception */
                const struct vng_owner *vgo = TAILQ_FIRST(&vgi->vgi_owners);
                pid_t pid = vgo ? proc_pid(vgo->vgo_p) : 0;
@@ -1269,13 +1452,32 @@ vng_guard_violation(const struct vng_info *vgi,
                EXC_GUARD_ENCODE_TARGET(code, pid);
                subcode = vgi->vgi_guard;
 
+               lck_rw_unlock_shared(&llock);
+
                if (vng_policy_flags & kVNG_POLICY_EXC_CORPSE) {
-                       task_violated_guard(code, subcode, NULL);
-                       /* not fatal */
+                       char *path;
+                       int len = MAXPATHLEN;
+                       MALLOC(path, char *, len, M_TEMP, M_WAITOK);
+                       os_reason_t r = NULL;
+                       if (NULL != path) {
+                               vn_getpath(vp, path, &len);
+                               if (*path && len) {
+                                       r = vng_reason_from_pathname(path, len);
+                               }
+                       }
+                       task_violated_guard(code, subcode, r); /* not fatal */
+                       if (NULL != r) {
+                               os_reason_free(r);
+                       }
+                       if (NULL != path) {
+                               FREE(path, M_TEMP);
+                       }
                } else {
                        thread_t t = current_thread();
-                       thread_guard_violation(t, code, subcode);
+                       thread_guard_violation(t, code, subcode, TRUE);
                }
+
+               lck_rw_lock_shared(&llock);
        } else if (vng_policy_flags & kVNG_POLICY_SIGKILL) {
                proc_t p = current_proc();
                psignal(p, SIGKILL);
@@ -1285,7 +1487,7 @@ vng_guard_violation(const struct vng_info *vgi,
 }
 
 /*
- * A vnode guard was tripped on this thread.
+ * A fatal vnode guard was tripped on this thread.
  *
  * (Invoked before returning to userland from the syscall handler.)
  */
@@ -1305,25 +1507,26 @@ vn_guard_ast(thread_t __unused t,
 static int
 vng_vnode_check_rename(kauth_cred_t __unused cred,
     struct vnode *__unused dvp, struct label *__unused dlabel,
-    struct vnode *__unused vp, struct label *label,
-    struct componentname *cnp,
+    struct vnode *vp, struct label *label,
+    struct componentname *__unused cnp,
     struct vnode *__unused tdvp, struct label *__unused tdlabel,
-    struct vnode *__unused tvp, struct label *tlabel,
-    struct componentname *tcnp)
+    struct vnode *tvp, struct label *tlabel,
+    struct componentname *__unused tcnp)
 {
        int error = 0;
        if (NULL != label || NULL != tlabel) {
                lck_rw_lock_shared(&llock);
                const struct vng_info *vgi =
                    vng_lbl_get_withattr(label, VNG_RENAME_FROM);
-               if (NULL != vgi)
-                       error = vng_guard_violation(vgi,
-                           VNG_RENAME_FROM, cnp->cn_nameptr);
+               if (NULL != vgi) {
+                       error = vng_guard_violation(vgi, VNG_RENAME_FROM, vp);
+               }
                if (0 == error) {
                        vgi = vng_lbl_get_withattr(tlabel, VNG_RENAME_TO);
-                       if (NULL != vgi)
+                       if (NULL != vgi) {
                                error = vng_guard_violation(vgi,
-                                   VNG_RENAME_TO, tcnp->cn_nameptr);
+                                   VNG_RENAME_TO, tvp);
+                       }
                }
                lck_rw_unlock_shared(&llock);
        }
@@ -1339,12 +1542,9 @@ vng_vnode_check_link(kauth_cred_t __unused cred,
        if (NULL != label) {
                lck_rw_lock_shared(&llock);
                const struct vng_info *vgi =
-                       vng_lbl_get_withattr(label, VNG_LINK);
+                   vng_lbl_get_withattr(label, VNG_LINK);
                if (vgi) {
-                       const char *nm = vnode_getname(vp);
-                       error = vng_guard_violation(vgi, VNG_LINK, nm);
-                       if (nm)
-                               vnode_putname(nm);
+                       error = vng_guard_violation(vgi, VNG_LINK, vp);
                }
                lck_rw_unlock_shared(&llock);
        }
@@ -1354,16 +1554,16 @@ vng_vnode_check_link(kauth_cred_t __unused cred,
 static int
 vng_vnode_check_unlink(kauth_cred_t __unused cred,
     struct vnode *__unused dvp, struct label *__unused dlabel,
-    struct vnode *__unused vp, struct label *label, struct componentname *cnp)
+    struct vnode *vp, struct label *label, struct componentname *__unused cnp)
 {
        int error = 0;
        if (NULL != label) {
                lck_rw_lock_shared(&llock);
                const struct vng_info *vgi =
                    vng_lbl_get_withattr(label, VNG_UNLINK);
-               if (vgi)
-                       error = vng_guard_violation(vgi, VNG_UNLINK,
-                           cnp->cn_nameptr);
+               if (vgi) {
+                       error = vng_guard_violation(vgi, VNG_UNLINK, vp);
+               }
                lck_rw_unlock_shared(&llock);
        }
        return error;
@@ -1385,16 +1585,13 @@ vng_vnode_check_write(kauth_cred_t __unused actv_cred,
                        proc_t p = current_proc();
                        const struct vng_owner *vgo;
                        TAILQ_FOREACH(vgo, &vgi->vgi_owners, vgo_link) {
-                               if (vgo->vgo_p == p)
+                               if (vgo->vgo_p == p) {
                                        goto done;
+                               }
                        }
-                       const char *nm = vnode_getname(vp);
-                       error = vng_guard_violation(vgi,
-                           VNG_WRITE_OTHER, nm);
-                       if (nm)
-                               vnode_putname(nm);
+                       error = vng_guard_violation(vgi, VNG_WRITE_OTHER, vp);
                }
-       done:
+done:
                lck_rw_unlock_shared(&llock);
        }
        return error;
@@ -1417,16 +1614,13 @@ vng_vnode_check_truncate(kauth_cred_t __unused actv_cred,
                        proc_t p = current_proc();
                        const struct vng_owner *vgo;
                        TAILQ_FOREACH(vgo, &vgi->vgi_owners, vgo_link) {
-                               if (vgo->vgo_p == p)
+                               if (vgo->vgo_p == p) {
                                        goto done;
+                               }
                        }
-                       const char *nm = vnode_getname(vp);
-                       error = vng_guard_violation(vgi,
-                           VNG_TRUNC_OTHER, nm);
-                       if (nm)
-                               vnode_putname(nm);
+                       error = vng_guard_violation(vgi, VNG_TRUNC_OTHER, vp);
                }
-       done:
+done:
                lck_rw_unlock_shared(&llock);
        }
        return error;
@@ -1441,22 +1635,15 @@ vng_vnode_check_exchangedata(kauth_cred_t __unused cred,
        if (NULL != flabel || NULL != slabel) {
                lck_rw_lock_shared(&llock);
                const struct vng_info *vgi =
-                       vng_lbl_get_withattr(flabel, VNG_EXCHDATA);
+                   vng_lbl_get_withattr(flabel, VNG_EXCHDATA);
                if (NULL != vgi) {
-                        const char *nm = vnode_getname(fvp);
-                       error = vng_guard_violation(vgi,
-                           VNG_EXCHDATA, nm);
-                       if (nm)
-                               vnode_putname(nm);
+                       error = vng_guard_violation(vgi, VNG_EXCHDATA, fvp);
                }
                if (0 == error) {
                        vgi = vng_lbl_get_withattr(slabel, VNG_EXCHDATA);
                        if (NULL != vgi) {
-                               const char *nm = vnode_getname(svp);
                                error = vng_guard_violation(vgi,
-                                   VNG_EXCHDATA, nm);
-                               if (nm)
-                                       vnode_putname(nm);
+                                   VNG_EXCHDATA, svp);
                        }
                }
                lck_rw_unlock_shared(&llock);
@@ -1464,6 +1651,18 @@ vng_vnode_check_exchangedata(kauth_cred_t __unused cred,
        return error;
 }
 
+/* Intercept open-time truncations (by "other") of a guarded vnode */
+
+static int
+vng_vnode_check_open(kauth_cred_t cred,
+    struct vnode *vp, struct label *label, int acc_mode)
+{
+       if (0 == (acc_mode & O_TRUNC)) {
+               return 0;
+       }
+       return vng_vnode_check_truncate(cred, NULL, vp, label);
+}
+
 /*
  * Configuration gorp
  */
@@ -1484,6 +1683,7 @@ SECURITY_READ_ONLY_EARLY(static struct mac_policy_ops) vng_policy_ops = {
        .mpo_vnode_check_write = vng_vnode_check_write,
        .mpo_vnode_check_truncate = vng_vnode_check_truncate,
        .mpo_vnode_check_exchangedata = vng_vnode_check_exchangedata,
+       .mpo_vnode_check_open = vng_vnode_check_open,
 
        .mpo_policy_syscall = vng_policy_syscall,
        .mpo_policy_init = vng_init,
@@ -1506,17 +1706,20 @@ SECURITY_READ_ONLY_LATE(static struct mac_policy_conf) vng_policy_conf = {
        .mpc_runtime_flags = 0
 };
 
-static mac_policy_handle_t vng_policy_handle;
+SECURITY_READ_ONLY_LATE(static mac_policy_handle_t) vng_policy_handle;
 
 void
 vnguard_policy_init(void)
 {
-       if (0 == PE_i_can_has_debugger(NULL))
+       if (0 == PE_i_can_has_debugger(NULL)) {
                return;
-       vng_policy_flags = kVNG_POLICY_LOGMSG | kVNG_POLICY_EXC_CORPSE;
-       PE_parse_boot_argn("vnguard", &vng_policy_flags, sizeof (vng_policy_flags));
-       if (vng_policy_flags)
+       }
+       vng_policy_flags = kVNG_POLICY_LOGMSG |
+           kVNG_POLICY_EXC_CORPSE | kVNG_POLICY_UPRINTMSG;
+       PE_parse_boot_argn("vnguard", &vng_policy_flags, sizeof(vng_policy_flags));
+       if (vng_policy_flags) {
                mac_policy_register(&vng_policy_conf, &vng_policy_handle, NULL);
+       }
 }
 
 #if DEBUG || DEVELOPMENT
@@ -1525,7 +1728,7 @@ vnguard_policy_init(void)
 SYSCTL_DECL(_kern_vnguard);
 SYSCTL_NODE(_kern, OID_AUTO, vnguard, CTLFLAG_RW | CTLFLAG_LOCKED, 0, "vnguard");
 SYSCTL_INT(_kern_vnguard, OID_AUTO, flags, CTLFLAG_RW | CTLFLAG_LOCKED,
-          &vng_policy_flags, 0, "vnguard policy flags");
+    &vng_policy_flags, 0, "vnguard policy flags");
 #endif
 
 #endif /* CONFIG_MACF && CONFIG_VNGUARD */