mirror of
https://github.com/torvalds/linux.git
synced 2024-11-30 08:01:59 +00:00
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: Johan Hovold <johan@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
53c1cf4281
commit
6a7e6f78c2
@ -3293,9 +3293,8 @@ struct device *tty_register_device_attr(struct tty_driver *driver,
|
||||
{
|
||||
char name[64];
|
||||
dev_t devt = MKDEV(driver->major, driver->minor_start) + index;
|
||||
struct device *dev = NULL;
|
||||
int retval = -ENODEV;
|
||||
bool cdev = false;
|
||||
struct device *dev;
|
||||
int retval;
|
||||
|
||||
if (index >= driver->num) {
|
||||
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,
|
||||
else
|
||||
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);
|
||||
if (!dev) {
|
||||
retval = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
if (!dev)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
dev->devt = devt;
|
||||
dev->class = tty_class;
|
||||
@ -3329,18 +3319,28 @@ struct device *tty_register_device_attr(struct tty_driver *driver,
|
||||
dev->groups = attr_grp;
|
||||
dev_set_drvdata(dev, drvdata);
|
||||
|
||||
dev_set_uevent_suppress(dev, 1);
|
||||
|
||||
retval = device_register(dev);
|
||||
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;
|
||||
|
||||
error:
|
||||
err_del:
|
||||
device_del(dev);
|
||||
err_put:
|
||||
put_device(dev);
|
||||
if (cdev) {
|
||||
cdev_del(driver->cdevs[index]);
|
||||
driver->cdevs[index] = NULL;
|
||||
}
|
||||
|
||||
return ERR_PTR(retval);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tty_register_device_attr);
|
||||
|
Loading…
Reference in New Issue
Block a user