public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
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

  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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox