aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorPaul Fulghum <paulkf@microgate.com>2006-02-14 16:53:00 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2006-02-14 19:09:33 -0500
commitda965822abd18a17d7cffe1d511f48951c82dfb6 (patch)
treeb5a64fd33374661dbc689d3192a5c9134b3672e5 /drivers
parent16bf134840da3920ded1290973c56ec214636f12 (diff)
[PATCH] tty reference count fix
Fix hole where tty structure can be released when reference count is non zero. Existing code can sleep without tty_sem protection between deciding to release the tty structure (setting local variables tty_closing and otty_closing) and setting TTY_CLOSING to prevent further opens. An open can occur during this interval causing release_dev() to free the tty structure while it is still referenced. This should fix bugzilla.kernel.org [Bug 6041] New: Unable to handle kernel paging request In Bug 6041, tty_open() oopes on accessing the tty structure it has successfully claimed. Bug was on SMP machine with the same tty being opened and closed by multiple processes, and DEBUG_PAGEALLOC enabled. Signed-off-by: Paul Fulghum <paulkf@microgate.com> Cc: Alan Cox <alan@lxorguk.ukuu.org.uk> Cc: Jesper Juhl <jesper.juhl@gmail.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/char/tty_io.c7
1 files changed, 3 insertions, 4 deletions
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index a23816d3e9a1..e9bba94fc898 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -1841,7 +1841,6 @@ static void release_dev(struct file * filp)
1841 tty_closing = tty->count <= 1; 1841 tty_closing = tty->count <= 1;
1842 o_tty_closing = o_tty && 1842 o_tty_closing = o_tty &&
1843 (o_tty->count <= (pty_master ? 1 : 0)); 1843 (o_tty->count <= (pty_master ? 1 : 0));
1844 up(&tty_sem);
1845 do_sleep = 0; 1844 do_sleep = 0;
1846 1845
1847 if (tty_closing) { 1846 if (tty_closing) {
@@ -1869,6 +1868,7 @@ static void release_dev(struct file * filp)
1869 1868
1870 printk(KERN_WARNING "release_dev: %s: read/write wait queue " 1869 printk(KERN_WARNING "release_dev: %s: read/write wait queue "
1871 "active!\n", tty_name(tty, buf)); 1870 "active!\n", tty_name(tty, buf));
1871 up(&tty_sem);
1872 schedule(); 1872 schedule();
1873 } 1873 }
1874 1874
@@ -1877,8 +1877,6 @@ static void release_dev(struct file * filp)
1877 * both sides, and we've completed the last operation that could 1877 * both sides, and we've completed the last operation that could
1878 * block, so it's safe to proceed with closing. 1878 * block, so it's safe to proceed with closing.
1879 */ 1879 */
1880
1881 down(&tty_sem);
1882 if (pty_master) { 1880 if (pty_master) {
1883 if (--o_tty->count < 0) { 1881 if (--o_tty->count < 0) {
1884 printk(KERN_WARNING "release_dev: bad pty slave count " 1882 printk(KERN_WARNING "release_dev: bad pty slave count "
@@ -1892,7 +1890,6 @@ static void release_dev(struct file * filp)
1892 tty->count, tty_name(tty, buf)); 1890 tty->count, tty_name(tty, buf));
1893 tty->count = 0; 1891 tty->count = 0;
1894 } 1892 }
1895 up(&tty_sem);
1896 1893
1897 /* 1894 /*
1898 * We've decremented tty->count, so we need to remove this file 1895 * We've decremented tty->count, so we need to remove this file
@@ -1937,6 +1934,8 @@ static void release_dev(struct file * filp)
1937 read_unlock(&tasklist_lock); 1934 read_unlock(&tasklist_lock);
1938 } 1935 }
1939 1936
1937 up(&tty_sem);
1938
1940 /* check whether both sides are closing ... */ 1939 /* check whether both sides are closing ... */
1941 if (!tty_closing || (o_tty && !o_tty_closing)) 1940 if (!tty_closing || (o_tty && !o_tty_closing))
1942 return; 1941 return;