All of lore.kernel.org
 help / color / mirror / Atom feed
From: Zeng Heng <zengheng4@huawei.com>
To: Kent Gibson <warthog618@gmail.com>,
	Andy Shevchenko <andriy.shevchenko@intel.com>,
	<linux@roeck-us.net>
Cc: <linus.walleij@linaro.org>, <brgl@bgdev.pl>,
	<linux-gpio@vger.kernel.org>, <liwei391@huawei.com>,
	<yuancan@huawei.com>,
	Linux Kernel Mailing List <linux-kernel@vger.kernel.org>
Subject: Re: [PATCH v2] gpiolib: fix memory leak in gpiochip_setup_dev
Date: Thu, 10 Nov 2022 10:36:53 +0800	[thread overview]
Message-ID: <f118d0b1-1bf2-b710-c3b4-2745c72f02b3@huawei.com> (raw)
In-Reply-To: <Y2xTSyce8WfLdtge@sol>


On 2022/11/10 9:26, Kent Gibson wrote:
> On Wed, Nov 09, 2022 at 04:47:08PM +0200, Andy Shevchenko wrote:
>> On Wed, Nov 09, 2022 at 05:31:20PM +0800, Zeng Heng wrote:
>>> gcdev_register & gcdev_unregister call device_add & device_del to
>>> request/release source. But in device_add, the dev->p allocated by
>>> device_private_init is not released by device_del.
>> First of all, we refer to the functions like func().
Thanks, it would be updated in next version.
> Further to this, the description of the problem could be clearer -
> it would be helpful to indicate the code path that triggers the problem
> - it is gpiochip_sysfs_register() returning an error?
>
>>> So when calling gcdev_unregister to release gdev, it needs put_device
>>> to release dev in the following.
>>>
>>> Otherwise, kmemleak would report memory leak such as below:
>>>
>>> unreferenced object 0xffff88810b406400 (size 512):
>>>    comm "python3", pid 1682, jiffies 4295346908 (age 24.090s)
>>>    hex dump (first 32 bytes):
>>>      00 00 00 00 ad 4e ad de ff ff ff ff 00 00 00 00  .....N..........
>>>      ff ff ff ff ff ff ff ff a0 5e 23 90 ff ff ff ff  .........^#.....
>>>    backtrace:
>> Second, read Submitting Patches on how to provide your backtraces in the
>> message body.

Thanks, it would be updated in next version.

>>
>>>      [<00000000a58ee5fe>] kmalloc_trace+0x22/0x110
>>>      [<0000000045fe2058>] device_add+0xb34/0x1130
>>>      [<00000000d778b45f>] cdev_device_add+0x83/0xe0
>>>      [<0000000089f948ed>] gpiolib_cdev_register+0x73/0xa0
>>>      [<00000000a3a8a316>] gpiochip_setup_dev+0x1c/0x70
>>>      [<00000000787227b4>] gpiochip_add_data_with_key+0x10f6/0x1bf0
>>>      [<000000009ac5742c>] devm_gpiochip_add_data_with_key+0x2e/0x80
>>>      [<00000000bf2b23d9>] xra1403_probe+0x192/0x1b0 [gpio_xra1403]
>>>      [<000000005b5ef2d4>] spi_probe+0xe1/0x140
>>>      [<000000002b26f6f1>] really_probe+0x17c/0x3f0
>>>      [<00000000dd2dad9c>] __driver_probe_device+0xe3/0x170
>>>      [<000000005ca60d2a>] device_driver_attach+0x34/0x80
>>>      [<00000000e9db90db>] bind_store+0x10b/0x1a0
>>>      [<00000000e2650f8a>] drv_attr_store+0x49/0x70
>>>      [<0000000080a80b2b>] sysfs_kf_write+0x8c/0xb0
>>>      [<00000000a28b45b9>] kernfs_fop_write_iter+0x216/0x2e0
>>>
>>> unreferenced object 0xffff888100de9800 (size 512):
>>>    comm "python3", pid 264, jiffies 4294737615 (age 33.514s)
>>>    hex dump (first 32 bytes):
>>>      00 00 00 00 ad 4e ad de ff ff ff ff 00 00 00 00  .....N..........
>>>      ff ff ff ff ff ff ff ff a0 5e 63 a1 ff ff ff ff  .........^c.....
>>>    backtrace:
>>>      [<00000000bcc571d0>] kmalloc_trace+0x22/0x110
>>>      [<00000000eeb06124>] device_add+0xb34/0x1130
>>>      [<000000007e5cd2fd>] cdev_device_add+0x83/0xe0
>>>      [<000000008f6bcd3a>] gpiolib_cdev_register+0x73/0xa0
>>>      [<0000000012c93b24>] gpiochip_setup_dev+0x1c/0x70
>>>      [<00000000a24b646a>] gpiochip_add_data_with_key+0x10f6/0x1bf0
>>>      [<000000000c225212>] tpic2810_probe+0x16e/0x196 [gpio_tpic2810]
>>>      [<00000000b52d04ff>] i2c_device_probe+0x651/0x680
>>>      [<0000000058d3ff6b>] really_probe+0x17c/0x3f0
>>>      [<00000000586f43d3>] __driver_probe_device+0xe3/0x170
>>>      [<000000003f428602>] device_driver_attach+0x34/0x80
>>>      [<0000000040e91a1b>] bind_store+0x10b/0x1a0
>>>      [<00000000c1d990b9>] drv_attr_store+0x49/0x70
>>>      [<00000000a23bfc22>] sysfs_kf_write+0x8c/0xb0
>>>      [<00000000064e6572>] kernfs_fop_write_iter+0x216/0x2e0
>>>      [<00000000026ce093>] vfs_write+0x658/0x810
>>>
>>> Because at the point of gpiochip_setup_dev here, where dev.release
>>> does not set yet, calling put_device would cause the warning of
>>> no release function and double-free in the following fault handler
>>> route (when kfree dev_name). So directly calling kfree to release
>>> dev->p here in case of memory leak.
> Again, this could be clearer.  The dev->p is normally freed by
> device_release() - why is that not happening in this case?
> (as put_device() is never called in this path)
>
> The double free you see if you do call put_device() appears to be due to
> different expectations as to the cleanup that gpiochip_setup_dev() will
> perform on error, depending on where it is called. gpiochip_setup_devs()
> assumes any cleanup is performed by gpiochip_setup_dev(), while
> gpiochip_add_data_with_key() assumes that it hasn't performed any cleanup.
>
> Having gpiochip_setup_dev() perform its own cleanup makes the most sense
> to me, so gpiochip_add_data_with_key() should be changed to allow for
> that.


