Subject: MNT_NODEV and nullfs and derived filesystems
To: None <tech-kern@netbsd.org, art@stacken.kth.se>
From: Manuel Bouyer <bouyer@antioche.lip6.fr>
List: tech-kern
Date: 03/17/1999 16:23:28
--tKW2IUtsqtDRztdT
Content-Type: text/plain; charset=us-ascii

Hi,
As pointed out to me by Artur Grabowski, there is a problem with nullfs
and derived (umap, union): MNT_NODEV has to be checked at open(), which is not
done for these filesystems (MNT_NODEV on the underlying filesystem is
handled, however, so this is not really a problem as big as MNT_NOEXEC).
Below is a patch that should fix this for null, umap, union (this was
fixed some time ago in OpenBSD, but for nullfs only).
In my sense this is more a semantic problem than a security problem.
Comments ?

--
Manuel Bouyer, LIP6, Universite Paris VI.           Manuel.Bouyer@lip6.fr
--

--tKW2IUtsqtDRztdT
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename=diff

Index: miscfs/nullfs/null_vnops.c
===================================================================
RCS file: /cvsroot/src/sys/miscfs/nullfs/null_vnops.c,v
retrieving revision 1.13
diff -u -r1.13 null_vnops.c
--- null_vnops.c	1998/03/01 02:21:43	1.13
+++ null_vnops.c	1999/03/17 15:11:53
@@ -203,6 +203,7 @@
 int	null_lookup __P((void *));
 int	null_setattr __P((void *));
 int	null_access __P((void *));
+int	null_open __P((void *));
 
 
 /*
@@ -495,6 +496,24 @@
 }
 
 /*
+ * We must handle open to be able to catch MNT_NODEV and friends.
+ */
+int
+null_open(v)
+	void *v;
+{
+	struct vop_open_args *ap = v;
+	struct vnode *vp = ap->a_vp;
+	enum vtype lower_type = NULLVPTOLOWERVP(vp)->v_type;
+
+	if (((lower_type == VBLK) || (lower_type == VCHR)) &&
+	    (vp->v_mount->mnt_flag & MNT_NODEV))
+		return ENXIO;
+
+	return null_bypass(ap);
+}
+
+/*
  * We need to process our own vnode lock and then clear the
  * interlock flag as it applies only to our vnode, not the
  * vnodes below us on the stack.
@@ -666,6 +685,8 @@
 	{ &vop_inactive_desc, null_inactive },
 	{ &vop_reclaim_desc,  null_reclaim },
 	{ &vop_print_desc,    null_print },
+
+	{ &vop_open_desc,     null_open },	/* mount option handling */
 
 	{ &vop_strategy_desc, null_strategy },
 	{ &vop_bwrite_desc,   null_bwrite },
Index: miscfs/umapfs/umap_vnops.c
===================================================================
RCS file: /cvsroot/src/sys/miscfs/umapfs/umap_vnops.c,v
retrieving revision 1.10
diff -u -r1.10 umap_vnops.c
--- umap_vnops.c	1998/03/01 02:21:51	1.10
+++ umap_vnops.c	1999/03/17 15:11:54
@@ -67,6 +67,7 @@
 int	umap_bwrite	__P((void *));
 int	umap_lock	__P((void *));
 int	umap_unlock	__P((void *));
+int	umap_open	__P((void *));
 
 extern int  null_bypass __P((void *));
 
@@ -88,6 +89,9 @@
 	{ &vop_inactive_desc, umap_inactive },
 	{ &vop_reclaim_desc, umap_reclaim },
 	{ &vop_print_desc, umap_print },
+
+	{ &vop_open_desc, umap_open }, /* mount option handling */
+
 	{ &vop_rename_desc, umap_rename },
 
 	{ &vop_strategy_desc, umap_strategy },
@@ -413,6 +417,25 @@
 		ap->a_vap->va_gid = (gid_t) NULLGROUP;
 	
 	return (0);
+}
+
+/* 
+ * We must handle open to be able to catch MNT_NODEV and friends.
+ */   
+int
+umap_open(v)
+        void *v;
+{
+        struct vop_open_args *ap = v;
+        struct vnode *vp = ap->a_vp;
+        enum vtype lower_type = UMAPVPTOLOWERVP(vp)->v_type;
+
+
+        if (((lower_type == VBLK) || (lower_type == VCHR)) &&
+            (vp->v_mount->mnt_flag & MNT_NODEV))
+                return ENXIO;
+
+        return umap_bypass(ap);
 }
 
 /*ARGSUSED*/
Index: miscfs/union/union_vnops.c
===================================================================
RCS file: /cvsroot/src/sys/miscfs/union/union_vnops.c,v
retrieving revision 1.42
diff -u -r1.42 union_vnops.c
--- union_vnops.c	1998/06/05 19:53:00	1.42
+++ union_vnops.c	1999/03/17 15:11:55
@@ -639,8 +639,11 @@
 		}
 
 		/*
-		 * Just open the lower vnode
+		 * Just open the lower vnode, but check for nodev mount flag
 		 */
+		if ((tvp->v_type == VBLK || tvp->v_type == VCHR) &&
+		    (ap->a_vp->v_mount->mnt_flag & MNT_NODEV))
+			return ENXIO;
 		un->un_openl++;
 		vn_lock(tvp, LK_EXCLUSIVE | LK_RETRY);
 		error = VOP_OPEN(tvp, mode, cred, p);
@@ -648,6 +651,12 @@
 
 		return (error);
 	}
+	/*
+	 * Just open the upper vnode, checking for nodev mount flag first
+	 */
+	if ((tvp->v_type == VBLK || tvp->v_type == VCHR) &&
+	    (ap->a_vp->v_mount->mnt_flag & MNT_NODEV))
+		return ENXIO;
 
 	FIXUP(un);
 

--tKW2IUtsqtDRztdT--