diff options
author | Christoph Hellwig <hch@lst.de> | 2007-02-10 04:46:46 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-02-11 14:18:07 -0500 |
commit | d5698c28b6e4711e4747bf155f69936208d60e28 (patch) | |
tree | f11e7a8892a4ff218dc9a9789dbb77754ccb61f6 /drivers/char | |
parent | 4b98d11b40f03382918796f3c5c936d5495d20a4 (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')
-rw-r--r-- | drivers/char/tty_io.c | 73 |
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 *); | |||
154 | int tty_ioctl(struct inode * inode, struct file * file, | 154 | int tty_ioctl(struct inode * inode, struct file * file, |
155 | unsigned int cmd, unsigned long arg); | 155 | unsigned int cmd, unsigned long arg); |
156 | static int tty_fasync(int fd, struct file * filp, int on); | 156 | static int tty_fasync(int fd, struct file * filp, int on); |
157 | static void release_mem(struct tty_struct *tty, int idx); | 157 | static 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 */ |
2098 | release_mem_out: | 2098 | release_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 | 2119 | static void release_one_tty(struct tty_struct *tty, int idx) | |
2120 | static 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 | */ | ||
2162 | static 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 */ |