From: Shuah Khan <shuahkh@osg.samsung.com>
To: Sakari Ailus <sakari.ailus@iki.fi>,
Mauro Carvalho Chehab <mchehab@osg.samsung.com>
Cc: "Linux Media Mailing List" <linux-media@vger.kernel.org>,
"Mauro Carvalho Chehab" <mchehab@infradead.org>,
"Laurent Pinchart" <laurent.pinchart@ideasonboard.com>,
"Hans Verkuil" <hans.verkuil@cisco.com>,
"Rafael Lourenço de Lima Chehab" <chehabrafael@gmail.com>,
"Javier Martinez Canillas" <javier@osg.samsung.com>,
"Shuah Khan" <shuahkh@osg.samsung.com>
Subject: Re: [PATCH 2/2] [media] media-device: dynamically allocate struct media_devnode
Date: Mon, 6 Jun 2016 17:13:12 -0600 [thread overview]
Message-ID: <57560388.7030903@osg.samsung.com> (raw)
In-Reply-To: <20160606084500.GW26360@valkosipuli.retiisi.org.uk>
Hi Sakari,
On 06/06/2016 02:45 AM, Sakari Ailus wrote:
> Hi Mauro,
>
> On Sat, May 07, 2016 at 12:12:09PM -0300, Mauro Carvalho Chehab wrote:
>> struct media_devnode is currently embedded at struct media_device.
>>
>> While this works fine during normal usage, it leads to a race
>> condition during devnode unregister. the problem is that drivers
>> assume that, after calling media_device_unregister(), the struct
>> that contains media_device can be freed. This is not true, as it
>> can't be freed until userspace closes all opened /dev/media devnodes.
>>
>> In other words, if the media devnode is still open, and media_device
>> gets freed, any call to an ioctl will make the core to try to access
>> struct media_device, with will cause an use-after-free and even GPF.
>>
>> Fix this by dynamically allocating the struct media_devnode and only
>> freeing it when it is safe.
>
> A few general comments on the patch --- I agree we've had the problem from
> the day one, but it's really started showing up recently. I agree with the
> taken approach of separating the lifetimes of both media device and the
> devnode. However, I don't think the patch as such is enough.
It is more like, we started actively testing for this problem. I added a new
test under selftests/media for this problem. Laurent brought this up at our
Finland media summit and I have been looking to solve this since then starting
with writing a test to reliably reproduce the problem.
You are right that this patch alone isn't enough and I sent in another patch that
sets cdev kref parent to media_devnode struct device kref.
https://patchwork.linuxtv.org/patch/34201/
>
> For one, there are some issue that remain. In particular, access to the data
> structures (i.e. media_device and media_devnode) aren't serialised: the
> IOCTL or a system call passes media-devnode framework asynchronously with a
> possible unregister() call coming from media_device_unregister() (in
> media-device.c). This may, unless I'm mistaken, to the following sequence:
>
> process 1 process 2
> fd = open(/dev/media0)
>
> media_device_unregister()
> (things are being cleaned up
> here but the devnode isn't
> unregistered yet)
> ...
> ioctl(fd, ...)
> __media_ioctl()
> media_devnode_is_registered()
> (returns true here)
> ...
> media_devnode_unregister()
> ...
> (driver releases the media device
> memory)
>
> media_device_ioctl()
> (By this point
> devnode->media_dev does not
> point to allocated memory.
> Bad things will happen here.)
>
>
> You could try to serialise the operations. I wonder how ugly that might
> be, and I'm not sure this would be a workable approach.
I don't believe this problem can be solved with serializing operations.
media_devnode_is_registered() relies on media devnode to be valid until
the corresponding close is done.
We have:
struct media_device embedding struct media_devnode and media_devnode
embeds cdev. Each one of these have their own refcounts. media_device
can be released even when the cdev is busy. When media_device is released,
media_devnode goes away. The only sure way to ensure media_devnode sticks
around is by dynamically allocating it. This decouples media_devnode life
time management from media_device management. Granted media_devnode is tied
to media_device, but by decoupling, we make the media_devnode_is_registered()
safe even when media_device is released.
The next step is coupling media_devnode cdev lifetime with media_devnode
lifetime, by setting devnode strucr device kobj as the cdev kobj parent.
Please see the following patch I sent out:
https://patchwork.linuxtv.org/patch/34201/
This patch ensures devnode isn't released until the last application
closes the device and the last cdev kobj parent is released.
>
> Secondly, a dependency is created from media devnode (i.e. media devnode
> becomes aware of the media device). This is against the original design of
> the two, as the media devnode was intended for other kinds of device nodes
> as well and is more generic than media device. I'm not necessarily arguing
> we have to keep it this way (as media devnode is only used by media device),
> but if we're not keeping it then it'd make sense to unify the two to keep it
> clean.
Unless there is a string reason to not make media devnode aware of the media
device, this is a good direction. As such, our current design is not ideal.
media devnode isn't aware of the structure its life depends on. :)
>
>
> Have you thought about taking a reference to the said structs (by the means
> of kref) where one is acquired?
>
> That way, we should be able to rather easily keep around everything that's
> needed until the last remaining user has gone away: opening a file handle
> should get a reference to both media device and media devnode as well as
> registering them (media_device_register() and media_devnode_register()).
Please see above. The patch I sent out does this exactly. Decoupling devnode
from media_device structure is necessary to avoid multiple concurrent lifetimes.
I do think, this is a good direction for us to go. I also have media device
allocator patch API out and reviewed which is based on these two patches and
it is simple and clean as I could rely on this problem being addressed with
these two patches.
thanks,
-- Shuah
next prev parent reply other threads:[~2016-06-06 23:13 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-05-07 15:12 [PATCH 0/2] Prepare for cdev fixes Mauro Carvalho Chehab
2016-05-07 15:12 ` [PATCH 1/2] [media] media-devnode: fix namespace mess Mauro Carvalho Chehab
2016-05-07 15:12 ` [PATCH 2/2] [media] media-device: dynamically allocate struct media_devnode Mauro Carvalho Chehab
2016-05-09 11:40 ` Laurent Pinchart
2016-05-09 15:03 ` Mauro Carvalho Chehab
2016-05-10 0:42 ` Shuah Khan
2016-06-06 8:45 ` Sakari Ailus
2016-06-06 23:13 ` Shuah Khan [this message]
2016-06-07 13:11 ` Mauro Carvalho Chehab
2016-06-09 23:22 ` Sakari Ailus
2016-05-07 15:27 ` [PATCH 0/2] Prepare for cdev fixes Mauro Carvalho Chehab
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=57560388.7030903@osg.samsung.com \
--to=shuahkh@osg.samsung.com \
--cc=chehabrafael@gmail.com \
--cc=hans.verkuil@cisco.com \
--cc=javier@osg.samsung.com \
--cc=laurent.pinchart@ideasonboard.com \
--cc=linux-media@vger.kernel.org \
--cc=mchehab@infradead.org \
--cc=mchehab@osg.samsung.com \
--cc=sakari.ailus@iki.fi \
/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