Right, the cleanup route of gpiochip_add_data_with_key() & 
gpiochip_setup_dev()

has to be considered comprehensively after any possible cases of fault 
injections.


>> ...
>>
>>> @@ -539,6 +539,7 @@ static int gpiochip_setup_dev(struct gpio_device *gdev)
>>>   
>>>   err_remove_device:
>>>   	gcdev_unregister(gdev);
>>> +	kfree(gdev->dev.p);
>>>   	return ret;
>> Third, I do not believe it's a correct fix.
>> Have you read comments around device_del() / etc.?

Yes, not only the comments I read, but also the device_del() implement code.

Releasing the dev->p pointer is not the business with device_del(), but 
it's relied on

put_device() calling release function.

Turning back here, the release function is not set yet at this point, 
there is a gap

between device_add() and set release function pointer.

That's the reason why choose to free dev->p explicitly as the mail 
mentioned above.

> I agree - this is not the correct fix.  The correct fix is to trigger the
> normal cleanup mechanism, so put_device().
> The fact that that triggers a warning:
>
> "Device '%s' does not have a release() function, it is broken and must be
> fixed. See Documentation/core-api/kobject.rst.\n"
>
> is an indicator that dev.release should be set earlier.
> If gpiodevice_release() is not appropriate, or cannot be modified to deal
> with the device state at that point, then an appropriate interim release
> function should be set.
>
> And, as mentioned above, gpiochip_add_data_with_key() needs to be modified
> to allow for gpiochip_setup_dev() cleaning up its own mess.
>
> That is my take, but that is just from perusing the code so I may be
> totally off base.  Either way, an ACK/NACK on this from a maintainer or
> other gpiolib expert would be helpful to expiditing a solution.
>
> Cheers,
> Kent.

Yes, exactly.

Thanks to all,

Zeng Heng


  reply	other threads:[~2022-11-10  2:37 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-11-08 11:53 [PATCH] gpiolib: fix memory leak in gpiochip_setup_dev Zeng Heng
2022-11-08 16:57 ` Kent Gibson
2022-11-09  5:12   ` Kent Gibson
2022-11-09  8:27     ` Zeng Heng
2022-11-09  9:06       ` Kent Gibson
2022-11-09  9:31         ` [PATCH v2] " Zeng Heng
2022-11-09 14:47           ` Andy Shevchenko
2022-11-10  1:26             ` Kent Gibson
2022-11-10  2:36               ` Zeng Heng [this message]
2022-11-17  9:02                 ` [PATCH v3] gpiolib: fix memory leak in gpiochip_setup_dev() Zeng Heng
2022-11-17 10:49                   ` Andy Shevchenko
2022-11-17 14:12                     ` Zeng Heng
2022-11-17 15:31                       ` Andy Shevchenko
2022-11-18  2:22                         ` [PATCH v4] " Zeng Heng
2022-11-18 10:28                           ` Andy Shevchenko
2022-11-18  2:31                         ` [PATCH v3] " Zeng Heng

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=f118d0b1-1bf2-b710-c3b4-2745c72f02b3@huawei.com \
    --to=zengheng4@huawei.com \
    --cc=andriy.shevchenko@intel.com \
    --cc=brgl@bgdev.pl \
    --cc=linus.walleij@linaro.org \
    --cc=linux-gpio@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux@roeck-us.net \
    --cc=liwei391@huawei.com \
    --cc=warthog618@gmail.com \
    --cc=yuancan@huawei.com \
    /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.