Module Name:    src
Committed By:   christos
Date:           Wed Nov 15 21:21:18 UTC 2017

Modified Files:
        src/sys/ufs/ffs: ffs_vfsops.c

Log Message:
PR/52728: Izumi Tsutsui: "mount -u /dev/ /" triggers kernel panic
Simplify the control flow of the mount code and make sure that the
mountfrom argument can be converted to a block device in the update
case.
XXX: pullup-8


To generate a diff of this commit:
cvs rdiff -u -r1.354 -r1.355 src/sys/ufs/ffs/ffs_vfsops.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/ufs/ffs/ffs_vfsops.c
diff -u src/sys/ufs/ffs/ffs_vfsops.c:1.354 src/sys/ufs/ffs/ffs_vfsops.c:1.355
--- src/sys/ufs/ffs/ffs_vfsops.c:1.354	Sun Aug 20 08:51:38 2017
+++ src/sys/ufs/ffs/ffs_vfsops.c	Wed Nov 15 16:21:18 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: ffs_vfsops.c,v 1.354 2017/08/20 12:51:38 maya Exp $	*/
+/*	$NetBSD: ffs_vfsops.c,v 1.355 2017/11/15 21:21:18 christos Exp $	*/
 
 /*-
  * Copyright (c) 2008, 2009 The NetBSD Foundation, Inc.
@@ -61,7 +61,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ffs_vfsops.c,v 1.354 2017/08/20 12:51:38 maya Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ffs_vfsops.c,v 1.355 2017/11/15 21:21:18 christos Exp $");
 
 #if defined(_KERNEL_OPT)
 #include "opt_ffs.h"
@@ -418,12 +418,13 @@ ffs_mount(struct mount *mp, const char *
 		return EINVAL;
 	}
 
+	ump = VFSTOUFS(mp);
+	if ((mp->mnt_flag & (MNT_GETARGS|MNT_UPDATE)) && ump == NULL) {
+		DPRINTF("no ump");
+		return EIO;
+	}
+
 	if (mp->mnt_flag & MNT_GETARGS) {
-		ump = VFSTOUFS(mp);
-		if (ump == NULL) {
-			DPRINTF("no ump");
-			return EIO;
-		}
 		args->fspec = NULL;
 		*data_len = sizeof *args;
 		return 0;
@@ -432,7 +433,13 @@ ffs_mount(struct mount *mp, const char *
 	update = mp->mnt_flag & MNT_UPDATE;
 
 	/* Check arguments */
-	if (args->fspec != NULL) {
+	if (args->fspec == NULL) {
+		if (!update) {
+			/* New mounts must have a filename for the device */
+			DPRINTF("no filename for mount");
+			return EINVAL;
+		}
+	} else {
 		/*
 		 * Look up the name and verify that it's sane.
 		 */
@@ -443,48 +450,43 @@ ffs_mount(struct mount *mp, const char *
 			return error;
 		}
 
-		if (!update) {
-			/*
-			 * Be sure this is a valid block device
-			 */
-			if (devvp->v_type != VBLK) {
-				DPRINTF("non block device %d", devvp->v_type);
-				error = ENOTBLK;
-			} else if (bdevsw_lookup(devvp->v_rdev) == NULL) {
-				DPRINTF("can't find block device 0x%jx",
-				    devvp->v_rdev);
-				error = ENXIO;
-			}
-		} else {
+		/*
+		 * Be sure this is a valid block device
+		 */
+		if (devvp->v_type != VBLK) {
+			DPRINTF("non block device %d", devvp->v_type);
+			error = ENOTBLK;
+			goto fail;
+		}
+
+		if (bdevsw_lookup(devvp->v_rdev) == NULL) {
+			DPRINTF("can't find block device 0x%jx",
+			    devvp->v_rdev);
+			error = ENXIO;
+			goto fail;
+		}
+
+		if (update) {
 			/*
 			 * Be sure we're still naming the same device
 			 * used for our initial mount
 			 */
-			ump = VFSTOUFS(mp);
-			if (devvp != ump->um_devvp) {
-				if (devvp->v_rdev != ump->um_devvp->v_rdev) {
-					DPRINTF("wrong device 0x%jx != 0x%jx",
-					    (uintmax_t)devvp->v_rdev,
-					    (uintmax_t)ump->um_devvp->v_rdev);
-					error = EINVAL;
-				} else {
-					vrele(devvp);
-					devvp = ump->um_devvp;
-					vref(devvp);
-				}
+			if (devvp != ump->um_devvp &&
+			    devvp->v_rdev != ump->um_devvp->v_rdev) {
+				DPRINTF("wrong device 0x%jx != 0x%jx",
+				    (uintmax_t)devvp->v_rdev,
+				    (uintmax_t)ump->um_devvp->v_rdev);
+				error = EINVAL;
+				goto fail;
 			}
+			vrele(devvp);
+			devvp = NULL;
 		}
-	} else {
-		if (!update) {
-			/* New mounts must have a filename for the device */
-			DPRINTF("no filename for mount");
-			return EINVAL;
-		} else {
-			/* Use the extant mount */
-			ump = VFSTOUFS(mp);
-			devvp = ump->um_devvp;
-			vref(devvp);
-		}
+	}
+
+	if (devvp == NULL) {
+		devvp = ump->um_devvp;
+		vref(devvp);
 	}
 
 	/*
@@ -495,25 +497,17 @@ ffs_mount(struct mount *mp, const char *
 	 * updating the mount is okay (for example, as far as securelevel goes)
 	 * which leaves us with the normal check.
 	 */
-	if (error == 0) {
-		accessmode = VREAD;
-		if (update ?
-		    (mp->mnt_iflag & IMNT_WANTRDWR) != 0 :
-		    (mp->mnt_flag & MNT_RDONLY) == 0)
-			accessmode |= VWRITE;
-		vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
-		error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_MOUNT,
-		    KAUTH_REQ_SYSTEM_MOUNT_DEVICE, mp, devvp,
-		    KAUTH_ARG(accessmode));
-		if (error) {
-			DPRINTF("kauth returned %d", error);
-		}
-		VOP_UNLOCK(devvp);
-	}
-
+	accessmode = VREAD;
+	if (update ? (mp->mnt_iflag & IMNT_WANTRDWR) != 0 :
+	    (mp->mnt_flag & MNT_RDONLY) == 0)
+		accessmode |= VWRITE;
+	vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
+	error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_MOUNT,
+	    KAUTH_REQ_SYSTEM_MOUNT_DEVICE, mp, devvp, KAUTH_ARG(accessmode));
+	VOP_UNLOCK(devvp);
 	if (error) {
-		vrele(devvp);
-		return (error);
+		DPRINTF("kauth returned %d", error);
+		goto fail;
 	}
 
 #ifdef WAPBL

Reply via email to