[media] media-device: dynamically allocate struct media_devnode

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.

Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
This commit is contained in:
Mauro Carvalho Chehab 2016-04-27 19:28:26 -03:00 committed by Mauro Carvalho Chehab
parent 163f1e93e9
commit a087ce704b
6 changed files with 54 additions and 25 deletions

View file

@ -33,6 +33,8 @@
#include <linux/device.h>
#include <linux/cdev.h>
struct media_device;
/*
* Flag to mark the media_devnode struct as registered. Drivers must not touch
* this flag directly, it will be set and cleared by media_devnode_register and
@ -81,6 +83,8 @@ struct media_file_operations {
* before registering the node.
*/
struct media_devnode {
struct media_device *media_dev;
/* device ops */
const struct media_file_operations *fops;
@ -103,6 +107,7 @@ struct media_devnode {
/**
* media_devnode_register - register a media device node
*
* @media_dev: struct media_device we want to register a device node
* @devnode: media device node structure we want to register
* @owner: should be filled with %THIS_MODULE
*
@ -116,7 +121,8 @@ struct media_devnode {
* the media_devnode structure is *not* called, so the caller is responsible for
* freeing any data.
*/
int __must_check media_devnode_register(struct media_devnode *devnode,
int __must_check media_devnode_register(struct media_device *mdev,
struct media_devnode *devnode,
struct module *owner);
/**
@ -146,9 +152,14 @@ static inline struct media_devnode *media_devnode_data(struct file *filp)
* false otherwise.
*
* @devnode: pointer to struct &media_devnode.
*
* Note: If mdev is NULL, it also returns false.
*/
static inline int media_devnode_is_registered(struct media_devnode *devnode)
{
if (!devnode)
return false;
return test_bit(MEDIA_FLAG_REGISTERED, &devnode->flags);
}