Jason Gunthorpe <jgunthorpe-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/@public.gmane.org>
wrote on 02/12/2016 04:15:38 PM:
> From: Jason Gunthorpe <jgunthorpe-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/@public.gmane.org>
> To: Stefan Berger/Watson/IBM@IBMUS
> Cc: dhowells-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org, dwmw2-wEGCiKHe2LqWVfeAwA7xHQ@public.gmane.org,
Jarkko Sakkinen
> <jarkko.sakkinen-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>, tpmdd-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org
> Date: 02/12/2016 04:15 PM
> Subject: Re: [tpmdd-devel] [PATCH v5 4/5] Initialize
TPM and get
> durations and timeouts
>
> On Fri, Feb 12, 2016 at 03:44:14PM -0500, Stefan Berger wrote:
> > What I observed is that both tpm_chip and vtpm_dev
structures are freed
> > once the last one of two sides (/dev/tpmX or server
side file
> > descriptor) closes.
>
> Hmmm...
>
> I don't see how that can happen. Looking at the tpm cdev, it is
Well, following my tests, it does happen.
> continues to exist even after tpm_unregister returns (cdev_del does
> not force close existing opens). Certainly the kAPI (ie
> tpm_chip_find_get) will continue to use the chip without blocking
> tpm_unregister.
>
> I see no mechanism for the cdev/kAPI to continue to hold a kref on
the
> vtpm struct.
>
> The obvious one would be because the vtpm struct is a parent of the
> chip, but that kref is let go during device_del.
>
> So, we have a situation where tpm_unregister can return, release the
> kref on the vtpm and still have outstanding users, which will result
> in a use after-free.
Maybe you should give it a try ... I don't see these
problems and any change seems like ill-fixing it. What will be accessed
after tpm_unregister? The only case we have tpm_unregister is here:
static void vtpm_delete_device_pair(structvtpm_dev *vtpm_dev)
{
tpm_chip_unregister(vtpm_dev->chip);
vtpm_fops_undo_open(vtpm_dev);
vtpm_delete_vtpm_dev(vtpm_dev);
}
followed by:
static inline voidvtpm_delete_vtpm_dev(struct vtpm_dev *vtpm_dev)
{
put_device(&vtpm_dev->chip->dev);
/* frees chip */
device_unregister(&vtpm_dev->dev);
/* does put_device
*/
}
I don't see a problem with that.
>
> [BTW, your lastest vtpm on github still has a problem with error
> unwind. Move the put_device(&vtpm_dev->chip->dev);
from
> vtpm_delete_vtpm_dev() and put it in vtpm_dev_release() with
a NULL
> test.
I tested all the error paths. The vtpm_delete_vtpm_dev
is the counter-part to vtpm_create_vtpm_dev and only ever gets called if
vtpm_create_vtpm_dev ran successfully and is the function to call to unwind
vtpm_create_vtpm_dev. So if we unwind there in reverse order then we should
be ok. If not, why not ?
>
> The put_device is missing after the tpm_chip_unregister call,
the
> above is the safest way to fix it.
No, it's the vtpm_delete_vtpm_dev function that unwinds
it. I tested this and structures get freed properly.
>
> This is why you shouldn't wrapper put_device, anything but naked
> put_device is probably wrong]
>
> [Also, err_kfree should not exist in vtpm_create_vtpm_dev, always
> put_device after device_initialize returns, the comment near
the device_add
> is wrong, it is using the get_device done implicitly by
> device_initialize]
Fixed.
>
> [Don't forget to error check dev_set_name]
Fixed. Looks like 80% of the drivers don't check here.
Stefan
>
> Jason
>