aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/tty
diff options
context:
space:
mode:
authorAlan Cox <alan@linux.intel.com>2012-07-27 13:02:54 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-07-27 14:55:59 -0400
commitd155255a344c417acad74156654295a2964e6b81 (patch)
tree71f7c39fda7d71980a64a5e1e35c08cf5c948820 /drivers/tty
parent373f5aedbc6fb73d30f00eeb0dc7313ecfede908 (diff)
tty: Fix race in tty release
Ian Abbott found that the tty layer would explode with the right set of parallel open and close operations. This is because we race in the handling of tty->drivers->termios[]. Correct this by Making tty_ldisc_release behave like nromal code (takes the lock, does stuff, drops the lock) Drop the tty lock earlier in tty_ldisc_release Taking the tty mutex around the driver->termios update in all cases Adding a WARN_ON to catch future screwups. I also forgot to clean up the pty resources properly. With a pty pair we need to pull both halves out of the tables. Signed-off-by: Alan Cox <alan@linux.intel.com> Tested-by: Ian Abbott <abbotti@mev.co.uk> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/tty')
-rw-r--r--drivers/tty/pty.c25
-rw-r--r--drivers/tty/tty_io.c20
-rw-r--r--drivers/tty/tty_ldisc.c3
3 files changed, 37 insertions, 11 deletions
diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c
index 60c08ce83782..d6579a9064c4 100644
--- a/drivers/tty/pty.c
+++ b/drivers/tty/pty.c
@@ -282,6 +282,17 @@ done:
282 return 0; 282 return 0;
283} 283}
284 284
285/**
286 * pty_common_install - set up the pty pair
287 * @driver: the pty driver
288 * @tty: the tty being instantiated
289 * @bool: legacy, true if this is BSD style
290 *
291 * Perform the initial set up for the tty/pty pair. Called from the
292 * tty layer when the port is first opened.
293 *
294 * Locking: the caller must hold the tty_mutex
295 */
285static int pty_common_install(struct tty_driver *driver, struct tty_struct *tty, 296static int pty_common_install(struct tty_driver *driver, struct tty_struct *tty,
286 bool legacy) 297 bool legacy)
287{ 298{
@@ -364,6 +375,14 @@ static int pty_install(struct tty_driver *driver, struct tty_struct *tty)
364 return pty_common_install(driver, tty, true); 375 return pty_common_install(driver, tty, true);
365} 376}
366 377
378static void pty_remove(struct tty_driver *driver, struct tty_struct *tty)
379{
380 struct tty_struct *pair = tty->link;
381 driver->ttys[tty->index] = NULL;
382 if (pair)
383 pair->driver->ttys[pair->index] = NULL;
384}
385
367static int pty_bsd_ioctl(struct tty_struct *tty, 386static int pty_bsd_ioctl(struct tty_struct *tty,
368 unsigned int cmd, unsigned long arg) 387 unsigned int cmd, unsigned long arg)
369{ 388{
@@ -395,7 +414,8 @@ static const struct tty_operations master_pty_ops_bsd = {
395 .set_termios = pty_set_termios, 414 .set_termios = pty_set_termios,
396 .ioctl = pty_bsd_ioctl, 415 .ioctl = pty_bsd_ioctl,
397 .cleanup = pty_cleanup, 416 .cleanup = pty_cleanup,
398 .resize = pty_resize 417 .resize = pty_resize,
418 .remove = pty_remove
399}; 419};
400 420
401static const struct tty_operations slave_pty_ops_bsd = { 421static const struct tty_operations slave_pty_ops_bsd = {
@@ -409,7 +429,8 @@ static const struct tty_operations slave_pty_ops_bsd = {
409 .unthrottle = pty_unthrottle, 429 .unthrottle = pty_unthrottle,
410 .set_termios = pty_set_termios, 430 .set_termios = pty_set_termios,
411 .cleanup = pty_cleanup, 431 .cleanup = pty_cleanup,
412 .resize = pty_resize 432 .resize = pty_resize,
433 .remove = pty_remove
413}; 434};
414 435
415static void __init legacy_pty_init(void) 436static void __init legacy_pty_init(void)
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
index be18d60ddf4c..c6f4d711771b 100644
--- a/drivers/tty/tty_io.c
+++ b/drivers/tty/tty_io.c
@@ -1465,7 +1465,6 @@ EXPORT_SYMBOL(tty_free_termios);
1465 * in use. It also gets called when setup of a device fails. 1465 * in use. It also gets called when setup of a device fails.
1466 * 1466 *
1467 * Locking: 1467 * Locking:
1468 * tty_mutex - sometimes only
1469 * takes the file list lock internally when working on the list 1468 * takes the file list lock internally when working on the list
1470 * of ttys that the driver keeps. 1469 * of ttys that the driver keeps.
1471 * 1470 *
@@ -1526,17 +1525,16 @@ EXPORT_SYMBOL(tty_kref_put);
1526 * and decrement the refcount of the backing module. 1525 * and decrement the refcount of the backing module.
1527 * 1526 *
1528 * Locking: 1527 * Locking:
1529 * tty_mutex - sometimes only 1528 * tty_mutex
1530 * takes the file list lock internally when working on the list 1529 * takes the file list lock internally when working on the list
1531 * of ttys that the driver keeps. 1530 * of ttys that the driver keeps.
1532 * FIXME: should we require tty_mutex is held here ??
1533 * 1531 *
1534 */ 1532 */
1535static void release_tty(struct tty_struct *tty, int idx) 1533static void release_tty(struct tty_struct *tty, int idx)
1536{ 1534{
1537 /* This should always be true but check for the moment */ 1535 /* This should always be true but check for the moment */
1538 WARN_ON(tty->index != idx); 1536 WARN_ON(tty->index != idx);
1539 1537 WARN_ON(!mutex_is_locked(&tty_mutex));
1540 if (tty->ops->shutdown) 1538 if (tty->ops->shutdown)
1541 tty->ops->shutdown(tty); 1539 tty->ops->shutdown(tty);
1542 tty_free_termios(tty); 1540 tty_free_termios(tty);
@@ -1708,6 +1706,9 @@ int tty_release(struct inode *inode, struct file *filp)
1708 * The closing flags are now consistent with the open counts on 1706 * The closing flags are now consistent with the open counts on
1709 * both sides, and we've completed the last operation that could 1707 * both sides, and we've completed the last operation that could
1710 * block, so it's safe to proceed with closing. 1708 * block, so it's safe to proceed with closing.
1709 *
1710 * We must *not* drop the tty_mutex until we ensure that a further
1711 * entry into tty_open can not pick up this tty.
1711 */ 1712 */
1712 if (pty_master) { 1713 if (pty_master) {
1713 if (--o_tty->count < 0) { 1714 if (--o_tty->count < 0) {
@@ -1759,12 +1760,13 @@ int tty_release(struct inode *inode, struct file *filp)
1759 } 1760 }
1760 1761
1761 mutex_unlock(&tty_mutex); 1762 mutex_unlock(&tty_mutex);
1763 tty_unlock();
1764 /* At this point the TTY_CLOSING flag should ensure a dead tty
1765 cannot be re-opened by a racing opener */
1762 1766
1763 /* check whether both sides are closing ... */ 1767 /* check whether both sides are closing ... */
1764 if (!tty_closing || (o_tty && !o_tty_closing)) { 1768 if (!tty_closing || (o_tty && !o_tty_closing))
1765 tty_unlock();
1766 return 0; 1769 return 0;
1767 }
1768 1770
1769#ifdef TTY_DEBUG_HANGUP 1771#ifdef TTY_DEBUG_HANGUP
1770 printk(KERN_DEBUG "%s: freeing tty structure...\n", __func__); 1772 printk(KERN_DEBUG "%s: freeing tty structure...\n", __func__);
@@ -1777,12 +1779,14 @@ int tty_release(struct inode *inode, struct file *filp)
1777 * The release_tty function takes care of the details of clearing 1779 * The release_tty function takes care of the details of clearing
1778 * the slots and preserving the termios structure. 1780 * the slots and preserving the termios structure.
1779 */ 1781 */
1782 mutex_lock(&tty_mutex);
1780 release_tty(tty, idx); 1783 release_tty(tty, idx);
1784 mutex_unlock(&tty_mutex);
1781 1785
1782 /* Make this pty number available for reallocation */ 1786 /* Make this pty number available for reallocation */
1783 if (devpts) 1787 if (devpts)
1784 devpts_kill_index(inode, idx); 1788 devpts_kill_index(inode, idx);
1785 tty_unlock(); 1789
1786 return 0; 1790 return 0;
1787} 1791}
1788 1792
diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c
index e6156c60d190..3d0687197d09 100644
--- a/drivers/tty/tty_ldisc.c
+++ b/drivers/tty/tty_ldisc.c
@@ -912,7 +912,6 @@ void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty)
912 * race with the set_ldisc code path. 912 * race with the set_ldisc code path.
913 */ 913 */
914 914
915 tty_unlock();
916 tty_ldisc_halt(tty); 915 tty_ldisc_halt(tty);
917 tty_ldisc_flush_works(tty); 916 tty_ldisc_flush_works(tty);
918 tty_lock(); 917 tty_lock();
@@ -930,6 +929,8 @@ void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty)
930 tty_set_termios_ldisc(tty, N_TTY); 929 tty_set_termios_ldisc(tty, N_TTY);
931 mutex_unlock(&tty->ldisc_mutex); 930 mutex_unlock(&tty->ldisc_mutex);
932 931
932 tty_unlock();
933
933 /* This will need doing differently if we need to lock */ 934 /* This will need doing differently if we need to lock */
934 if (o_tty) 935 if (o_tty)
935 tty_ldisc_release(o_tty, NULL); 936 tty_ldisc_release(o_tty, NULL);