diff options
| author | Paul Fulghum <paulkf@microgate.com> | 2006-02-14 16:53:00 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-02-14 19:09:33 -0500 |
| commit | da965822abd18a17d7cffe1d511f48951c82dfb6 (patch) | |
| tree | b5a64fd33374661dbc689d3192a5c9134b3672e5 | |
| parent | 16bf134840da3920ded1290973c56ec214636f12 (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>
| -rw-r--r-- | drivers/char/tty_io.c | 7 |
1 files changed, 3 insertions, 4 deletions
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index a23816d3e9..e9bba94fc8 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; |
