aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2010-05-27 00:17:29 -0400
committerDavid S. Miller <davem@davemloft.net>2010-05-27 00:17:29 -0400
commit9616ff434d96303689391af3d6e1c845d233405f (patch)
treefe467102ce2a59dc2113e8f4da6a4d8185404fda
parent7c1f6afcf98fe95fb3f2b70ce01cf66f6db53b5e (diff)
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>
-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:
1500static int __devexit su_remove(struct of_device *op) 1500static int __devexit su_remove(struct of_device *op)
1501{ 1501{
1502 struct uart_sunsu_port *up = dev_get_drvdata(&op->dev); 1502 struct uart_sunsu_port *up = dev_get_drvdata(&op->dev);
1503 bool kbdms = false;
1503 1504
1504 if (up->su_type == SU_PORT_MS || 1505 if (up->su_type == SU_PORT_MS ||
1505 up->su_type == SU_PORT_KBD) { 1506 up->su_type == SU_PORT_KBD)
1507 kbdms = true;
1508
1509 if (kbdms) {
1506#ifdef CONFIG_SERIO 1510#ifdef CONFIG_SERIO
1507 serio_unregister_port(&up->serio); 1511 serio_unregister_port(&up->serio);
1508#endif 1512#endif
1509 kfree(up); 1513 } else if (up->port.type != PORT_UNKNOWN)
1510 } else if (up->port.type != PORT_UNKNOWN) {
1511 uart_remove_one_port(&sunsu_reg, &up->port); 1514 uart_remove_one_port(&sunsu_reg, &up->port);
1512 }
1513 1515
1514 if (up->port.membase) 1516 if (up->port.membase)
1515 of_iounmap(&op->resource[0], up->port.membase, up->reg_size); 1517 of_iounmap(&op->resource[0], up->port.membase, up->reg_size);
1516 1518
1519 if (kbdms)
1520 kfree(up);
1521
1517 dev_set_drvdata(&op->dev, NULL); 1522 dev_set_drvdata(&op->dev, NULL);
1518 1523
1519 return 0; 1524 return 0;