* [Ocfs2-devel] [PATCH] lib/kobject: fix memory leak in error path of kset_create_and_add()
[not found] <871tbpebjw.fsf@gmail.com>
@ 2015-11-17 4:12 ` Greg Kroah-Hartman
[not found] ` <87k2pfcl73.fsf_-_@gmail.com>
0 siblings, 1 reply; 2+ messages in thread
From: Greg Kroah-Hartman @ 2015-11-17 4:12 UTC (permalink / raw)
To: Nicolai Stange
Cc: Theodore Ts'o, Andreas Dilger, Mark Fasheh, Joel Becker,
Andrew Morton, Joe Perches, linux-kernel, linux-ext4, ocfs2-devel
On Tue, Nov 17, 2015 at 01:04:19AM +0100, Nicolai Stange wrote:
> In kset_create_and_add(), the name duped into the kset's kobject by
> kset_create() gets leaked if the call to kset_register() fails.
>
> Indeed, triggering failure by invoking kset_create_and_add() with a
> duplicate name makes kmemleak reporting
>
> unreferenced object 0xffff8800b4a1f428 (size 16):
> comm "insmod", pid 682, jiffies 4294745489 (age 50.477s)
> hex dump (first 16 bytes):
> 64 75 70 6c 69 63 61 74 65 00 6b 6b 6b 6b 6b a5 duplicate.kkkkk.
> backtrace:
> [<ffffffff814380ee>] kmemleak_alloc+0x4e/0xb0
> [<ffffffff811aab01>] __kmalloc_track_caller+0x2b1/0x390
> [<ffffffff811797f1>] kstrdup+0x31/0x60
> [<ffffffff81179843>] kstrdup_const+0x23/0x30
> [<ffffffff81290254>] kvasprintf_const+0x54/0x90
> [<ffffffff81284d21>] kobject_set_name_vargs+0x21/0xa0
> [<ffffffff81284dee>] kobject_set_name+0x4e/0x70
> [<ffffffff812854f5>] kset_create_and_add+0x45/0xa0
> [...]
>
> Similar problems exist at all call sites of kset_register(), that is
> in drivers/base, fs/ext4 and in fs/ocfs2.
Yes, but those calls all succeed, so this isn't a problem in the "real"
world :)
> The deeper cause behind this are the current semantics of the kset
> initialization, creation and registration functions which differ from the
> ones of their corresponding kobject counterparts.
> Namely,
> - there is no _exported_ kset initialization function,
> - the (not exported) kset_create() creates a halfway initialized kset
> object,
> - and the kset_register() finishes a kset object's initialization but
> expects its name to already have been set at its entry.
>
> To fix this:
> - Export kset_init() and let it mimic the semantics of kobject_init().
> Especially it takes and sets a kobj_type which makes the kset object
> kset_put()able upon return.
> - Let the internal kset_create() do the complete initialization by means
> of kset_init().
> - Remove any kset initialization from kset_register(): it expects a
> readily initialized kset object now. Furthermore, let kset_register()
> take and set the kset object's name. This resembles the behaviour of
> kobject_add(). In analogy to the latter, require the caller to call
> kset_put() or kset_unregister() unconditionally, even on failure.
>
> At the call sites of kset_register():
> - Replace the open coded kset object initialization by a call to
> kset_init().
> - Remove the explicit name setting and let the kset_register() call do
> that work.
> - Replace any kfree()s by kset_put()s where appropriate.
>
> Signed-off-by: Nicolai Stange <nicstange@gmail.com>
> ---
> To the maintainers of ext4 and ocfs2: although several subsystems are
> touched, the changes come in one single patch in order to keep them bisectable.
>
>
> drivers/base/bus.c | 14 ++-----
> drivers/base/class.c | 39 ++++++++++++++-----
> fs/ext4/sysfs.c | 13 +++----
> fs/ocfs2/cluster/masklog.c | 13 ++++---
> include/linux/kobject.h | 6 ++-
> lib/kobject.c | 94 ++++++++++++++++++++++++++++------------------
> 6 files changed, 110 insertions(+), 69 deletions(-)
>
> diff --git a/drivers/base/bus.c b/drivers/base/bus.c
> index 5005924..a81227c 100644
> --- a/drivers/base/bus.c
> +++ b/drivers/base/bus.c
> @@ -900,15 +900,11 @@ int bus_register(struct bus_type *bus)
>
> BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier);
>
> - retval = kobject_set_name(&priv->subsys.kobj, "%s", bus->name);
> - if (retval)
> - goto out;
> -
> - priv->subsys.kobj.kset = bus_kset;
> - priv->subsys.kobj.ktype = &bus_ktype;
> priv->drivers_autoprobe = 1;
>
> - retval = kset_register(&priv->subsys);
> + kset_init(&priv->subsys, &bus_ktype, NULL);
> + priv->subsys.kobj.kset = bus_kset;
> + retval = kset_register(&priv->subsys, bus->name, NULL);
> if (retval)
> goto out;
>
> @@ -955,10 +951,8 @@ bus_drivers_fail:
> bus_devices_fail:
> bus_remove_file(bus, &bus_attr_uevent);
> bus_uevent_fail:
> - kset_unregister(&bus->p->subsys);
> out:
> - kfree(bus->p);
> - bus->p = NULL;
> + kset_unregister(&bus->p->subsys);
> return retval;
> }
> EXPORT_SYMBOL_GPL(bus_register);
> diff --git a/drivers/base/class.c b/drivers/base/class.c
> index 71059e3..94a5b040 100644
> --- a/drivers/base/class.c
> +++ b/drivers/base/class.c
> @@ -19,6 +19,7 @@
> #include <linux/slab.h>
> #include <linux/genhd.h>
> #include <linux/mutex.h>
> +#include <linux/printk.h>
> #include "base.h"
>
> #define to_class_attr(_attr) container_of(_attr, struct class_attribute, attr)
> @@ -82,6 +83,24 @@ static struct kobj_type class_ktype = {
> .child_ns_type = class_child_ns_type,
> };
>
> +static void glue_dirs_release_dummy(struct kobject *kobj)
> +{
> + /*
> + * The glue_dirs kset member of struct subsys_private is never
> + * registered and thus, never unregistered.
> + * This release function is a dummy to make kset_init() happy.
> + */
> + pr_err(
> + "class (%p): unexpected kset_put() on glue_dirs, something is broken.",
> + container_of(kobj, struct subsys_private,
> + glue_dirs.kobj)->class);
> + dump_stack();
How can this ever happen?
> +}
> +
> +static struct kobj_type glue_dirs_ktype = {
> + .release = glue_dirs_release_dummy,
> +};
> +
> /* Hotplug events for classes go to the class subsys */
> static struct kset *class_kset;
>
> @@ -175,18 +194,14 @@ int __class_register(struct class *cls, struct lock_class_key *key)
> return -ENOMEM;
> klist_init(&cp->klist_devices, klist_class_dev_get, klist_class_dev_put);
> INIT_LIST_HEAD(&cp->interfaces);
> - kset_init(&cp->glue_dirs);
> + kset_init(&cp->glue_dirs, &glue_dirs_ktype, NULL);
> __mutex_init(&cp->mutex, "subsys mutex", key);
> - error = kobject_set_name(&cp->subsys.kobj, "%s", cls->name);
> - if (error) {
> - kfree(cp);
> - return error;
> - }
>
> /* set the default /sys/dev directory for devices of this class */
> if (!cls->dev_kobj)
> cls->dev_kobj = sysfs_dev_char_kobj;
>
> + kset_init(&cp->subsys, &class_ktype, NULL);
> #if defined(CONFIG_BLOCK)
> /* let the block class directory show up in the root of sysfs */
> if (!sysfs_deprecated || cls != &block_class)
> @@ -194,13 +209,19 @@ int __class_register(struct class *cls, struct lock_class_key *key)
> #else
> cp->subsys.kobj.kset = class_kset;
> #endif
> - cp->subsys.kobj.ktype = &class_ktype;
> cp->class = cls;
> cls->p = cp;
>
> - error = kset_register(&cp->subsys);
> + error = kset_register(&cp->subsys, cls->name, NULL);
> if (error) {
> - kfree(cp);
> + /*
> + * class->release() would be called by cp->subsys'
> + * release function. Prevent this from happening in
> + * the error case by zeroing cp->class out.
> + */
> + cp->class = NULL;
> + cls->p = NULL;
> + kset_put(&cp->subsys);
That seems pretty messy, why can't we allow the release to be called? I
don't think this is really correct :(
But overall I like the patch, nice job. Any way to fix this last bit
up?
thanks,
greg k-h
^ permalink raw reply [flat|nested] 2+ messages in thread
* [Ocfs2-devel] [PATCH v2] kset- and class-registration cleanups
[not found] ` <87k2pfcl73.fsf_-_@gmail.com>
@ 2016-02-23 14:58 ` Nicolai Stange
0 siblings, 0 replies; 2+ messages in thread
From: Nicolai Stange @ 2016-02-23 14:58 UTC (permalink / raw)
To: Greg Kroah-Hartman
Cc: Nicolai Stange, Theodore Ts'o, Andreas Dilger, Mark Fasheh,
Joel Becker, Andrew Morton, Joe Perches, linux-kernel, linux-ext4,
ocfs2-devel
Nicolai Stange <nicstange@gmail.com> writes:
> In order to have something to base further discussion on, here comes the
> second version.
>
Hi Greg,
I'd like to ask whether this is still in your review queue or did it
slip through?
Should I resend?
Thank you,
Nicolai
> In addition to some changes to the inital patch (now [1/3]), two
> additional ones have been introduced.
>
> The three patches depend on one another in sequence.
>
> For a detailed changelist, see the end of this mail.
>
> Greg Kroah-Hartman <gregkh@linuxfoundation.org> writes:
>> On Tue, Nov 17, 2015 at 01:04:19AM +0100, Nicolai Stange wrote:
>> Yes, but those calls all succeed, so this isn't a problem in the "real"
>> world :)
>
> I added a word about non-impact in the commit message of [1/3].
>
>>> +static void glue_dirs_release_dummy(struct kobject *kobj)
>>> +{
>>> + /*
>>> + * The glue_dirs kset member of struct subsys_private is never
>>> + * registered and thus, never unregistered.
>>> + * This release function is a dummy to make kset_init() happy.
>>> + */
>>> + pr_err(
>>> + "class (%p): unexpected kset_put() on glue_dirs, something is broken.",
>>> + container_of(kobj, struct subsys_private,
>>> + glue_dirs.kobj)->class);
>>> + dump_stack();
>>
>> How can this ever happen?
>
> Not at all. I'm not sure I understand you correctly here.
> Do you strictly want to abandon the dummy releaser, or more specifically,
> the dummy kobj_type?
> For the moment, I turned the pr_err()/dump_stack() into a WARN() for the
> sake of better style.
>
>>> if (error) {
>>> - kfree(cp);
>>> + /*
>>> + * class->release() would be called by cp->subsys'
>>> + * release function. Prevent this from happening in
>>> + * the error case by zeroing cp->class out.
>>> + */
>>> + cp->class = NULL;
>>> + cls->p = NULL;
>>> + kset_put(&cp->subsys);
>>
>> That seems pretty messy, why can't we allow the release to be called? I
>> don't think this is really correct :(
>
> At the moment, it is necessary. I've added [3/3] for the case that you
> want cls->class_release() to get called from __class_register() on error.
> In [3/3] you will also find the (few) callers expecting the behaviour as
> it currently is.
>
>
> Detailed changes from initial version to v2:
> [1/3] lib/kobject: fix memory leak in error path of kset_create_and_add()
> This one is the original patch with a few changes:
> - added a word of non-impact to commit message
> - use WARN() instead of open coded pr_error()/dump_stack() pair in
> struct class' glue_dirs' dummy class releaser.
> - follow my own advice in the docstring of kset_register() and
> use kset_put() instead of kset_unregister() on error of
> kset_register() in ext4's ext4_init_sysfs() and ocfs2's mlog_sys_init().
>
> [2/3] drivers/base/class: __class_register(): make error behaviour consistent
> This one is new and quite unrelated to the original patch.
> Following the sidenote made in my last mail, it makes __class_register()
> properly clean up after itself on error.
>
> [3/3] drivers/base/class: __class_register(): invoke class' releaser on failure
> This one is new.
> It addresses Greg K-H's comment on the initial version about the messiness
> of avoiding to call class->class_release() from __class_register() on
> error. Given the fact that I had to introduce an explicit
> cls->class_release() in the early part when there is no kset object
> available yet, I'm by no means sure that it is much less messy now and
> that this patch is worth the trouble.
> -> It is up to you to judge.
> As there are enough people bothered already, I did not CC the people
> suggested for this one by get_maintainer.pl: all of them are maintainers
> of external subsystems and probably not particularly interested in
> __class_register() and friends. I will do this as soon as
> a decision for this patch has been made, perhaps in a separate thread.
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2016-02-23 14:58 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <871tbpebjw.fsf@gmail.com>
2015-11-17 4:12 ` [Ocfs2-devel] [PATCH] lib/kobject: fix memory leak in error path of kset_create_and_add() Greg Kroah-Hartman
[not found] ` <87k2pfcl73.fsf_-_@gmail.com>
2016-02-23 14:58 ` [Ocfs2-devel] [PATCH v2] kset- and class-registration cleanups Nicolai Stange
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox