diff options
author | Jiri Slaby <jslaby@suse.cz> | 2012-04-13 04:31:32 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-04-13 13:54:43 -0400 |
commit | a2f892060f174e5f90041167ca00eb9e68badcb8 (patch) | |
tree | daf87a58266da05e2e8a3f06538df2cfd360d3bc /drivers/tty/hvc | |
parent | 59d59b0600e541b4e94b891148c92f2e2d18f7c0 (diff) |
TTY: hvc, fix TTY refcounting
A -next commit "TTY: HVC, use tty from tty_port" switched the driver
to use tty_port helper for tty refcounting. But it omitted to remove
manual tty refcounting from open, close and hangup. So now we are
getting random crashes caused by use-after-free:
Unable to handle kernel paging request for data at address 0xc0000003f9d550
Faulting instruction address: 0xc0000000001b7f40
Oops: Kernel access of bad area, sig: 11 [#1]
...
NIP: c0000000001b7f40 LR: c0000000001b7f14 CTR: c0000000000e04f0
...
NIP [c0000000001b7f40] .__kmalloc+0x70/0x230
LR [c0000000001b7f14] .__kmalloc+0x44/0x230
Call Trace:
[c0000003f68bf930] [c0000003f68bf9b0] 0xc0000003f68bf9b0 (unreliable)
[c0000003f68bf9e0] [c0000000001e5424] .alloc_fdmem+0x24/0x70
[c0000003f68bfa60] [c0000000001e54f8] .alloc_fdtable+0x88/0x130
[c0000003f68bfaf0] [c0000000001e5924] .dup_fd+0x384/0x450
[c0000003f68bfbd0] [c00000000009a310] .copy_process+0x880/0x11d0
[c0000003f68bfcd0] [c00000000009aee0] .do_fork+0x70/0x400
[c0000003f68bfdc0] [c0000000000141c4] .sys_clone+0x54/0x70
[c0000003f68bfe30] [c000000000009aa0] .ppc_clone+0x8/0xc
Fix that by complete removal of tty_kref_get/put in open/close/hangup
paths.
Signed-off-by: Jiri Slaby <jslaby@suse.cz>
Reported-and-tested-by: Michael Neuling <mikey@neuling.org>
Cc: Stephen Rothwell <sfr@canb.auug.org.au>
Cc: ppc-dev <linuxppc-dev@lists.ozlabs.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/tty/hvc')
-rw-r--r-- | drivers/tty/hvc/hvc_console.c | 5 |
1 files changed, 0 insertions, 5 deletions
diff --git a/drivers/tty/hvc/hvc_console.c b/drivers/tty/hvc/hvc_console.c index 6c45cbf3fc91..2d691eb7c40a 100644 --- a/drivers/tty/hvc/hvc_console.c +++ b/drivers/tty/hvc/hvc_console.c | |||
@@ -317,8 +317,6 @@ static int hvc_open(struct tty_struct *tty, struct file * filp) | |||
317 | /* Check and then increment for fast path open. */ | 317 | /* Check and then increment for fast path open. */ |
318 | if (hp->port.count++ > 0) { | 318 | if (hp->port.count++ > 0) { |
319 | spin_unlock_irqrestore(&hp->port.lock, flags); | 319 | spin_unlock_irqrestore(&hp->port.lock, flags); |
320 | /* FIXME why taking a reference here? */ | ||
321 | tty_kref_get(tty); | ||
322 | hvc_kick(); | 320 | hvc_kick(); |
323 | return 0; | 321 | return 0; |
324 | } /* else count == 0 */ | 322 | } /* else count == 0 */ |
@@ -338,7 +336,6 @@ static int hvc_open(struct tty_struct *tty, struct file * filp) | |||
338 | */ | 336 | */ |
339 | if (rc) { | 337 | if (rc) { |
340 | tty_port_tty_set(&hp->port, NULL); | 338 | tty_port_tty_set(&hp->port, NULL); |
341 | tty_kref_put(tty); | ||
342 | tty->driver_data = NULL; | 339 | tty->driver_data = NULL; |
343 | tty_port_put(&hp->port); | 340 | tty_port_put(&hp->port); |
344 | printk(KERN_ERR "hvc_open: request_irq failed with rc %d.\n", rc); | 341 | printk(KERN_ERR "hvc_open: request_irq failed with rc %d.\n", rc); |
@@ -393,7 +390,6 @@ static void hvc_close(struct tty_struct *tty, struct file * filp) | |||
393 | spin_unlock_irqrestore(&hp->port.lock, flags); | 390 | spin_unlock_irqrestore(&hp->port.lock, flags); |
394 | } | 391 | } |
395 | 392 | ||
396 | tty_kref_put(tty); | ||
397 | tty_port_put(&hp->port); | 393 | tty_port_put(&hp->port); |
398 | } | 394 | } |
399 | 395 | ||
@@ -433,7 +429,6 @@ static void hvc_hangup(struct tty_struct *tty) | |||
433 | 429 | ||
434 | while(temp_open_count) { | 430 | while(temp_open_count) { |
435 | --temp_open_count; | 431 | --temp_open_count; |
436 | tty_kref_put(tty); | ||
437 | tty_port_put(&hp->port); | 432 | tty_port_put(&hp->port); |
438 | } | 433 | } |
439 | } | 434 | } |