mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-10 09:09:55 -04:00
[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:
committed by
Mauro Carvalho Chehab
parent
163f1e93e9
commit
a087ce704b
@@ -347,7 +347,7 @@ struct media_entity_notify {
|
||||
struct media_device {
|
||||
/* dev->driver_data points to this struct. */
|
||||
struct device *dev;
|
||||
struct media_devnode devnode;
|
||||
struct media_devnode *devnode;
|
||||
|
||||
char model[32];
|
||||
char driver_name[32];
|
||||
@@ -393,9 +393,6 @@ struct usb_device;
|
||||
#define MEDIA_DEV_NOTIFY_PRE_LINK_CH 0
|
||||
#define MEDIA_DEV_NOTIFY_POST_LINK_CH 1
|
||||
|
||||
/* media_devnode to media_device */
|
||||
#define to_media_device(node) container_of(node, struct media_device, devnode)
|
||||
|
||||
/**
|
||||
* media_entity_enum_init - Initialise an entity enumeration
|
||||
*
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user