]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/commitdiff
driver core: Don't ignore class_dir_create_and_add() failure.
authorTetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Mon, 7 May 2018 10:10:31 +0000 (19:10 +0900)
committerThadeu Lima de Souza Cascardo <cascardo@canonical.com>
Fri, 9 Nov 2018 19:00:09 +0000 (17:00 -0200)
BugLink: http://bugs.launchpad.net/bugs/1800537
commit 84d0c27d6233a9ba0578b20f5a09701eb66cee42 upstream.

syzbot is hitting WARN() at kernfs_add_one() [1].
This is because kernfs_create_link() is confused by previous device_add()
call which continued without setting dev->kobj.parent field when
get_device_parent() failed by memory allocation fault injection.
Fix this by propagating the error from class_dir_create_and_add() to
the calllers of get_device_parent().

[1] https://syzkaller.appspot.com/bug?id=fae0fb607989ea744526d1c082a5b8de6529116f

Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Reported-by: syzbot <syzbot+df47f81c226b31d89fb1@syzkaller.appspotmail.com>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: stable <stable@vger.kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Kamal Mostafa <kamal@canonical.com>
Signed-off-by: Khalid Elmously <khalid.elmously@canonical.com>
drivers/base/core.c

index 3e63e0f443fbb789af2b3f078038884ff5bfa53c..715145798d97f63bab42d70e5de1405b3626f3b6 100644 (file)
@@ -1470,7 +1470,7 @@ class_dir_create_and_add(struct class *class, struct kobject *parent_kobj)
 
        dir = kzalloc(sizeof(*dir), GFP_KERNEL);
        if (!dir)
-               return NULL;
+               return ERR_PTR(-ENOMEM);
 
        dir->class = class;
        kobject_init(&dir->kobj, &class_dir_ktype);
@@ -1480,7 +1480,7 @@ class_dir_create_and_add(struct class *class, struct kobject *parent_kobj)
        retval = kobject_add(&dir->kobj, parent_kobj, "%s", class->name);
        if (retval < 0) {
                kobject_put(&dir->kobj);
-               return NULL;
+               return ERR_PTR(retval);
        }
        return &dir->kobj;
 }
@@ -1787,6 +1787,10 @@ int device_add(struct device *dev)
 
        parent = get_device(dev->parent);
        kobj = get_device_parent(dev, parent);
+       if (IS_ERR(kobj)) {
+               error = PTR_ERR(kobj);
+               goto parent_error;
+       }
        if (kobj)
                dev->kobj.parent = kobj;
 
@@ -1885,6 +1889,7 @@ done:
        kobject_del(&dev->kobj);
  Error:
        cleanup_glue_dir(dev, glue_dir);
+parent_error:
        put_device(parent);
 name_error:
        kfree(dev->p);
@@ -2704,6 +2709,11 @@ int device_move(struct device *dev, struct device *new_parent,
        device_pm_lock();
        new_parent = get_device(new_parent);
        new_parent_kobj = get_device_parent(dev, new_parent);
+       if (IS_ERR(new_parent_kobj)) {
+               error = PTR_ERR(new_parent_kobj);
+               put_device(new_parent);
+               goto out;
+       }
 
        pr_debug("device: '%s': %s: moving to '%s'\n", dev_name(dev),
                 __func__, new_parent ? dev_name(new_parent) : "<NULL>");