summaryrefslogtreecommitdiffstats
path: root/sys/kern
diff options
context:
space:
mode:
authorjhb <jhb@FreeBSD.org>2008-08-04 19:51:23 +0000
committerjhb <jhb@FreeBSD.org>2008-08-04 19:51:23 +0000
commit11d83a7f893aefb63e7fe739e664381bb499d3fb (patch)
tree7829ca3d3beabb104e02a4c2ac2b873729b21443 /sys/kern
parente6ae2f5414dbb59a0d5f60290194dfa8ab1472e5 (diff)
downloadFreeBSD-src-11d83a7f893aefb63e7fe739e664381bb499d3fb.zip
FreeBSD-src-11d83a7f893aefb63e7fe739e664381bb499d3fb.tar.gz
Close two different races with concurrent opens of pty master devices
that could result in leaked ttys or a leaked pty + tty pair. MFC after: 1 week
Diffstat (limited to 'sys/kern')
-rw-r--r--sys/kern/tty_pty.c29
1 files changed, 24 insertions, 5 deletions
diff --git a/sys/kern/tty_pty.c b/sys/kern/tty_pty.c
index 5d28fe6..3827e82 100644
--- a/sys/kern/tty_pty.c
+++ b/sys/kern/tty_pty.c
@@ -100,6 +100,9 @@ static struct cdevsw ptc_cdevsw = {
.d_flags = D_TTY | D_NEEDGIANT,
};
+static struct mtx ptyinit_lock;
+MTX_SYSINIT(ptyinit_lock, &ptyinit_lock, "ptyinit", MTX_DEF);
+
#define BUFSIZ 100 /* Chunk size iomoved to/from user */
struct ptsc {
@@ -151,8 +154,16 @@ ptyinit(struct cdev *devc, struct thread *td)
pt->pt_tty = ttyalloc();
pt->pt_tty->t_sc = pt;
- devc->si_drv1 = pt;
- devc->si_tty = pt->pt_tty;
+ mtx_lock(&ptyinit_lock);
+ if (devc->si_drv1 == NULL) {
+ devc->si_drv1 = pt;
+ devc->si_tty = pt->pt_tty;
+ mtx_unlock(&ptyinit_lock);
+ } else {
+ mtx_unlock(&ptyinit_lock);
+ ttyrel(pt->pt_tty);
+ free(pt, M_PTY);
+ }
return (devc);
}
@@ -335,9 +346,17 @@ ptcopen(struct cdev *dev, int flag, int devtype, struct thread *td)
* we need to recreate it.
*/
if (pt->pt_tty == NULL) {
- pt->pt_tty = ttyalloc();
- pt->pt_tty->t_sc = pt;
- dev->si_tty = pt->pt_tty;
+ tp = ttyalloc();
+ mtx_lock(&ptyinit_lock);
+ if (pt->pt_tty == NULL) {
+ pt->pt_tty = tp;
+ pt->pt_tty->t_sc = pt;
+ dev->si_tty = pt->pt_tty;
+ mtx_unlock(&ptyinit_lock);
+ } else {
+ mtx_unlock(&ptyinit_lock);
+ ttyrel(tp);
+ }
}
tp = dev->si_tty;
OpenPOWER on IntegriCloud