The dev_refthread() in the tty_gettp() may fail, because Giant is taken

in the giant_trick routines after the dev_refthread increments the
si_threadcount. Remove assert, do not perform dev_relthread() for failed
dev_refthread(), and handle failure in the tty_gettp() callers (cdevsw
tty methods).

Before kern_conf.c 1.210 and 1.211, the kernel usually paniced in the
giant_trick routines dereferencing NULL cdevsw, not taking this fault.

Reported by:	Vince Hoffman <jhary unsane co uk>
Debugging help and tested by:	pho
Reviewed by:	jhb
MFC after:	1 week
This commit is contained in:
Konstantin Belousov 2008-05-23 16:46:27 +00:00
parent ca091c56e3
commit cc57af357b

View File

@ -270,11 +270,12 @@ tty_gettp(struct cdev *dev)
struct cdevsw *csw;
csw = dev_refthread(dev);
KASSERT(csw != NULL, ("No cdevsw in ttycode (%s)", devtoname(dev)));
if (csw == NULL)
return (NULL);
KASSERT(csw->d_flags & D_TTY,
("non D_TTY (%s) in tty code", devtoname(dev)));
dev_relthread(dev);
tp = dev->si_tty;
dev_relthread(dev);
KASSERT(tp != NULL,
("no tty pointer on (%s) in tty code", devtoname(dev)));
return (tp);
@ -1325,7 +1326,7 @@ ttykqfilter(struct cdev *dev, struct knote *kn)
int s;
tp = tty_gettp(dev);
if (tp->t_state & TS_GONE)
if (tp == NULL || (tp->t_state & TS_GONE))
return (ENODEV);
switch (kn->kn_filter) {
@ -3255,7 +3256,7 @@ ttyread(struct cdev *dev, struct uio *uio, int flag)
tp = tty_gettp(dev);
if (tp->t_state & TS_GONE)
if (tp == NULL || (tp->t_state & TS_GONE))
return (ENODEV);
return (ttyld_read(tp, uio, flag));
}
@ -3267,7 +3268,7 @@ ttywrite(struct cdev *dev, struct uio *uio, int flag)
tp = tty_gettp(dev);
if (tp->t_state & TS_GONE)
if (tp == NULL || (tp->t_state & TS_GONE))
return (ENODEV);
return (ttyld_write(tp, uio, flag));
}