tty: don't leak cdev in tty_cdev_add()
authorLeon Yu <chianglungyu@gmail.com>
Mon, 7 Sep 2015 13:08:37 +0000 (13:08 +0000)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sun, 4 Oct 2015 17:51:42 +0000 (18:51 +0100)
Commit a3a10ce3429e ("Avoid usb reset crashes by making tty_io cdevs truly
dynamic") which mixes using cdev_alloc() and cdev_init() is problematic.
Subsequent call to cdev_init() after cdev_alloc() sets kobj release method
from cdev_dynamic_release() to cdev_default_release() and thus makes it
impossible to free allocated cdev.

This patch also consolidates error path of cdev_add() as cdev can also leak
here if things went wrong.

Signed-off-by: Leon Yu <chianglungyu@gmail.com>
Fixes: a3a10ce3429e ("Avoid usb reset crashes by making tty_io cdevs truly dynamic")
Acked-by: Richard Watts <rrw@kynesim.co.uk>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/tty/tty_io.c

index 02785d844354be01b9774ad10e70ab398297c6da..17b02724273440fa7b7b8504f7a0b86f539a66b2 100644 (file)
@@ -3151,13 +3151,18 @@ struct class *tty_class;
 static int tty_cdev_add(struct tty_driver *driver, dev_t dev,
                unsigned int index, unsigned int count)
 {
+       int err;
+
        /* init here, since reused cdevs cause crashes */
        driver->cdevs[index] = cdev_alloc();
        if (!driver->cdevs[index])
                return -ENOMEM;
-       cdev_init(driver->cdevs[index], &tty_fops);
+       driver->cdevs[index]->ops = &tty_fops;
        driver->cdevs[index]->owner = driver->owner;
-       return cdev_add(driver->cdevs[index], dev, count);
+       err = cdev_add(driver->cdevs[index], dev, count);
+       if (err)
+               kobject_put(&driver->cdevs[index]->kobj);
+       return err;
 }
 
 /**