drivers: base: core: do not put noninitialized devices
Subsystems (2)
PATCH 1/1 drivers: base: core: do not put noninitialized devices
If kobject_set_name_vargs() fails then put_device() frees device with zero kobj->state_initialized. This leads to WARN(). Divide device_register() call to device_initialize() call before kobject_set_name_vargs() and device_add() call after it.
---
Compile tested only.
drivers/base/core.c | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-)
drivers/base/core.c +2 -1
@@ -1424,11 +1424,12 @@ struct device *device_create_vargs(struct class *class, struct device *parent, dev->release = device_create_release;dev_set_drvdata (dev, drvdata); +device_initialize (dev); retval =kobject_set_name_vargs (&dev->kobj, fmt, args);if (retval) goto error; - retval =device_register (dev); + retval =device_add (dev);if (retval) goto error;
Signature · 1 line
1.7.0.4
Quoted 2 lines · Vasiliy Kulikov
If
kobject_set_name_vargs()fails thenput_device()frees device with zerokobj->state_initialized. This leads toWARN().
Have you seen this happen?
Quoted 6 lines
Divide
device_register()call todevice_initialize()call beforekobject_set_name_vargs()anddevice_add()call after it.Signed-off-by Vasiliy Kulikov <[email protected]>---
Compile tested only.
I'd prefer not to change this unless you are seeing problems with the current code.
How did kobject_set_name_vargs() fail for you?
thanks,
greg k-h
Hi Greg,
Quoted 5 lines · Greg KH
Quoted 2 lines · Vasiliy Kulikov
If
kobject_set_name_vargs()fails thenput_device()frees device with zerokobj->state_initialized. This leads toWARN().Have you seen this happen?
No, I've just analized the code. Without device_initialize() ->kobj is not initialized:
kobject_init(&dev->kobj, &device_ktype) calls kobject_init_internal(kobj) calls kobj->state_initialized = 1;
kobject_put() calls WARN if state_initialized = 0:
void kobject_put(struct kobject *kobj)
{
if (kobj) {
if (!kobj->state_initialized)
WARN(1, KERN_WARNING "kobject: '%s' (%p): is not "
"initialized, yet kobject_put() is being "
"called.\n", kobject_name(kobj), kobj);I got the stack dump with similar code:
struct device *dev = kzalloc(sizeof(*dev), GFP_KERNEL);
put_device(dev);Quoted 4 lines
I'd prefer not to change this unless you are seeing problems with the current code.
How did
kobject_set_name_vargs()fail for you?
int kobject_set_name_vargs(struct kobject *kobj, const char *fmt,
va_list vargs)
{
[...]
kobj->name = kvasprintf(GFP_KERNEL, fmt, vargs);
if (!kobj->name)
return -ENOMEM;char *kvasprintf(gfp_t gfp, const char *fmt, va_list ap)
{
[...]
p = kmalloc(len+1, gfp);
if (!p)
return NULL;Unlikely, but may fail in OOM situation.
Thanks,
Signature · 2 lines
Vasiliy Kulikov http://www.openwall.com - bringing security into open computing environments
Quoted 2 lines · Vasiliy Kulikov
No, I've just analized the code. Without
device_initialize()->kobj is not initialized:
I mean 'not set' instead of 'not initialized' - it is already kzalloc()'ed :)
Thanks,
Signature · 2 lines
Vasiliy Kulikov http://www.openwall.com - bringing security into open computing environments
Quoted 29 lines · Vasiliy Kulikov
Hi Greg,
Quoted 5 lines · Greg KH
Quoted 2 lines · Vasiliy Kulikov
If
kobject_set_name_vargs()fails thenput_device()frees device with zerokobj->state_initialized. This leads toWARN().Have you seen this happen?
No, I've just analized the code. Without
device_initialize()->kobj is not initialized:kobject_init(&dev->kobj, &device_ktype) calls kobject_init_internal(kobj) calls kobj->state_initialized = 1;
kobject_put()calls WARN ifstate_initialized= 0:void kobject_put(struct kobject *kobj) { if (kobj) { if (!kobj->state_initialized) WARN(1, KERN_WARNING "kobject: '%s' (%p): is not " "initialized, yet kobject_put() is being " "called.\n", kobject_name(kobj), kobj);
Quoted 4 lines
I got the stack dump with similar code:
struct device *dev = kzalloc(sizeof(*dev), GFP_KERNEL); put_device(dev);
Sure, that's illegal code, and we want to warn about that. So I would say, if an error happens, we want to see this message so the code should stay as-is.
thanks,
greg k-h
Quoted 12 lines · Greg KH
Quoted 11 lines · Vasiliy Kulikov
kobject_put()calls WARN ifstate_initialized= 0:void kobject_put(struct kobject *kobj) { if (kobj) { if (!kobj->state_initialized) WARN(1, KERN_WARNING "kobject: '%s' (%p): is not " "initialized, yet kobject_put() is being " "called.\n", kobject_name(kobj), kobj);
Quoted 6 lines
Quoted 4 lines
I got the stack dump with similar code:
struct device *dev = kzalloc(sizeof(*dev), GFP_KERNEL); put_device(dev);Sure, that's illegal code,
You might misunderstood me, see this part of device_create_vargs():
struct device *device_create_vargs(...)
{
...
dev = kzalloc(sizeof(*dev), GFP_KERNEL); <<<
if (!dev)
...
dev->devt = devt;
dev->class = class;
dev->parent = parent;
dev->release = device_create_release;
dev_set_drvdata(dev, drvdata);
retval = kobject_set_name_vargs(&dev->kobj, fmt, args); <<<
if (retval)
goto error; <<<
...error:
put_device(dev); <<<
...
}It is device_create_vargs()'s mistake, not the caller.
Quoted 3 lines
and we want to warn about that. So I would
say, if an error happens, we want to see this message so the code should stay as-is.
If you mean "if memomy allocation for name fails then we want to see message about allocation failure" then maybe use pr_err("No mem for device name\n") instead of confusing "kobject is not initialized, yet kobject_put() is being called"?
Thanks,
Signature · 2 lines
Vasiliy Kulikov http://www.openwall.com - bringing security into open computing environments