Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[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>

authored by

Paul Fulghum and committed by
Linus Torvalds
da965822 16bf1348

+3 -4
+3 -4
drivers/char/tty_io.c
··· 1841 1841 tty_closing = tty->count <= 1; 1842 1842 o_tty_closing = o_tty && 1843 1843 (o_tty->count <= (pty_master ? 1 : 0)); 1844 - up(&tty_sem); 1845 1844 do_sleep = 0; 1846 1845 1847 1846 if (tty_closing) { ··· 1868 1869 1869 1870 printk(KERN_WARNING "release_dev: %s: read/write wait queue " 1870 1871 "active!\n", tty_name(tty, buf)); 1872 + up(&tty_sem); 1871 1873 schedule(); 1872 1874 } 1873 1875 ··· 1877 1877 * both sides, and we've completed the last operation that could 1878 1878 * block, so it's safe to proceed with closing. 1879 1879 */ 1880 - 1881 - down(&tty_sem); 1882 1880 if (pty_master) { 1883 1881 if (--o_tty->count < 0) { 1884 1882 printk(KERN_WARNING "release_dev: bad pty slave count " ··· 1890 1892 tty->count, tty_name(tty, buf)); 1891 1893 tty->count = 0; 1892 1894 } 1893 - up(&tty_sem); 1894 1895 1895 1896 /* 1896 1897 * We've decremented tty->count, so we need to remove this file ··· 1933 1936 } while_each_task_pid(o_tty->session, PIDTYPE_SID, p); 1934 1937 read_unlock(&tasklist_lock); 1935 1938 } 1939 + 1940 + up(&tty_sem); 1936 1941 1937 1942 /* check whether both sides are closing ... */ 1938 1943 if (!tty_closing || (o_tty && !o_tty_closing))