[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

kern/72436: [patch] digi(4) panic's system on open



>Number:         72436
>Category:       kern
>Synopsis:       [patch] digi(4) panic's system on open
>Confidential:   no
>Severity:       serious
>Priority:       high
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Thu Oct 07 23:30:20 GMT 2004
>Closed-Date:
>Last-Modified:
>Originator:     Peter Jeremy
>Release:        FreeBSD 5.3-BETA6 i386
>Organization:
Alcatel Australia Limited
>Environment:
System: FreeBSD srpca.alcatel.com.au 5.3-BETA6 FreeBSD 5.3-BETA6 #1: Tue Oct 5 13:52:33 EST 2004 root_(_at_)_srpca_(_dot_)_alcatel_(_dot_)_com_(_dot_)_au:/var/obj/usr/src/sys/GENERIC i386

>Description:
	The digi(4) driver locally allocates struct tty objects rather
	than using ttymalloc(9).  As a result, the tty object is not
	initialised as expected by the rest of the TTY subsystem.  In
	particular, the various mutex structures are not initialised and
	the attempt to use them during the open causes the system to
	panic.
 
	I would appreciate it if this fix was merged into 5.3.

>How-To-Repeat:
	Install a DigiBoard Xem or equivalent.
	kldload digi
	stty -a -f /dev/ttyD0.0
	[instant panic dereferencing a NULL pointer in knote()]

>Fix:
	Currently, the digi(4) driver allocates {numports} struct tty
	objects in a single block (digi_softc.ttys) and creates a
	reference to individual tty objects for each port.  This fix
	removes the 'ttys' field from the digi_softc and initialises
	the tty reference in each port using ttymalloc(9).  Other
	references to digi_softc.ttys[i] are changed to digi_softc.ports[i].tp
	and the cleanup code has be changed to call ttyrel(9) instead
	of just freeing the memory.

Index: digi.c
===================================================================
RCS file: /usr/ncvs/src/sys/dev/digi/digi.c,v
retrieving revision 1.55
diff -u -r1.55 digi.c
--- digi.c	28 Jul 2004 21:06:13 -0000	1.55
+++ digi.c	7 Oct 2004 01:49:36 -0000
@@ -538,16 +538,14 @@
 		device_printf(sc->dev, "%s, %d ports found\n", sc->name,
 		    sc->numports);
 
-	if (sc->ports)
+	if (sc->ports) {
+		for (i = 0; i < sc->numports; i++)
+			ttyrel(sc->ports[i].tp);
 		free(sc->ports, M_TTYS);
+	}
 	sc->ports = malloc(sizeof(struct digi_p) * sc->numports,
 	    M_TTYS, M_WAITOK | M_ZERO);
 
-	if (sc->ttys)
-		free(sc->ttys, M_TTYS);
-	sc->ttys = malloc(sizeof(struct tty) * sc->numports,
-	    M_TTYS, M_WAITOK | M_ZERO);
-
 	/*
 	 * XXX Should read port 0xc90 for an array of 2byte values, 1 per
 	 * port.  If the value is 0, the port is broken....
@@ -567,7 +565,7 @@
 		port->pnum = i;
 		port->sc = sc;
 		port->status = ENABLED;
-		port->tp = sc->ttys + i;
+		port->tp = ttymalloc(NULL);
 		port->bc = bc;
 
 		if (sc->model == PCXEVE) {
@@ -958,7 +956,7 @@
 
 	sc = (struct digi_softc *)devclass_get_softc(digi_devclass, unit);
 	KASSERT(sc, ("digi%d: softc not allocated in digiclose\n", unit));
-	tp = &sc->ttys[pnum];
+	tp = sc->ports[pnum].tp;
 
 	error = ttyld_read(tp, uio, flag);
 	DLOG(DIGIDB_READ, (sc->dev, "port %d: read() returns %d\n",
@@ -984,7 +982,7 @@
 
 	sc = (struct digi_softc *)devclass_get_softc(digi_devclass, unit);
 	KASSERT(sc, ("digi%d: softc not allocated in digiclose\n", unit));
-	tp = &sc->ttys[pnum];
+	tp = sc->ports[pnum].tp;
 
 	error = ttyld_write(tp, uio, flag);
 	DLOG(DIGIDB_WRITE, (sc->dev, "port %d: write() returns %d\n",
@@ -1829,7 +1827,7 @@
 	int i;
 
 	for (i = 0; i < sc->numports; i++)
-		if (sc->ttys[i].t_state & TS_ISOPEN) {
+		if (sc->ports[i].tp->t_state & TS_ISOPEN) {
 			DLOG(DIGIDB_INIT, (sc->dev, "port%d: busy\n", i));
 			return (1);
 		} else if (sc->ports[i].wopeners || sc->ports[i].opencnt) {
@@ -1866,11 +1864,10 @@
 #endif
 	if (sc->numports) {
 		KASSERT(sc->ports, ("digi%d: Lost my ports ?", sc->res.unit));
-		KASSERT(sc->ttys, ("digi%d: Lost my ttys ?", sc->res.unit));
+		for (i = 0; i < sc->numports; i++)
+			ttyrel(sc->ports[i].tp);
 		free(sc->ports, M_TTYS);
 		sc->ports = NULL;
-		free(sc->ttys, M_TTYS);
-		sc->ttys = NULL;
 		sc->numports = 0;
 	}
 
Index: digi.h
===================================================================
RCS file: /usr/ncvs/src/sys/dev/digi/digi.h,v
retrieving revision 1.17
diff -u -r1.17 digi.h
--- digi.h	11 Jul 2004 15:18:37 -0000	1.17
+++ digi.h	7 Oct 2004 01:49:42 -0000
@@ -177,7 +177,6 @@
 #endif
 
 	struct digi_p *ports;	/* pointer to array of port descriptors */
-	struct tty *ttys;	/* pointer to array of TTY structures */
 	volatile struct global_data *gdata;
 	u_char window;		/* saved window */
 	int win_size;

>Release-Note:
>Audit-Trail:
>Unformatted: