Commit 6a7e6f78 authored by Johan Hovold's avatar Johan Hovold Committed by Greg Kroah-Hartman

tty: close race between device register and open

The tty class device is currently not registered until after the
character device has been registered thereby leaving a small window
were a racing open could end up with a NULL tty->dev pointer due to the
class-device lookup failing in alloc_tty_struct.

Close this race by registering the class device before the character
device while making sure to defer the user-space uevent notification
until after the character device has been registered.

Note that some tty drivers expect a valid tty->dev and would misbehave
or crash otherwise. Some line disciplines also currently dereference the
class device unconditionally despite the fact that not every tty is
guaranteed to have one (Unix98 pty), but this is being fixed separately.
Signed-off-by: default avatarJohan Hovold <johan@kernel.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 53c1cf42
...@@ -3293,9 +3293,8 @@ struct device *tty_register_device_attr(struct tty_driver *driver, ...@@ -3293,9 +3293,8 @@ struct device *tty_register_device_attr(struct tty_driver *driver,
{ {
char name[64]; char name[64];
dev_t devt = MKDEV(driver->major, driver->minor_start) + index; dev_t devt = MKDEV(driver->major, driver->minor_start) + index;
struct device *dev = NULL; struct device *dev;
int retval = -ENODEV; int retval;
bool cdev = false;
if (index >= driver->num) { if (index >= driver->num) {
pr_err("%s: Attempt to register invalid tty line number (%d)\n", pr_err("%s: Attempt to register invalid tty line number (%d)\n",
...@@ -3308,18 +3307,9 @@ struct device *tty_register_device_attr(struct tty_driver *driver, ...@@ -3308,18 +3307,9 @@ struct device *tty_register_device_attr(struct tty_driver *driver,
else else
tty_line_name(driver, index, name); tty_line_name(driver, index, name);
if (!(driver->flags & TTY_DRIVER_DYNAMIC_ALLOC)) {
retval = tty_cdev_add(driver, devt, index, 1);
if (retval)
goto error;
cdev = true;
}
dev = kzalloc(sizeof(*dev), GFP_KERNEL); dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (!dev) { if (!dev)
retval = -ENOMEM; return ERR_PTR(-ENOMEM);
goto error;
}
dev->devt = devt; dev->devt = devt;
dev->class = tty_class; dev->class = tty_class;
...@@ -3329,18 +3319,28 @@ struct device *tty_register_device_attr(struct tty_driver *driver, ...@@ -3329,18 +3319,28 @@ struct device *tty_register_device_attr(struct tty_driver *driver,
dev->groups = attr_grp; dev->groups = attr_grp;
dev_set_drvdata(dev, drvdata); dev_set_drvdata(dev, drvdata);
dev_set_uevent_suppress(dev, 1);
retval = device_register(dev); retval = device_register(dev);
if (retval) if (retval)
goto error; goto err_put;
if (!(driver->flags & TTY_DRIVER_DYNAMIC_ALLOC)) {
retval = tty_cdev_add(driver, devt, index, 1);
if (retval)
goto err_del;
}
dev_set_uevent_suppress(dev, 0);
kobject_uevent(&dev->kobj, KOBJ_ADD);
return dev; return dev;
error: err_del:
device_del(dev);
err_put:
put_device(dev); put_device(dev);
if (cdev) {
cdev_del(driver->cdevs[index]);
driver->cdevs[index] = NULL;
}
return ERR_PTR(retval); return ERR_PTR(retval);
} }
EXPORT_SYMBOL_GPL(tty_register_device_attr); EXPORT_SYMBOL_GPL(tty_register_device_attr);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment