From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
To: "Tobin C. Harding" <me@tobin.cc>
Cc: "Rafael J. Wysocki" <rafael@kernel.org>,
cl@linux.com, tycho@tycho.ws, willy@infradead.org,
linux-kernel@vger.kernel.org
Subject: Re: memleak around kobject_init_and_add()
Date: Thu, 2 May 2019 09:17:42 +0200 [thread overview]
Message-ID: <20190502071742.GC16247@kroah.com> (raw)
In-Reply-To: <20190501215616.GD18827@eros.localdomain>
On Thu, May 02, 2019 at 07:56:16AM +1000, Tobin C. Harding wrote:
> On Sat, Apr 27, 2019 at 09:28:09PM +0200, Greg Kroah-Hartman wrote:
> > On Sat, Apr 27, 2019 at 06:13:30PM +1000, Tobin C. Harding wrote:
> > > (Note at bottom on reasons for 'To' list 'Cc' list)
> > >
> > > Hi,
> > >
> > > kobject_init_and_add() seems to be routinely misused. A failed call to this
> > > function requires a call to kobject_put() otherwise we leak memory.
> > >
> > > Examples memleaks can be seen in:
> > >
> > > mm/slub.c
> > > fs/btrfs/sysfs.c
> > > fs/xfs/xfs_sysfs.h: xfs_sysfs_init()
> > >
> > > Question: Do we fix the misuse or fix the API?
> >
> > Fix the misuse.
> >
> > > $ git grep kobject_init_and_add | wc -l
> > > 117
> > >
> > > Either way, we will have to go through all 117 call sites and check them.
> >
> > Yes. Same for other functions like device_add(), that is the "pattern"
> > those users must follow.
> >
> > > I
> > > don't mind fixing them all but I don't want to do it twice because I chose the
> > > wrong option. Reaching out to those more experienced for a suggestion please.
> > >
> > > Fix the API
> > > -----------
> > >
> > > Typically init functions do not require cleanup if they fail, this argument
> > > leads to this patch
> > >
> > > diff --git a/lib/kobject.c b/lib/kobject.c
> > > index aa89edcd2b63..62328054bbd0 100644
> > > --- a/lib/kobject.c
> > > +++ b/lib/kobject.c
> > > @@ -453,6 +453,9 @@ int kobject_init_and_add(struct kobject *kobj, struct kobj_type *ktype,
> > > retval = kobject_add_varg(kobj, parent, fmt, args);
> > > va_end(args);
> > >
> > > + if (retval)
> > > + kobject_put(kobj);
> > > +
> > > return retval;
> > > }
> > > EXPORT_SYMBOL_GPL(kobject_init_and_add);
> >
> > I would _love_ to do this, but realize what a kobject really is.
> >
> > It's just a "base object" that is embedded inside of some other object.
> > The kobject core has no idea what is going on outside of itself. If the
> > kobject_init_and_add() function fails, it can NOT drop the last
> > reference on itself, as that would cause the memory owned by the _WHOLE_
> > structure the kobject is embedded in, to be freed.
> >
> > And the kobject core can not "know" that something else needed to be
> > done _before_ that memory could be freed. What if the larger structure
> > needs to have some other destructor called on it first? What if
> > some other api initialization needs to be torn down.
> >
> > As an example, consider this code:
> >
> > struct foo {
> > struct kobject kobj;
> > struct baz *baz;
> > };
> >
> > void foo_release(struct kobject *kobj)
> > {
> > struct foo *foo = container_of(kobj, struct foo, kobj);
> > kfree(foo);
> > }
> >
> > struct kobj_type foo_ktype = {
> > .release = foo_release,
> > };
> >
> > struct foo *foo_create(struct foo *parent, char *name)
> > {
> > struct *foo;
> >
> > foo = kzalloc(sizeof(*foo), GFP_KERNEL);
> > if (!foo)
> > return NULL;
> >
> > foo->baz = baz_create(name);
> > if (!foo->baz)
> > return NULL;
> >
> > ret = kobject_init_and_add(&foo->kobj, foo_ktype, &parent->kobj, "foo-%s", name);
> > if (ret) {
> > baz_destroy(foo->baz);
> > kobject_put(&foo->kobj);
> > return NULL;
> > }
> >
> > return foo;
> > }
> >
> > void foo_destroy(struct foo *foo)
> > {
> > baz_destroy(foo->baz);
> > kobject_del(&foo->kobj);
> kojbect_put(&foo->kobj);
> > }
>
> Does this need this extra call to kobject_put()? Then foo_create()
> leaves foo with a refcount of 1 and foo_destroy drops that refcount.
Oops, no, I messed this up, it should _only_ be a call to
kobject_put(), kobject_del() is not needed here.
kobject_del() is for people who "really want to control the lifetime" of
a kobject. All it does is remove the kobject from sysfs, and drop the
parent reference of the kobject, allowing the kobject to be "free" on
it's own. Later a kobject_put() call must be called on it to really
clean it up.
If you just call kobject_put(), and this is the last reference,
kobject_del() will be correctly called for you by the kobject code, as
it "knows" this is time to clean up the sysfs entities.
A "normal" user should never have to call kobject_del().
thanks,
greg k-h
next prev parent reply other threads:[~2019-05-02 7:17 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-04-27 8:13 memleak around kobject_init_and_add() Tobin C. Harding
2019-04-27 19:28 ` Greg Kroah-Hartman
2019-04-27 23:33 ` Tobin C. Harding
2019-04-28 1:19 ` Tobin C. Harding
2019-04-28 16:14 ` Greg Kroah-Hartman
2019-04-28 22:46 ` Tobin C. Harding
2019-05-01 21:56 ` Tobin C. Harding
2019-05-02 7:17 ` Greg Kroah-Hartman [this message]
2019-05-02 7:28 ` Greg Kroah-Hartman
2019-05-02 8:19 ` Tobin C. Harding
2019-05-02 10:22 ` [PATCH] kobject: clean up the kobject add documentation a bit more Greg Kroah-Hartman
2019-05-03 1:25 ` Tobin C. Harding
2019-05-03 6:27 ` Greg Kroah-Hartman
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20190502071742.GC16247@kroah.com \
--to=gregkh@linuxfoundation.org \
--cc=cl@linux.com \
--cc=linux-kernel@vger.kernel.org \
--cc=me@tobin.cc \
--cc=rafael@kernel.org \
--cc=tycho@tycho.ws \
--cc=willy@infradead.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.