Disallow writes to filesystems mounted read-only via NULLFS. In this case
authorMatthew Dillon <dillon@dragonflybsd.org>
Mon, 18 Sep 2006 17:42:28 +0000 (17:42 +0000)
committerMatthew Dillon <dillon@dragonflybsd.org>
Mon, 18 Sep 2006 17:42:28 +0000 (17:42 +0000)
the ncp->nc_mount in the namecache must be checked since the vnode's
mount point is the actual filesystem and not the NULLFS mount.

Reported-by: Joerg Sonnenberger <joerg@britannica.bec.de>
sys/kern/kern_fp.c
sys/kern/vfs_syscalls.c
sys/kern/vfs_vnops.c
sys/sys/vnode.h

index 3df86f7..ed30e64 100644 (file)
@@ -31,7 +31,7 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  * 
- * $DragonFly: src/sys/kern/kern_fp.c,v 1.17 2006/06/13 08:12:03 dillon Exp $
+ * $DragonFly: src/sys/kern/kern_fp.c,v 1.18 2006/09/18 17:42:27 dillon Exp $
  */
 
 /*
@@ -160,7 +160,7 @@ fp_vpopen(struct vnode *vp, int flags, file_t *fpp)
            error = EISDIR;
            goto bad2;
        }
-       error = vn_writechk(vp);
+       error = vn_writechk(vp, NULL);
        if (error)
            goto bad2;
        vmode |= VWRITE;
index 004a3dc..70017ce 100644 (file)
@@ -37,7 +37,7 @@
  *
  *     @(#)vfs_syscalls.c      8.13 (Berkeley) 4/15/94
  * $FreeBSD: src/sys/kern/vfs_syscalls.c,v 1.151.2.18 2003/04/04 20:35:58 tegge Exp $
- * $DragonFly: src/sys/kern/vfs_syscalls.c,v 1.102 2006/09/05 00:55:45 dillon Exp $
+ * $DragonFly: src/sys/kern/vfs_syscalls.c,v 1.103 2006/09/18 17:42:27 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -1916,7 +1916,8 @@ retry:
                        flags |= VWRITE;
                if (aflags & X_OK)
                        flags |= VEXEC;
-               if ((flags & VWRITE) == 0 || (error = vn_writechk(vp)) == 0)
+               if ((flags & VWRITE) == 0 || 
+                   (error = vn_writechk(vp, nd->nl_ncp)) == 0)
                        error = VOP_ACCESS(vp, flags, nd->nl_cred);
 
                /*
@@ -2558,7 +2559,7 @@ kern_truncate(struct nlookupdata *nd, off_t length)
        }
        if (vp->v_type == VDIR) {
                error = EISDIR;
-       } else if ((error = vn_writechk(vp)) == 0 &&
+       } else if ((error = vn_writechk(vp, nd->nl_ncp)) == 0 &&
            (error = VOP_ACCESS(vp, VWRITE, nd->nl_cred)) == 0) {
                VATTR_NULL(&vattr);
                vattr.va_size = length;
@@ -2608,7 +2609,7 @@ kern_ftruncate(int fd, off_t length)
        vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
        if (vp->v_type == VDIR) {
                error = EISDIR;
-       } else if ((error = vn_writechk(vp)) == 0) {
+       } else if ((error = vn_writechk(vp, NULL)) == 0) {
                VATTR_NULL(&vattr);
                vattr.va_size = length;
                error = VOP_SETATTR(vp, &vattr, fp->f_cred);
@@ -3190,7 +3191,7 @@ sys_fhopen(struct fhopen_args *uap)
                        error = EISDIR;
                        goto bad;
                }
-               error = vn_writechk(vp);
+               error = vn_writechk(vp, NULL);
                if (error)
                        goto bad;
                mode |= VWRITE;
index 774e42d..9e0cffb 100644 (file)
@@ -37,7 +37,7 @@
  *
  *     @(#)vfs_vnops.c 8.2 (Berkeley) 1/21/94
  * $FreeBSD: src/sys/kern/vfs_vnops.c,v 1.87.2.13 2002/12/29 18:19:53 dillon Exp $
- * $DragonFly: src/sys/kern/vfs_vnops.c,v 1.46 2006/09/10 01:26:39 dillon Exp $
+ * $DragonFly: src/sys/kern/vfs_vnops.c,v 1.47 2006/09/18 17:42:27 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -55,6 +55,8 @@
 #include <sys/conf.h>
 #include <sys/syslog.h>
 
+static int ncp_writechk(struct namecache *ncp);
+
 static int vn_closefile (struct file *fp);
 static int vn_ioctl (struct file *fp, u_long com, caddr_t data,
                struct ucred *cred);
@@ -176,6 +178,8 @@ vn_open(struct nlookupdata *nd, struct file *fp, int fmode, int cmode)
 again:
        if (fmode & O_CREAT) {
                if (ncp->nc_vp == NULL) {
+                       if ((error = ncp_writechk(ncp)) != 0)
+                               return (error);
                        VATTR_NULL(vap);
                        vap->va_type = VREG;
                        vap->va_mode = cmode;
@@ -222,7 +226,7 @@ again:
                                error = EISDIR;
                                goto bad;
                        }
-                       error = vn_writechk(vp);
+                       error = vn_writechk(vp, ncp);
                        if (error) {
                                /*
                                 * Special stale handling, re-resolve the
@@ -338,13 +342,10 @@ bad:
 
 /*
  * Check for write permissions on the specified vnode.
- * Prototype text segments cannot be written.
  */
 int
