Bug 26049

Summary: bug in modular vn code causes a fatal trap 12
Product: Base System Reporter: chervarium <chervarium>
Component: i386Assignee: freebsd-bugs (Nobody) <bugs>
Status: Closed FIXED    
Severity: Affects Only Me    
Priority: Normal    
Version: Unspecified   
Hardware: Any   
OS: Any   
Attachments:
Description Flags
file.diff none

Description chervarium 2001-03-24 12:00:02 UTC
incorrectly modularised vn driver causes a fatal trap 12 due to when module is unloaded, it's entry in cdevsw[] array is left unchanged. afterward, any lstat-ting /dev/vn0 result in unresolved page fault and crash. last in chain function devsw from /usr/src/sys/kerc/kern_conf.c returns invalid (struct cdevsw *) pointer to vn_isdisk from vfs_subr.c, and that pointer is accessed (i'm not describing the whole functions chain, everyone can see it in the sources):
        if (!devsw(vp->v_rdev)) {
                if (errp != NULL)
                        *errp = ENXIO;
                return (0);
        }
        if (!(devsw(vp->v_rdev)->d_flags & D_DISK)) {
                if (errp != NULL)
                        *errp = ENOTBLK;
                return (0);
        }
(watch the second major if statement)
this problem may be found in other modular disk drivers. patch available (posted in the "Fix to the problem if known" part)...

How-To-Repeat: almost any loading of vn, using it and unloading it, followed by lstat syscall to "/dev/vn0" result in activating the bug and fatal trap 12 (page fault exception on x86 in protected mode with paging bit in %cr0 = 1 ;)...
Comment 1 iedowse 2001-03-25 20:30:38 UTC
In message <200103241152.f2OBqOh33828@freefall.freebsd.org>, chervarium@nove.bg
 writes:

>@@ -776,6 +776,7 @@
>                                vnclear(vn);
>                        free(vn, M_DEVBUF);
>                }
>+               cdevsw_remove(&vn_cdevsw);
>                break;

Thanks for the bug report, though it seems that this patch is not
quite enough to solve the problems that occur when unloading the
`vn' module after use.

If you attempt to use vnconfig again after the module has been
unloaded, it may appear to work, but the system could become unstable
and crash somewhere else. With 'options INVARIANTS' in the kernel
config file, this problem is much more obvious and the following
sequence of operations will cause a crash.

	dd if=/dev/zero bs=1k count=100 of=/tmp/foo
	vnconfig -e /dev/vn0 /tmp/foo
	vnconfig -u /dev/vn0
	kldunload vn
	vnconfig -e /dev/vn0 /tmp/foo

The following patch, which includes the cdevsw_remove you suggested,
seems to solve this. The module stores a pointer to the vn_softc in
the device si_drv1 field, but this pointer will be stale if the
module is unloaded and then reloaded. This patch avoids the use
of this saved pointer in vnopen by forcing a full lookup.

Ian

Index: vn.c
===================================================================
RCS file: /dump/FreeBSD-CVS/src/sys/dev/vn/Attic/vn.c,v
retrieving revision 1.105.2.1
diff -u -r1.105.2.1 vn.c
--- vn.c	2000/05/15 16:50:33	1.105.2.1
+++ vn.c	2001/03/25 19:09:54
@@ -177,13 +177,10 @@
 	struct vn_softc *vn;
 
 	unit = dkunit(dev);
-	vn = dev->si_drv1;
-	if (!vn) {
-		SLIST_FOREACH(vn, &vn_list, sc_list) {
-			if (vn->sc_unit == unit) {
-				dev->si_drv1 = vn;
-				break;
-			}
+	SLIST_FOREACH(vn, &vn_list, sc_list) {
+		if (vn->sc_unit == unit) {
+			dev->si_drv1 = vn;
+			break;
 		}
 	}
 	if (!vn) {
@@ -208,9 +205,7 @@
 	/*
 	 * Locate preexisting device
 	 */
-
-	if ((vn = dev->si_drv1) == NULL)
-		vn = vnfindvn(dev);
+	vn = vnfindvn(dev);
 
 	/*
 	 * Update si_bsize fields for device.  This data will be overriden by
@@ -776,6 +771,7 @@
 				vnclear(vn);
 			free(vn, M_DEVBUF);
 		}
+		cdevsw_remove(&vn_cdevsw);
 		break;
 	default:
 		break;
Comment 2 n_hibma 2001-03-26 08:21:01 UTC
http://www.freebsd.org/cgi/query-pr.cgi?pr=18270

is a duplicate of this one. I believe that I committd the fix to current
quite some time ago.

Could you close this one as well, while you are at it?

Thanks.

Nick
Comment 3 iedowse freebsd_committer freebsd_triage 2001-03-26 18:02:20 UTC
State Changed
From-To: open->closed

A similar patch, based on kern/18270 has been committed to -stable. 
Thanks for the bug report!