summaryrefslogtreecommitdiff
path: root/drivers/serial
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2010-05-26 21:17:29 -0700
committerDavid S. Miller <davem@davemloft.net>2010-05-26 21:17:29 -0700
commit9616ff434d96303689391af3d6e1c845d233405f (patch)
treefe467102ce2a59dc2113e8f4da6a4d8185404fda /drivers/serial
parent7c1f6afcf98fe95fb3f2b70ce01cf66f6db53b5e (diff)
downloadlinux-9616ff434d96303689391af3d6e1c845d233405f.tar.gz
linux-9616ff434d96303689391af3d6e1c845d233405f.tar.xz
sunsu: Fix use after free in su_remove().
Real serial port 'up' objects are statically allocated from an array in the driver. Keyboard and mouse ports, on the other hand, are dynamically allocated. Unfortunately, we free these dynamic 'up' objects before we unmap the I/O registers. Rearrange su_remove() so that this does not happen. Noticed by Julia Lawall. Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/serial')
-rw-r--r--drivers/serial/sunsu.c13
1 files changed, 9 insertions, 4 deletions
diff --git a/drivers/serial/sunsu.c b/drivers/serial/sunsu.c
index 234459c2f012..ffbf4553f665 100644
--- a/drivers/serial/sunsu.c
+++ b/drivers/serial/sunsu.c
@@ -1500,20 +1500,25 @@ out_unmap:
static int __devexit su_remove(struct of_device *op)
{
struct uart_sunsu_port *up = dev_get_drvdata(&op->dev);
+ bool kbdms = false;
if (up->su_type == SU_PORT_MS ||
- up->su_type == SU_PORT_KBD) {
+ up->su_type == SU_PORT_KBD)
+ kbdms = true;
+
+ if (kbdms) {
#ifdef CONFIG_SERIO
serio_unregister_port(&up->serio);
#endif
- kfree(up);
- } else if (up->port.type != PORT_UNKNOWN) {
+ } else if (up->port.type != PORT_UNKNOWN)
uart_remove_one_port(&sunsu_reg, &up->port);
- }
if (up->port.membase)
of_iounmap(&op->resource[0], up->port.membase, up->reg_size);
+ if (kbdms)
+ kfree(up);
+
dev_set_drvdata(&op->dev, NULL);
return 0;