X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/5ba3f43ea354af8ad55bea84372a2bc834d8757c..bca245acd4c03fd752d1a45f011ad495e60fe53d:/bsd/kern/kern_guarded.c diff --git a/bsd/kern/kern_guarded.c b/bsd/kern/kern_guarded.c index ea583e9cf..c78c64673 100644 --- a/bsd/kern/kern_guarded.c +++ b/bsd/kern/kern_guarded.c @@ -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 @@ -11,10 +11,10 @@ * 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@ */ @@ -53,14 +53,15 @@ #include #include #include +#include #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, * 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 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 */