]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/vfs/vfs_vnops.c
xnu-4903.231.4.tar.gz
[apple/xnu.git] / bsd / vfs / vfs_vnops.c
index 27f61a448b3f6438eaf3f664e5472d94aca98b6b..6b03aa5a44f4d75f81a62ad5a6c0fd8edae9e978 100644 (file)
@@ -112,18 +112,19 @@ int       ubc_setcred(struct vnode *, struct proc *);
 #endif
 
 #include <IOKit/IOBSD.h>
+#include <libkern/section_keywords.h>
 
 static int vn_closefile(struct fileglob *fp, vfs_context_t ctx);
 static int vn_ioctl(struct fileproc *fp, u_long com, caddr_t data,
-                       vfs_context_t ctx);
+               vfs_context_t ctx);
 static int vn_read(struct fileproc *fp, struct uio *uio, int flags,
-                       vfs_context_t ctx);
+               vfs_context_t ctx);
 static int vn_write(struct fileproc *fp, struct uio *uio, int flags,
-                       vfs_context_t ctx);
+               vfs_context_t ctx);
 static int vn_select( struct fileproc *fp, int which, void * wql,
-                       vfs_context_t ctx);
+               vfs_context_t ctx);
 static int vn_kqfilt_add(struct fileproc *fp, struct knote *kn,
-                       vfs_context_t ctx);
+               struct kevent_internal_s *kev, vfs_context_t ctx);
 static void filt_vndetach(struct knote *kn);
 static int filt_vnode(struct knote *kn, long hint);
 static int filt_vnode_common(struct knote *kn, vnode_t vp, long hint);
@@ -147,10 +148,10 @@ const struct fileops vnops = {
 static int filt_vntouch(struct knote *kn, struct kevent_internal_s *kev);
 static int filt_vnprocess(struct knote *kn, struct filt_process_s *data, struct kevent_internal_s *kev);
 
-struct  filterops vnode_filtops = { 
-       .f_isfd = 1, 
-       .f_attach = NULL, 
-       .f_detach = filt_vndetach, 
+SECURITY_READ_ONLY_EARLY(struct  filterops) vnode_filtops = {
+       .f_isfd = 1,
+       .f_attach = NULL,
+       .f_detach = filt_vndetach,
        .f_event = filt_vnode,
        .f_touch = filt_vntouch,
        .f_process = filt_vnprocess,
@@ -567,6 +568,19 @@ continue_create_lookup:
                panic("Haven't cleaned up adequately in vn_open_auth()");
        }
 
+#if DEVELOPMENT || DEBUG
+       /*
+        * XXX VSWAP: Check for entitlements or special flag here
+        * so we can restrict access appropriately.
+        */
+#else /* DEVELOPMENT || DEBUG */
+
+       if (vnode_isswap(vp) && (fmode & (FWRITE | O_TRUNC)) && (ctx != vfs_context_kernel())) {
+               error = EPERM;
+               goto bad;
+       }
+#endif /* DEVELOPMENT || DEBUG */
+
        /*
         * Expect to use this code for filesystems without compound VNOPs, for the root 
         * of a filesystem, which can't be "looked up" in the sense of VNOP_LOOKUP(),
@@ -922,7 +936,21 @@ vn_rdwr_64(
                                error = VNOP_READ(vp, auio, ioflg, &context);
                        }
                } else {
+
+#if DEVELOPMENT || DEBUG
+                       /*
+                        * XXX VSWAP: Check for entitlements or special flag here
+                        * so we can restrict access appropriately.
+                        */
                        error = VNOP_WRITE(vp, auio, ioflg, &context);
+#else /* DEVELOPMENT || DEBUG */
+
+                       if (vnode_isswap(vp) && ((ioflg & (IO_SWAP_DISPATCH | IO_SKIP_ENCRYPTION)) == 0)) {
+                               error = EPERM;
+                       } else {
+                               error = VNOP_WRITE(vp, auio, ioflg, &context);
+                       }
+#endif /* DEVELOPMENT || DEBUG */
                }
        }
 
@@ -1017,11 +1045,13 @@ vn_read(struct fileproc *fp, struct uio *uio, int flags, vfs_context_t ctx)
        count = uio_resid(uio);
 
        if (vnode_isswap(vp) && !(IO_SKIP_ENCRYPTION & ioflag)) {
+
                /* special case for swap files */
                error = vn_read_swapfile(vp, uio);
        } else {
                error = VNOP_READ(vp, uio, ioflag, ctx);
        }
