diff options
author | jhb <jhb@FreeBSD.org> | 2008-08-04 19:51:23 +0000 |
---|---|---|
committer | jhb <jhb@FreeBSD.org> | 2008-08-04 19:51:23 +0000 |
commit | 11d83a7f893aefb63e7fe739e664381bb499d3fb (patch) | |
tree | 7829ca3d3beabb104e02a4c2ac2b873729b21443 | |
parent | e6ae2f5414dbb59a0d5f60290194dfa8ab1472e5 (diff) | |
download | FreeBSD-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
-rw-r--r-- | sys/kern/tty_pty.c | 29 |
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; |