diff options
| author | Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> | 2018-05-07 19:10:31 +0900 |
|---|---|---|
| committer | Ben Hutchings <ben@decadent.org.uk> | 2018-11-20 18:04:55 +0000 |
| commit | fb24b672da091a3d7ce4672f690d46b5f4284e81 (patch) | |
| tree | 4cccdc683170dbd56e0e9a1b186dcac696abd4a1 /drivers/base | |
| parent | 92cfd9649a8094dc3a4d67390bdee0d3732ff84a (diff) | |
| download | linux-fb24b672da091a3d7ce4672f690d46b5f4284e81.tar.gz linux-fb24b672da091a3d7ce4672f690d46b5f4284e81.tar.bz2 linux-fb24b672da091a3d7ce4672f690d46b5f4284e81.zip | |
driver core: Don't ignore class_dir_create_and_add() failure.
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>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
[bwh: Backported to 3.16: adjust context]
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
Diffstat (limited to 'drivers/base')
| -rw-r--r-- | drivers/base/core.c | 14 |
1 files changed, 12 insertions, 2 deletions
diff --git a/drivers/base/core.c b/drivers/base/core.c index 0e9468cb814f..4b7bb49b5291 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -709,7 +709,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); @@ -719,7 +719,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; } @@ -1000,6 +1000,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; @@ -1097,6 +1101,7 @@ done: kobject_del(&dev->kobj); Error: cleanup_device_parent(dev); +parent_error: if (parent) put_device(parent); name_error: @@ -1867,6 +1872,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>"); |
