Commit 9616ff434d96303689391af3d6e1c845d233405f
1 parent
7c1f6afcf9
Exists in
master
and in
7 other branches
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>
Showing 1 changed file with 9 additions and 4 deletions Side-by-side Diff
drivers/serial/sunsu.c
... | ... | @@ -1500,19 +1500,24 @@ |
1500 | 1500 | static int __devexit su_remove(struct of_device *op) |
1501 | 1501 | { |
1502 | 1502 | struct uart_sunsu_port *up = dev_get_drvdata(&op->dev); |
1503 | + bool kbdms = false; | |
1503 | 1504 | |
1504 | 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 | 1510 | #ifdef CONFIG_SERIO |
1507 | 1511 | serio_unregister_port(&up->serio); |
1508 | 1512 | #endif |
1509 | - kfree(up); | |
1510 | - } else if (up->port.type != PORT_UNKNOWN) { | |
1513 | + } else if (up->port.type != PORT_UNKNOWN) | |
1511 | 1514 | uart_remove_one_port(&sunsu_reg, &up->port); |
1512 | - } | |
1513 | 1515 | |
1514 | 1516 | if (up->port.membase) |
1515 | 1517 | of_iounmap(&op->resource[0], up->port.membase, up->reg_size); |
1518 | + | |
1519 | + if (kbdms) | |
1520 | + kfree(up); | |
1516 | 1521 | |
1517 | 1522 | dev_set_drvdata(&op->dev, NULL); |
1518 | 1523 |