+
        if ((flags & FOF_OFFSET) == 0) {
                fp->f_fglob->fg_offset += count - uio_resid(uio);
                if (offset_locked) {
@@ -1056,6 +1086,21 @@ vn_write(struct fileproc *fp, struct uio *uio, int flags, vfs_context_t ctx)
                return(error);
        }
 
+#if DEVELOPMENT || DEBUG
+       /*
+        * XXX VSWAP: Check for entitlements or special flag here
+        * so we can restrict access appropriately.
+        */
+#else /* DEVELOPMENT || DEBUG */
+
+       if (vnode_isswap(vp)) {
+               (void)vnode_put(vp);
+               error = EPERM;
+               return (error);
+       }
+#endif /* DEVELOPMENT || DEBUG */
+
+
 #if CONFIG_MACF
        error = mac_vnode_check_write(ctx, vfs_context_ucred(ctx), vp);
        if (error) {
@@ -1298,7 +1343,7 @@ vn_stat_noauth(struct vnode *vp, void *sbptr, kauth_filesec_t *xsec, int isstat6
        };
        if (isstat64 != 0) {
                sb64->st_mode = mode;
-               sb64->st_nlink = VATTR_IS_SUPPORTED(&va, va_nlink) ? (u_int16_t)va.va_nlink : 1;
+               sb64->st_nlink = VATTR_IS_SUPPORTED(&va, va_nlink) ? va.va_nlink > UINT16_MAX ? UINT16_MAX : (u_int16_t)va.va_nlink : 1;
                sb64->st_uid = va.va_uid;
                sb64->st_gid = va.va_gid;
                sb64->st_rdev = va.va_rdev;
@@ -1316,7 +1361,7 @@ vn_stat_noauth(struct vnode *vp, void *sbptr, kauth_filesec_t *xsec, int isstat6
                sb64->st_blocks = roundup(va.va_total_alloc, 512) / 512;
        } else {
                sb->st_mode = mode;
-               sb->st_nlink = VATTR_IS_SUPPORTED(&va, va_nlink) ? (u_int16_t)va.va_nlink : 1;
+               sb->st_nlink = VATTR_IS_SUPPORTED(&va, va_nlink) ? va.va_nlink > UINT16_MAX ? UINT16_MAX : (u_int16_t)va.va_nlink : 1;
                sb->st_uid = va.va_uid;
                sb->st_gid = va.va_gid;
                sb->st_rdev = va.va_rdev;
@@ -1642,12 +1687,13 @@ vn_pathconf(vnode_t vp, int name, int32_t *retval, vfs_context_t ctx)
 }
 
 static int
-vn_kqfilt_add(struct fileproc *fp, struct knote *kn, vfs_context_t ctx)
+vn_kqfilt_add(struct fileproc *fp, struct knote *kn,
+               struct kevent_internal_s *kev, vfs_context_t ctx)
 {
        struct vnode *vp;
        int error = 0;
        int result = 0;
-       
+
        vp = (struct vnode *)fp->f_fglob->fg_data;
 
        /*
@@ -1665,7 +1711,7 @@ vn_kqfilt_add(struct fileproc *fp, struct knote *kn, vfs_context_t ctx)
 
                                } else if (!vnode_isreg(vp)) {
                                        if (vnode_ischr(vp)) {
-                                               result = spec_kqfilter(vp, kn);
+                                               result = spec_kqfilter(vp, kn, kev);
                                                if ((kn->kn_flags & EV_ERROR) == 0) {
                                                        /* claimed by a special device */
                                                        vnode_put(vp);
@@ -1749,7 +1795,7 @@ filt_vndetach(struct knote *kn)
  * differently than the regular case for VREG files.  If not in poll(),
  * then we need to know current fileproc offset for VREG.
  */
-static intptr_t
+static int64_t
 vnode_readable_data_count(vnode_t vp, off_t current_offset, int ispoll)
 {
        if (vnode_isfifo(vp)) {
@@ -1757,25 +1803,25 @@ vnode_readable_data_count(vnode_t vp, off_t current_offset, int ispoll)
                int cnt;
                int err = fifo_charcount(vp, &cnt);
                if (err == 0) {
-                       return (intptr_t)cnt;
+                       return (int64_t)cnt;
                } else 
 #endif
                {
-                       return (intptr_t)0;
+                       return 0;
                }
        } else if (vnode_isreg(vp)) {
                if (ispoll) {
-                       return (intptr_t)1;
+                       return 1;
                }
 
                off_t amount;
                amount = vp->v_un.vu_ubcinfo->ui_size - current_offset;
-               if (amount > (off_t)INTPTR_MAX) {
-                       return INTPTR_MAX;
-               } else if (amount < (off_t)INTPTR_MIN) {
-                       return INTPTR_MIN;
+               if (amount > INT64_MAX) {
+                       return INT64_MAX;
+               } else if (amount < INT64_MIN) {
+                       return INT64_MIN;
                } else {
-                       return (intptr_t)amount;
+                       return (int64_t)amount;
                } 
        } else {
                panic("Should never have an EVFILT_READ except for reg or fifo.");
@@ -1890,8 +1936,6 @@ filt_vntouch(struct knote *kn, struct kevent_internal_s *kev)
 
        /* accept new input fflags mask */
        kn->kn_sfflags = kev->fflags;
-       if ((kn->kn_status & KN_UDATA_SPECIFIC) == 0)
-               kn->kn_udata = kev->udata;
 
        activate = filt_vnode_common(kn, vp, hint);