aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/tty_io.c
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@lst.de>2007-02-10 04:46:46 -0500
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-02-11 14:18:07 -0500
commitd5698c28b6e4711e4747bf155f69936208d60e28 (patch)
treef11e7a8892a4ff218dc9a9789dbb77754ccb61f6 /drivers/char/tty_io.c
parent4b98d11b40f03382918796f3c5c936d5495d20a4 (diff)
[PATCH] tty: cleanup release_mem
release_mem contains two copies of exactly the same code. Refactor these into a new helper, release_tty. The only change in behaviour is that the driver reference count is now decremented after the master tty has been freed instead of before. [penberg@cs.helsinki.fi: fix use-after-free in release_tty.] Cc: Alan Cox <alan@redhat.com> Signed-off-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Pekka Enberg <penberg@cs.helsinki.fi> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/char/tty_io.c')
-rw-r--r--drivers/char/tty_io.c73
1 files changed, 37 insertions, 36 deletions
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index 305e46db70e4..558ca927e32b 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -154,7 +154,7 @@ static int tty_release(struct inode *, struct file *);
154int tty_ioctl(struct inode * inode, struct file * file, 154int tty_ioctl(struct inode * inode, struct file * file,
155 unsigned int cmd, unsigned long arg); 155 unsigned int cmd, unsigned long arg);
156static int tty_fasync(int fd, struct file * filp, int on); 156static int tty_fasync(int fd, struct file * filp, int on);
157static void release_mem(struct tty_struct *tty, int idx); 157static void release_tty(struct tty_struct *tty, int idx);
158 158
159/** 159/**
160 * alloc_tty_struct - allocate a tty object 160 * alloc_tty_struct - allocate a tty object
@@ -2002,7 +2002,7 @@ static int init_dev(struct tty_driver *driver, int idx,
2002 2002
2003 /* 2003 /*
2004 * All structures have been allocated, so now we install them. 2004 * All structures have been allocated, so now we install them.
2005 * Failures after this point use release_mem to clean up, so 2005 * Failures after this point use release_tty to clean up, so
2006 * there's no need to null out the local pointers. 2006 * there's no need to null out the local pointers.
2007 */ 2007 */
2008 if (!(driver->flags & TTY_DRIVER_DEVPTS_MEM)) { 2008 if (!(driver->flags & TTY_DRIVER_DEVPTS_MEM)) {
@@ -2023,8 +2023,8 @@ static int init_dev(struct tty_driver *driver, int idx,
2023 2023
2024 /* 2024 /*
2025 * Structures all installed ... call the ldisc open routines. 2025 * Structures all installed ... call the ldisc open routines.
2026 * If we fail here just call release_mem to clean up. No need 2026 * If we fail here just call release_tty to clean up. No need
2027 * to decrement the use counts, as release_mem doesn't care. 2027 * to decrement the use counts, as release_tty doesn't care.
2028 */ 2028 */
2029 2029
2030 if (tty->ldisc.open) { 2030 if (tty->ldisc.open) {
@@ -2094,17 +2094,17 @@ fail_no_mem:
2094 retval = -ENOMEM; 2094 retval = -ENOMEM;
2095 goto end_init; 2095 goto end_init;
2096 2096
2097 /* call the tty release_mem routine to clean out this slot */ 2097 /* call the tty release_tty routine to clean out this slot */
2098release_mem_out: 2098release_mem_out:
2099 if (printk_ratelimit()) 2099 if (printk_ratelimit())
2100 printk(KERN_INFO "init_dev: ldisc open failed, " 2100 printk(KERN_INFO "init_dev: ldisc open failed, "
2101 "clearing slot %d\n", idx); 2101 "clearing slot %d\n", idx);
2102 release_mem(tty, idx); 2102 release_tty(tty, idx);
2103 goto end_init; 2103 goto end_init;
2104} 2104}
2105 2105
2106/** 2106/**
2107 * release_mem - release tty structure memory 2107 * release_one_tty - release tty structure memory
2108 * 2108 *
2109 * Releases memory associated with a tty structure, and clears out the 2109 * Releases memory associated with a tty structure, and clears out the
2110 * driver table slots. This function is called when a device is no longer 2110 * driver table slots. This function is called when a device is no longer
@@ -2116,37 +2116,14 @@ release_mem_out:
2116 * of ttys that the driver keeps. 2116 * of ttys that the driver keeps.
2117 * FIXME: should we require tty_mutex is held here ?? 2117 * FIXME: should we require tty_mutex is held here ??
2118 */ 2118 */
2119 2119static void release_one_tty(struct tty_struct *tty, int idx)
2120static void release_mem(struct tty_struct *tty, int idx)
2121{ 2120{
2122 struct tty_struct *o_tty;
2123 struct ktermios *tp;
2124 int devpts = tty->driver->flags & TTY_DRIVER_DEVPTS_MEM; 2121 int devpts = tty->driver->flags & TTY_DRIVER_DEVPTS_MEM;
2125 2122 struct ktermios *tp;
2126 if ((o_tty = tty->link) != NULL) {
2127 if (!devpts)
2128 o_tty->driver->ttys[idx] = NULL;
2129 if (o_tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) {
2130 tp = o_tty->termios;
2131 if (!devpts)
2132 o_tty->driver->termios[idx] = NULL;
2133 kfree(tp);
2134
2135 tp = o_tty->termios_locked;
2136 if (!devpts)
2137 o_tty->driver->termios_locked[idx] = NULL;
2138 kfree(tp);
2139 }
2140 o_tty->magic = 0;
2141 o_tty->driver->refcount--;
2142 file_list_lock();
2143 list_del_init(&o_tty->tty_files);
2144 file_list_unlock();
2145 free_tty_struct(o_tty);
2146 }
2147 2123
2148 if (!devpts) 2124 if (!devpts)
2149 tty->driver->ttys[idx] = NULL; 2125 tty->driver->ttys[idx] = NULL;
2126
2150 if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) { 2127 if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) {
2151 tp = tty->termios; 2128 tp = tty->termios;
2152 if (!devpts) 2129 if (!devpts)
@@ -2159,15 +2136,39 @@ static void release_mem(struct tty_struct *tty, int idx)
2159 kfree(tp); 2136 kfree(tp);
2160 } 2137 }
2161 2138
2139
2162 tty->magic = 0; 2140 tty->magic = 0;
2163 tty->driver->refcount--; 2141 tty->driver->refcount--;
2142
2164 file_list_lock(); 2143 file_list_lock();
2165 list_del_init(&tty->tty_files); 2144 list_del_init(&tty->tty_files);
2166 file_list_unlock(); 2145 file_list_unlock();
2167 module_put(tty->driver->owner); 2146
2168 free_tty_struct(tty); 2147 free_tty_struct(tty);
2169} 2148}
2170 2149
2150/**
2151 * release_tty - release tty structure memory
2152 *
2153 * Release both @tty and a possible linked partner (think pty pair),
2154 * and decrement the refcount of the backing module.
2155 *
2156 * Locking:
2157 * tty_mutex - sometimes only
2158 * takes the file list lock internally when working on the list
2159 * of ttys that the driver keeps.
2160 * FIXME: should we require tty_mutex is held here ??
2161 */
2162static void release_tty(struct tty_struct *tty, int idx)
2163{
2164 struct tty_driver *driver = tty->driver;
2165
2166 if (tty->link)
2167 release_one_tty(tty->link, idx);
2168 release_one_tty(tty, idx);
2169 module_put(driver->owner);
2170}
2171
2171/* 2172/*
2172 * Even releasing the tty structures is a tricky business.. We have 2173 * Even releasing the tty structures is a tricky business.. We have
2173 * to be very careful that the structures are all released at the 2174 * to be very careful that the structures are all released at the
@@ -2435,10 +2436,10 @@ static void release_dev(struct file * filp)
2435 tty_set_termios_ldisc(o_tty,N_TTY); 2436 tty_set_termios_ldisc(o_tty,N_TTY);
2436 } 2437 }
2437 /* 2438 /*
2438 * The release_mem function takes care of the details of clearing 2439 * The release_tty function takes care of the details of clearing
2439 * the slots and preserving the termios structure. 2440 * the slots and preserving the termios structure.
2440 */ 2441 */
2441 release_mem(tty, idx); 2442 release_tty(tty, idx);
2442 2443
2443#ifdef CONFIG_UNIX98_PTYS 2444#ifdef CONFIG_UNIX98_PTYS
2444 /* Make this pty number available for reallocation */ 2445 /* Make this pty number available for reallocation */