]> bbs.cooldavid.org Git - net-next-2.6.git/commitdiff
sunsu: Fix use after free in su_remove().
authorDavid S. Miller <davem@davemloft.net>
Thu, 27 May 2010 04:17:29 +0000 (21:17 -0700)
committerDavid S. Miller <davem@davemloft.net>
Thu, 27 May 2010 04:17:29 +0000 (21:17 -0700)
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>
drivers/serial/sunsu.c

index 234459c2f0122fc24e78f5b173f3fe4a3f83555d..ffbf4553f6651966269b1be1bc57b43b37b34b98 100644 (file)
@@ -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;