mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-10-10 02:29:01 +00:00
driver core: Don't ignore class_dir_create_and_add() failure.
commit 84d0c27d62
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>
This commit is contained in:
parent
f3233cb248
commit
c81a6be9da
1 changed files with 12 additions and 2 deletions
|
@ -1461,7 +1461,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);
|
||||
|
@ -1471,7 +1471,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;
|
||||
}
|
||||
|
@ -1778,6 +1778,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;
|
||||
|
||||
|
@ -1876,6 +1880,7 @@ int device_add(struct device *dev)
|
|||
kobject_del(&dev->kobj);
|
||||
Error:
|
||||
cleanup_glue_dir(dev, glue_dir);
|
||||
parent_error:
|
||||
put_device(parent);
|
||||
name_error:
|
||||
kfree(dev->p);
|
||||
|
@ -2695,6 +2700,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>");
|
||||
|
|
Loading…
Reference in a new issue