-vn_writechk(vp)
-       struct vnode *vp;
+vn_writechk(struct vnode *vp, struct namecache *ncp)
 {
-
        /*
         * If there's shared text associated with
         * the vnode, try to free it up once.  If
@@ -352,9 +353,35 @@ vn_writechk(vp)
         */
        if (vp->v_flag & VTEXT)
                return (ETXTBSY);
+
+       /*
+        * If the vnode represents a regular file, check the mount
+        * point via the ncp.  This may be a different mount point
+        * then the one embedded in the vnode (e.g. nullfs).
+        *
+        * We can still write to non-regular files (e.g. devices)
+        * via read-only mounts.
+        */
+       if (ncp && vp->v_type == VREG)
+               return (ncp_writechk(ncp));
        return (0);
 }
 
+/*
+ * Check whether the underlying mount is read-only.  The mount point 
+ * referenced by the namecache may be different from the mount point
+ * used by the underlying vnode in the case of NULLFS, so a separate
+ * check is needed.
+ */
+static
+int
+ncp_writechk(struct namecache *ncp)
+{
+       if (ncp->nc_mount && (ncp->nc_mount->mnt_flag & MNT_RDONLY))
+               return (EROFS);
+       return(0);
+}
+
 /*
  * Vnode close call
  */
index 64cb763..340e513 100644 (file)
@@ -32,7 +32,7 @@
  *
  *     @(#)vnode.h     8.7 (Berkeley) 2/4/94
  * $FreeBSD: src/sys/sys/vnode.h,v 1.111.2.19 2002/12/29 18:19:53 dillon Exp $
- * $DragonFly: src/sys/sys/vnode.h,v 1.68 2006/09/10 01:26:40 dillon Exp $
+ * $DragonFly: src/sys/sys/vnode.h,v 1.69 2006/09/18 17:42:28 dillon Exp $
  */
 
 #ifndef _SYS_VNODE_H_
@@ -509,7 +509,7 @@ int vn_rdwr_inchunks (enum uio_rw rw, struct vnode *vp, caddr_t base,
 int    vn_stat (struct vnode *vp, struct stat *sb, struct ucred *cred);
 cdev_t vn_todev (struct vnode *vp);
 void   vfs_timestamp (struct timespec *);
-int    vn_writechk (struct vnode *vp);
+int    vn_writechk (struct vnode *vp, struct namecache *ncp);
 int    vop_stdopen (struct vop_open_args *ap);
 int    vop_stdclose (struct vop_close_args *ap);
 int    vop_nopoll (struct vop_poll_args *ap);