aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMauro Carvalho Chehab <mchehab@osg.samsung.com>2016-04-27 18:28:26 -0400
committerMauro Carvalho Chehab <mchehab@s-opensource.com>2016-06-15 16:57:24 -0400
commita087ce704b802becbb4b0f2a20f2cb3f6911802e (patch)
tree6cfa3f4ac4ef03bc7f7cc5fe4180a956f470213b
parent163f1e93e995048b894c5fc86a6034d16beed740 (diff)
[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>
-rw-r--r--drivers/media/media-device.c44
-rw-r--r--drivers/media/media-devnode.c7
-rw-r--r--drivers/media/usb/au0828/au0828-core.c4
-rw-r--r--drivers/media/usb/uvc/uvc_driver.c2
-rw-r--r--include/media/media-device.h5
-rw-r--r--include/media/media-devnode.h13
6 files changed, 52 insertions, 23 deletions
diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c
index a1cd50f331f1..e61fa66d95df 100644
--- a/drivers/media/media-device.c
+++ b/drivers/media/media-device.c
@@ -423,7 +423,7 @@ static long media_device_ioctl(struct file *filp, unsigned int cmd,
423 unsigned long arg) 423 unsigned long arg)
424{ 424{
425 struct media_devnode *devnode = media_devnode_data(filp); 425 struct media_devnode *devnode = media_devnode_data(filp);
426 struct media_device *dev = to_media_device(devnode); 426 struct media_device *dev = devnode->media_dev;
427 long ret; 427 long ret;
428 428
429 mutex_lock(&dev->graph_mutex); 429 mutex_lock(&dev->graph_mutex);
@@ -495,7 +495,7 @@ static long media_device_compat_ioctl(struct file *filp, unsigned int cmd,
495 unsigned long arg) 495 unsigned long arg)
496{ 496{
497 struct media_devnode *devnode = media_devnode_data(filp); 497 struct media_devnode *devnode = media_devnode_data(filp);
498 struct media_device *dev = to_media_device(devnode); 498 struct media_device *dev = devnode->media_dev;
499 long ret; 499 long ret;
500 500
501 switch (cmd) { 501 switch (cmd) {
@@ -531,7 +531,8 @@ static const struct media_file_operations media_device_fops = {
531static ssize_t show_model(struct device *cd, 531static ssize_t show_model(struct device *cd,
532 struct device_attribute *attr, char *buf) 532 struct device_attribute *attr, char *buf)
533{ 533{
534 struct media_device *mdev = to_media_device(to_media_devnode(cd)); 534 struct media_devnode *devnode = to_media_devnode(cd);
535 struct media_device *mdev = devnode->media_dev;
535 536
536 return sprintf(buf, "%.*s\n", (int)sizeof(mdev->model), mdev->model); 537 return sprintf(buf, "%.*s\n", (int)sizeof(mdev->model), mdev->model);
537} 538}
@@ -704,23 +705,34 @@ EXPORT_SYMBOL_GPL(media_device_cleanup);
704int __must_check __media_device_register(struct media_device *mdev, 705int __must_check __media_device_register(struct media_device *mdev,
705 struct module *owner) 706 struct module *owner)
706{ 707{
708 struct media_devnode *devnode;
707 int ret; 709 int ret;
708 710
711 devnode = kzalloc(sizeof(*devnode), GFP_KERNEL);
712 if (!devnode)
713 return -ENOMEM;
714
709 /* Register the device node. */ 715 /* Register the device node. */
710 mdev->devnode.fops = &media_device_fops; 716 mdev->devnode = devnode;
711 mdev->devnode.parent = mdev->dev; 717 devnode->fops = &media_device_fops;
712 mdev->devnode.release = media_device_release; 718 devnode->parent = mdev->dev;
719 devnode->release = media_device_release;
713 720
714 /* Set version 0 to indicate user-space that the graph is static */ 721 /* Set version 0 to indicate user-space that the graph is static */
715 mdev->topology_version = 0; 722 mdev->topology_version = 0;
716 723
717 ret = media_devnode_register(&mdev->devnode, owner); 724 ret = media_devnode_register(mdev, devnode, owner);
718 if (ret < 0) 725 if (ret < 0) {
726 mdev->devnode = NULL;
727 kfree(devnode);
719 return ret; 728 return ret;
729 }
720 730
721 ret = device_create_file(&mdev->devnode.dev, &dev_attr_model); 731 ret = device_create_file(&devnode->dev, &dev_attr_model);
722 if (ret < 0) { 732 if (ret < 0) {
723 media_devnode_unregister(&mdev->devnode); 733 mdev->devnode = NULL;
734 media_devnode_unregister(devnode);
735 kfree(devnode);
724 return ret; 736 return ret;
725 } 737 }
726 738
@@ -771,7 +783,7 @@ void media_device_unregister(struct media_device *mdev)
771 mutex_lock(&mdev->graph_mutex); 783 mutex_lock(&mdev->graph_mutex);
772 784
773 /* Check if mdev was ever registered at all */ 785 /* Check if mdev was ever registered at all */
774 if (!media_devnode_is_registered(&mdev->devnode)) { 786 if (!media_devnode_is_registered(mdev->devnode)) {
775 mutex_unlock(&mdev->graph_mutex); 787 mutex_unlock(&mdev->graph_mutex);
776 return; 788 return;
777 } 789 }
@@ -794,9 +806,13 @@ void media_device_unregister(struct media_device *mdev)
794 806
795 mutex_unlock(&mdev->graph_mutex); 807 mutex_unlock(&mdev->graph_mutex);
796 808
797 device_remove_file(&mdev->devnode.dev, &dev_attr_model); 809 dev_dbg(mdev->dev, "Media device unregistered\n");
798 dev_dbg(mdev->dev, "Media device unregistering\n"); 810
799 media_devnode_unregister(&mdev->devnode); 811 /* Check if mdev devnode was registered */
812 if (media_devnode_is_registered(mdev->devnode)) {
813 device_remove_file(&mdev->devnode->dev, &dev_attr_model);
814 media_devnode_unregister(mdev->devnode);
815 }
800} 816}
801EXPORT_SYMBOL_GPL(media_device_unregister); 817EXPORT_SYMBOL_GPL(media_device_unregister);
802 818
diff --git a/drivers/media/media-devnode.c b/drivers/media/media-devnode.c
index 7481c9610945..ecdc02d6ed83 100644
--- a/drivers/media/media-devnode.c
+++ b/drivers/media/media-devnode.c
@@ -44,6 +44,7 @@
44#include <linux/uaccess.h> 44#include <linux/uaccess.h>
45 45
46#include <media/media-devnode.h> 46#include <media/media-devnode.h>
47#include <media/media-device.h>
47 48
48#define MEDIA_NUM_DEVICES 256 49#define MEDIA_NUM_DEVICES 256
49#define MEDIA_NAME "media" 50#define MEDIA_NAME "media"
@@ -74,6 +75,8 @@ static void media_devnode_release(struct device *cd)
74 /* Release media_devnode and perform other cleanups as needed. */ 75 /* Release media_devnode and perform other cleanups as needed. */
75 if (devnode->release) 76 if (devnode->release)
76 devnode->release(devnode); 77 devnode->release(devnode);
78
79 kfree(devnode);
77} 80}
78 81
79static struct bus_type media_bus_type = { 82static struct bus_type media_bus_type = {
@@ -219,7 +222,8 @@ static const struct file_operations media_devnode_fops = {
219 .llseek = no_llseek, 222 .llseek = no_llseek,
220}; 223};
221 224
222int __must_check media_devnode_register(struct media_devnode *devnode, 225int __must_check media_devnode_register(struct media_device *mdev,
226 struct media_devnode *devnode,
223 struct module *owner) 227 struct module *owner)
224{ 228{
225 int minor; 229 int minor;
@@ -238,6 +242,7 @@ int __must_check media_devnode_register(struct media_devnode *devnode,
238 mutex_unlock(&media_devnode_lock); 242 mutex_unlock(&media_devnode_lock);
239 243
240 devnode->minor = minor; 244 devnode->minor = minor;
245 devnode->media_dev = mdev;
241 246
242 /* Part 2: Initialize and register the character device */ 247 /* Part 2: Initialize and register the character device */
243 cdev_init(&devnode->cdev, &media_devnode_fops); 248 cdev_init(&devnode->cdev, &media_devnode_fops);
diff --git a/drivers/media/usb/au0828/au0828-core.c b/drivers/media/usb/au0828/au0828-core.c
index 321ea5cf1329..bf53553d2624 100644
--- a/drivers/media/usb/au0828/au0828-core.c
+++ b/drivers/media/usb/au0828/au0828-core.c
@@ -142,7 +142,7 @@ static void au0828_unregister_media_device(struct au0828_dev *dev)
142 struct media_device *mdev = dev->media_dev; 142 struct media_device *mdev = dev->media_dev;
143 struct media_entity_notify *notify, *nextp; 143 struct media_entity_notify *notify, *nextp;
144 144
145 if (!mdev || !media_devnode_is_registered(&mdev->devnode)) 145 if (!mdev || !media_devnode_is_registered(mdev->devnode))
146 return; 146 return;
147 147
148 /* Remove au0828 entity_notify callbacks */ 148 /* Remove au0828 entity_notify callbacks */
@@ -482,7 +482,7 @@ static int au0828_media_device_register(struct au0828_dev *dev,
482 if (!dev->media_dev) 482 if (!dev->media_dev)
483 return 0; 483 return 0;
484 484
485 if (!media_devnode_is_registered(&dev->media_dev->devnode)) { 485 if (!media_devnode_is_registered(dev->media_dev->devnode)) {
486 486
487 /* register media device */ 487 /* register media device */
488 ret = media_device_register(dev->media_dev); 488 ret = media_device_register(dev->media_dev);
diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c
index 451e84e962e2..302e284a95eb 100644
--- a/drivers/media/usb/uvc/uvc_driver.c
+++ b/drivers/media/usb/uvc/uvc_driver.c
@@ -1674,7 +1674,7 @@ static void uvc_delete(struct uvc_device *dev)
1674 if (dev->vdev.dev) 1674 if (dev->vdev.dev)
1675 v4l2_device_unregister(&dev->vdev); 1675 v4l2_device_unregister(&dev->vdev);
1676#ifdef CONFIG_MEDIA_CONTROLLER 1676#ifdef CONFIG_MEDIA_CONTROLLER
1677 if (media_devnode_is_registered(&dev->mdev.devnode)) 1677 if (media_devnode_is_registered(dev->mdev.devnode))
1678 media_device_unregister(&dev->mdev); 1678 media_device_unregister(&dev->mdev);
1679 media_device_cleanup(&dev->mdev); 1679 media_device_cleanup(&dev->mdev);
1680#endif 1680#endif
diff --git a/include/media/media-device.h b/include/media/media-device.h
index a9b33c47310d..f743ae2210ee 100644
--- a/include/media/media-device.h
+++ b/include/media/media-device.h
@@ -347,7 +347,7 @@ struct media_entity_notify {
347struct media_device { 347struct media_device {
348 /* dev->driver_data points to this struct. */ 348 /* dev->driver_data points to this struct. */
349 struct device *dev; 349 struct device *dev;
350 struct media_devnode devnode; 350 struct media_devnode *devnode;
351 351
352 char model[32]; 352 char model[32];
353 char driver_name[32]; 353 char driver_name[32];
@@ -393,9 +393,6 @@ struct usb_device;
393#define MEDIA_DEV_NOTIFY_PRE_LINK_CH 0 393#define MEDIA_DEV_NOTIFY_PRE_LINK_CH 0
394#define MEDIA_DEV_NOTIFY_POST_LINK_CH 1 394#define MEDIA_DEV_NOTIFY_POST_LINK_CH 1
395 395
396/* media_devnode to media_device */
397#define to_media_device(node) container_of(node, struct media_device, devnode)
398
399/** 396/**
400 * media_entity_enum_init - Initialise an entity enumeration 397 * media_entity_enum_init - Initialise an entity enumeration
401 * 398 *
diff --git a/include/media/media-devnode.h b/include/media/media-devnode.h
index e1d5af077adb..5bb3b0e86d73 100644
--- a/include/media/media-devnode.h
+++ b/include/media/media-devnode.h
@@ -33,6 +33,8 @@
33#include <linux/device.h> 33#include <linux/device.h>
34#include <linux/cdev.h> 34#include <linux/cdev.h>
35 35
36struct media_device;
37
36/* 38/*
37 * Flag to mark the media_devnode struct as registered. Drivers must not touch 39 * Flag to mark the media_devnode struct as registered. Drivers must not touch
38 * this flag directly, it will be set and cleared by media_devnode_register and 40 * this flag directly, it will be set and cleared by media_devnode_register and
@@ -81,6 +83,8 @@ struct media_file_operations {
81 * before registering the node. 83 * before registering the node.
82 */ 84 */
83struct media_devnode { 85struct media_devnode {
86 struct media_device *media_dev;
87
84 /* device ops */ 88 /* device ops */
85 const struct media_file_operations *fops; 89 const struct media_file_operations *fops;
86 90
@@ -103,6 +107,7 @@ struct media_devnode {
103/** 107/**
104 * media_devnode_register - register a media device node 108 * media_devnode_register - register a media device node
105 * 109 *
110 * @media_dev: struct media_device we want to register a device node
106 * @devnode: media device node structure we want to register 111 * @devnode: media device node structure we want to register
107 * @owner: should be filled with %THIS_MODULE 112 * @owner: should be filled with %THIS_MODULE
108 * 113 *
@@ -116,7 +121,8 @@ struct media_devnode {
116 * the media_devnode structure is *not* called, so the caller is responsible for 121 * the media_devnode structure is *not* called, so the caller is responsible for
117 * freeing any data. 122 * freeing any data.
118 */ 123 */
119int __must_check media_devnode_register(struct media_devnode *devnode, 124int __must_check media_devnode_register(struct media_device *mdev,
125 struct media_devnode *devnode,
120 struct module *owner); 126 struct module *owner);
121 127
122/** 128/**
@@ -146,9 +152,14 @@ static inline struct media_devnode *media_devnode_data(struct file *filp)
146 * false otherwise. 152 * false otherwise.
147 * 153 *
148 * @devnode: pointer to struct &media_devnode. 154 * @devnode: pointer to struct &media_devnode.
155 *
156 * Note: If mdev is NULL, it also returns false.
149 */ 157 */
150static inline int media_devnode_is_registered(struct media_devnode *devnode) 158static inline int media_devnode_is_registered(struct media_devnode *devnode)
151{ 159{
160 if (!devnode)
161 return false;
162
152 return test_bit(MEDIA_FLAG_REGISTERED, &devnode->flags); 163 return test_bit(MEDIA_FLAG_REGISTERED, &devnode->flags);
153} 164}
154 165