staging: android: timed_output: fix sysfs file creation race
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 24 Aug 2013 17:27:29 +0000 (10:27 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 24 Aug 2013 17:27:29 +0000 (10:27 -0700)
The sysfs file for the driver was being created _after_ the device was
announced to userspace, causing a race with any tools looking for sysfs
files.

Fix the race by using the default attribute group for the class.

Cc: Kees Cook <keescook@chromium.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/staging/android/timed_output.c

index ee3a57f..2c61783 100644 (file)
@@ -28,7 +28,7 @@ static struct class *timed_output_class;
 static atomic_t device_count;
 
 static ssize_t enable_show(struct device *dev, struct device_attribute *attr,
-               char *buf)
+                          char *buf)
 {
        struct timed_output_dev *tdev = dev_get_drvdata(dev);
        int remaining = tdev->get_time(tdev);
@@ -36,9 +36,8 @@ static ssize_t enable_show(struct device *dev, struct device_attribute *attr,
        return sprintf(buf, "%d\n", remaining);
 }
 
-static ssize_t enable_store(
-               struct device *dev, struct device_attribute *attr,
-               const char *buf, size_t size)
+static ssize_t enable_store(struct device *dev, struct device_attribute *attr,
+                           const char *buf, size_t size)
 {
        struct timed_output_dev *tdev = dev_get_drvdata(dev);
        int value;
@@ -50,8 +49,13 @@ static ssize_t enable_store(
 
        return size;
 }
+static DEVICE_ATTR_RW(enable);
 
-static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR, enable_show, enable_store);
+static struct attribute *timed_output_attrs[] = {
+       &dev_attr_enable.attr,
+       NULL,
+};
+ATTRIBUTE_GROUPS(timed_output);
 
 static int create_timed_output_class(void)
 {
@@ -60,6 +64,7 @@ static int create_timed_output_class(void)
                if (IS_ERR(timed_output_class))
                        return PTR_ERR(timed_output_class);
                atomic_set(&device_count, 0);
+               timed_output_class->dev_groups = timed_output_groups;
        }
 
        return 0;
@@ -82,27 +87,15 @@ int timed_output_dev_register(struct timed_output_dev *tdev)
        if (IS_ERR(tdev->dev))
                return PTR_ERR(tdev->dev);
 
-       ret = device_create_file(tdev->dev, &dev_attr_enable);
-       if (ret < 0)
-               goto err_create_file;
-
        dev_set_drvdata(tdev->dev, tdev);
        tdev->state = 0;
        return 0;
-
-err_create_file:
-       device_destroy(timed_output_class, MKDEV(0, tdev->index));
-       pr_err("failed to register driver %s\n",
-                       tdev->name);
-
-       return ret;
 }
 EXPORT_SYMBOL_GPL(timed_output_dev_register);
 
 void timed_output_dev_unregister(struct timed_output_dev *tdev)
 {
        tdev->enable(tdev, 0);
-       device_remove_file(tdev->dev, &dev_attr_enable);
        device_destroy(timed_output_class, MKDEV(0, tdev->index));
        dev_set_drvdata(tdev->dev, NULL);
 }