summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authornicm <nicm@openbsd.org>2013-04-24 09:52:54 +0000
committernicm <nicm@openbsd.org>2013-04-24 09:52:54 +0000
commitbe2adc8d83fea254ed38697f5d81723c72bf3e3b (patch)
tree84ba24044aaac306c6c41283dae5c0456e3cb684
parentWhen attaching disks, feed the disklabel's checksum to (diff)
downloadwireguard-openbsd-be2adc8d83fea254ed38697f5d81723c72bf3e3b.tar.xz
wireguard-openbsd-be2adc8d83fea254ed38697f5d81723c72bf3e3b.zip
When a ucom(4) is removed, it frees the tty with ttyfree(). However if
anyone is waiting with kqueue their knotes may still have a reference to the tty and later try to use it in the filt_tty* functions. To avoid this, walk the knotes in ttyfree(), remove them from the tty's list and invalidate them by setting kn_hook to NODEV. The filter functions can then check for this and safely ignore the knotes. ok tedu matthieu
-rw-r--r--sys/kern/kern_event.c11
-rw-r--r--sys/kern/tty.c53
-rw-r--r--sys/sys/event.h3
3 files changed, 58 insertions, 9 deletions
diff --git a/sys/kern/kern_event.c b/sys/kern/kern_event.c
index dc99aa7b449..9a57e8e6672 100644
--- a/sys/kern/kern_event.c
+++ b/sys/kern/kern_event.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kern_event.c,v 1.48 2012/07/08 17:21:08 guenther Exp $ */
+/* $OpenBSD: kern_event.c,v 1.49 2013/04/24 09:52:54 nicm Exp $ */
/*-
* Copyright (c) 1999,2000,2001 Jonathan Lemon <jlemon@FreeBSD.org>
@@ -941,6 +941,15 @@ kqueue_wakeup(struct kqueue *kq)
}
/*
+ * activate one knote.
+ */
+void
+knote_activate(struct knote *kn)
+{
+ KNOTE_ACTIVATE(kn);
+}
+
+/*
* walk down a list of knotes, activating them if their event has triggered.
*/
void
diff --git a/sys/kern/tty.c b/sys/kern/tty.c
index 45f7283658c..48e3ed66f7d 100644
--- a/sys/kern/tty.c
+++ b/sys/kern/tty.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: tty.c,v 1.96 2013/01/17 21:24:58 deraadt Exp $ */
+/* $OpenBSD: tty.c,v 1.97 2013/04/24 09:52:54 nicm Exp $ */
/* $NetBSD: tty.c,v 1.68.4.2 1996/06/06 16:04:52 thorpej Exp $ */
/*-
@@ -71,6 +71,7 @@ void ttyunblock(struct tty *);
static void ttyecho(int, struct tty *);
static void ttyrubo(struct tty *, int);
static int proc_compare(struct proc *, struct proc *);
+void ttkqflush(struct klist *klist);
int filt_ttyread(struct knote *kn, long hint);
void filt_ttyrdetach(struct knote *kn);
int filt_ttywrite(struct knote *kn, long hint);
@@ -1113,12 +1114,30 @@ ttkqfilter(dev_t dev, struct knote *kn)
}
void
+ttkqflush(struct klist *klist)
+{
+ struct knote *kn, *kn1;
+
+ SLIST_FOREACH_SAFE(kn, klist, kn_selnext, kn1) {
+ SLIST_REMOVE(klist, kn, knote, kn_selnext);
+ kn->kn_hook = (caddr_t)((u_long)NODEV);
+ kn->kn_flags |= EV_EOF;
+ knote_activate(kn);
+ }
+}
+
+void
filt_ttyrdetach(struct knote *kn)
{
dev_t dev = (dev_t)((u_long)kn->kn_hook);
- struct tty *tp = (*cdevsw[major(dev)].d_tty)(dev);
- int s = spltty();
+ struct tty *tp;
+ int s;
+
+ if (dev == NODEV)
+ return;
+ tp = (*cdevsw[major(dev)].d_tty)(dev);
+ s = spltty();
SLIST_REMOVE(&tp->t_rsel.si_note, kn, knote, kn_selnext);
splx(s);
}
@@ -1127,9 +1146,15 @@ int
filt_ttyread(struct knote *kn, long hint)
{
dev_t dev = (dev_t)((u_long)kn->kn_hook);
- struct tty *tp = (*cdevsw[major(dev)].d_tty)(dev);
+ struct tty *tp;
int s;
+ if (dev == NODEV) {
+ kn->kn_flags |= EV_EOF;
+ return (1);
+ }
+ tp = (*cdevsw[major(dev)].d_tty)(dev);
+
s = spltty();
kn->kn_data = ttnread(tp);
splx(s);
@@ -1144,9 +1169,14 @@ void
filt_ttywdetach(struct knote *kn)
{
dev_t dev = (dev_t)((u_long)kn->kn_hook);
- struct tty *tp = (*cdevsw[major(dev)].d_tty)(dev);
- int s = spltty();
+ struct tty *tp;
+ int s;
+
+ if (dev == NODEV)
+ return;
+ tp = (*cdevsw[major(dev)].d_tty)(dev);
+ s = spltty();
SLIST_REMOVE(&tp->t_wsel.si_note, kn, knote, kn_selnext);
splx(s);
}
@@ -1155,9 +1185,15 @@ int
filt_ttywrite(struct knote *kn, long hint)
{
dev_t dev = (dev_t)((u_long)kn->kn_hook);
- struct tty *tp = (*cdevsw[major(dev)].d_tty)(dev);
+ struct tty *tp;
int canwrite, s;
+ if (dev == NODEV) {
+ kn->kn_flags |= EV_EOF;
+ return (1);
+ }
+ tp = (*cdevsw[major(dev)].d_tty)(dev);
+
s = spltty();
kn->kn_data = tp->t_outq.c_cn - tp->t_outq.c_cc;
canwrite = (tp->t_outq.c_cc <= tp->t_lowat);
@@ -2309,6 +2345,9 @@ ttyfree(struct tty *tp)
#endif
TAILQ_REMOVE(&ttylist, tp, tty_link);
+ ttkqflush(&tp->t_rsel.si_note);
+ ttkqflush(&tp->t_wsel.si_note);
+
clfree(&tp->t_rawq);
clfree(&tp->t_canq);
clfree(&tp->t_outq);
diff --git a/sys/sys/event.h b/sys/sys/event.h
index fada3e779cb..96812ab59a2 100644
--- a/sys/sys/event.h
+++ b/sys/sys/event.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: event.h,v 1.17 2012/06/08 05:22:49 guenther Exp $ */
+/* $OpenBSD: event.h,v 1.18 2013/04/24 09:52:54 nicm Exp $ */
/*-
* Copyright (c) 1999,2000,2001 Jonathan Lemon <jlemon@FreeBSD.org>
@@ -167,6 +167,7 @@ struct knote {
struct proc;
extern void knote(struct klist *list, long hint);
+extern void knote_activate(struct knote *);
extern void knote_remove(struct proc *p, struct klist *list);
extern void knote_fdclose(struct proc *p, int fd);
extern void knote_processexit(struct process *);