#include <kern/kalloc.h>
#include <sys/sysproto.h>
#include <sys/vnode.h>
+#include <sys/vnode_internal.h>
+#include <sys/uio_internal.h>
+#include <sys/ubc_internal.h>
#include <vfs/vfs_support.h>
#include <security/audit/audit.h>
+#include <sys/syscall.h>
+#include <sys/kauth.h>
+#include <sys/kdebug.h>
+#include <stdbool.h>
+#include <vm/vm_protos.h>
+#if CONFIG_PROTECT
+#include <sys/cprotect.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 );
+extern int wr_uio(struct proc *p, struct fileproc *fp, uio_t uio, user_ssize_t *retval);
/*
* Experimental guarded file descriptor support.
#define GUARD_REQUIRED (GUARD_DUP)
#define GUARD_ALL (GUARD_REQUIRED | \
- (GUARD_CLOSE | GUARD_SOCKET_IPC | GUARD_FILEPORT))
+ (GUARD_CLOSE | GUARD_SOCKET_IPC | GUARD_FILEPORT | GUARD_WRITE))
if (((uap->guardflags & GUARD_REQUIRED) != GUARD_REQUIRED) ||
((uap->guardflags & ~GUARD_ALL) != 0))
guarded_fileproc_alloc_init, &crarg, retval));
}
+/*
+ * int guarded_open_dprotected_np(const char *pathname, int flags,
+ * const guardid_t *guard, u_int guardflags, int dpclass, int dpflags, ...);
+ *
+ * This SPI is extension of guarded_open_np() to include dataprotection class on creation
+ * in "dpclass" and dataprotection flags 'dpflags'. Otherwise behaviors are same as in
+ * guarded_open_np()
+ */
+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);
+
+#define GUARD_REQUIRED (GUARD_DUP)
+#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);
+
+ int error;
+ struct gfp_crarg crarg = {
+ .gca_attrs = uap->guardflags
+ };
+
+ if ((error = copyin(uap->guard,
+ &(crarg.gca_guard), sizeof (crarg.gca_guard))) != 0)
+ return (error);
+
+ /*
+ * Disallow certain guard values -- is zero enough?
+ */
+ if (crarg.gca_guard == 0)
+ return (EINVAL);
+
+ struct filedesc *fdp = p->p_fd;
+ struct vnode_attr va;
+ struct nameidata nd;
+ vfs_context_t ctx = vfs_context_current();
+ int cmode;
+
+ VATTR_INIT(&va);
+ cmode = ((uap->mode & ~fdp->fd_cmask) & ALLPERMS) & ~S_ISTXT;
+ VATTR_SET(&va, va_mode, cmode & ACCESSPERMS);
+
+ NDINIT(&nd, LOOKUP, OP_OPEN, FOLLOW | AUDITVNPATH1, UIO_USERSPACE,
+ uap->path, ctx);
+
+ /*
+ * 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) {
+ VATTR_SET(&va, va_dataprotect_class, uap->dpclass);
+ }
+
+ if (uap->dpflags & O_DP_GETRAWENCRYPTED) {
+ if ( uap->flags & (O_RDWR | O_WRONLY)) {
+ /* Not allowed to write raw encrypted bytes */
+ return EINVAL;
+ }
+ VATTR_SET(&va, va_dataprotect_flags, VA_DP_RAWENCRYPTED);
+ }
+
+ return (open1(ctx, &nd, uap->flags | O_CLOFORK, &va,
+ guarded_fileproc_alloc_init, &crarg, retval));
+}
+
/*
* int guarded_kqueue_np(const guardid_t *guard, u_int guardflags);
*
};
struct fileproc *nfp =
guarded_fileproc_alloc_init(&crarg);
+ struct guarded_fileproc *gfp;
proc_fdlock(p);
switch (error = fp_tryswap(p, fd, nfp)) {
- struct guarded_fileproc *gfp;
-
case 0: /* guarded-ness comes with side-effects */
gfp = FP_TO_GFP(nfp);
if (gfp->gf_attrs & GUARD_CLOSE)
proc_fdunlock(p);
return (error);
}
-
+
+/*
+ * user_ssize_t guarded_write_np(int fd, const guardid_t *guard,
+ * user_addr_t cbuf, user_ssize_t nbyte);
+ *
+ * Initial implementation of guarded writes.
+ */
+int
+guarded_write_np(struct proc *p, struct guarded_write_np_args *uap, user_ssize_t *retval)
+{
+ int error;
+ int fd = uap->fd;
+ guardid_t uguard;
+ struct fileproc *fp;
+ struct guarded_fileproc *gfp;
+ bool wrote_some = false;
+
+ AUDIT_ARG(fd, fd);
+
+ if ((error = copyin(uap->guard, &uguard, sizeof (uguard))) != 0)
+ return (error);
+
+ error = fp_lookup_guarded(p, fd, uguard, &gfp);
+ 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);
+ wrote_some = *retval > 0;
+ }
+ if (wrote_some)
+ fp_drop_written(p, fd, fp);
+ else
+ fp_drop(p, fd, fp, 0);
+ return(error);
+}
+
+/*
+ * user_ssize_t guarded_pwrite_np(int fd, const guardid_t *guard,
+ * user_addr_t buf, user_size_t nbyte, off_t offset);
+ *
+ * Initial implementation of guarded pwrites.
+ */
+ int
+ guarded_pwrite_np(struct proc *p, struct guarded_pwrite_np_args *uap, user_ssize_t *retval)
+ {
+ struct fileproc *fp;
+ int error;
+ int fd = uap->fd;
+ vnode_t vp = (vnode_t)0;
+ guardid_t uguard;
+ struct guarded_fileproc *gfp;
+ bool wrote_some = false;
+
+ AUDIT_ARG(fd, fd);
+
+ if ((error = copyin(uap->guard, &uguard, sizeof (uguard))) != 0)
+ return (error);
+
+ error = fp_lookup_guarded(p, fd, uguard, &gfp);
+ 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;
+
+ if (fp->f_type != DTYPE_VNODE) {
+ error = ESPIPE;
+ goto errout;
+ }
+ vp = (vnode_t)fp->f_fglob->fg_data;
+ if (vnode_isfifo(vp)) {
+ error = ESPIPE;
+ goto errout;
+ }
+ if ((vp->v_flag & VISTTY)) {
+ error = ENXIO;
+ goto errout;
+ }
+ if (uap->offset == (off_t)-1) {
+ error = EINVAL;
+ goto errout;
+ }
+
+ error = dofilewrite(&context, fp, uap->buf, uap->nbyte,
+ 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);
+
+ 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);
+}
+
+/*
+ * user_ssize_t guarded_writev_np(int fd, const guardid_t *guard,
+ * struct iovec *iovp, u_int iovcnt);
+ *
+ * Initial implementation of guarded writev.
+ *
+ */
+int
+guarded_writev_np(struct proc *p, struct guarded_writev_np_args *uap, user_ssize_t *retval)
+{
+ uio_t auio = NULL;
+ int error;
+ struct fileproc *fp;
+ struct user_iovec *iovp;
+ guardid_t uguard;
+ struct guarded_fileproc *gfp;
+ bool wrote_some = false;
+
+ AUDIT_ARG(fd, uap->fd);
+
+ /* Verify range bedfore calling uio_create() */
+ 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);
+
+ /* get location of iovecs within the uio. then copyin the iovecs from
+ * user space.
+ */
+ iovp = uio_iovsaddr(auio);
+ if (iovp == NULL) {
+ error = ENOMEM;
+ goto ExitThisRoutine;
+ }
+ error = copyin_user_iovec_array(uap->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
+ */
+ uio_calculateresid(auio);
+
+ if ((error = copyin(uap->guard, &uguard, sizeof (uguard))) != 0)
+ goto ExitThisRoutine;
+
+ error = fp_lookup_guarded(p, uap->fd, uguard, &gfp);
+ if (error)
+ goto ExitThisRoutine;
+
+ fp = GFP_TO_FP(gfp);
+ if ((fp->f_flag & FWRITE) == 0) {
+ error = EBADF;
+ } else {
+ 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);
+ExitThisRoutine:
+ if (auio != NULL) {
+ uio_free(auio);
+ }
+ return (error);
+}