* [PATCH 1/4] media: dvb-core: Fix use-after-free due to race condition occurring in dvb_frontend
2022-11-15 13:18 [PATCH 0/4] Fix multiple race condition vulnerabilities in dvb-core and device driver imv4bel
@ 2022-11-15 13:18 ` imv4bel
2022-11-15 13:18 ` [PATCH 2/4] media: dvb-core: Fix use-after-free due to race condition occurring in dvb_net imv4bel
` (2 subsequent siblings)
3 siblings, 0 replies; 6+ messages in thread
From: imv4bel @ 2022-11-15 13:18 UTC (permalink / raw)
To: mchehab; +Cc: Hyunwoo Kim, kernel, linux-media, linux-usb, cai.huoqing, tiwai
From: Hyunwoo Kim <imv4bel@gmail.com>
If the device node of dvb_frontend is open() and the device is
disconnected, many kinds of UAFs may occur when calling close()
on the device node.
The root cause of this is that wake_up() for dvbdev->wait_queue
is implemented in the dvb_frontend_release() function, but
wait_event() is not implemented in the dvb_frontend_stop() function.
So, implement wait_event() function in dvb_frontend_stop() and
add 'remove_mutex' which prevents race condition for 'fe->exit'.
Signed-off-by: Hyunwoo Kim <imv4bel@gmail.com>
---
drivers/media/dvb-core/dvb_frontend.c | 39 +++++++++++++++++++++++----
include/media/dvb_frontend.h | 6 ++++-
2 files changed, 39 insertions(+), 6 deletions(-)
diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c
index 48e735cdbe6b..b3556e3580c6 100644
--- a/drivers/media/dvb-core/dvb_frontend.c
+++ b/drivers/media/dvb-core/dvb_frontend.c
@@ -809,6 +809,8 @@ static void dvb_frontend_stop(struct dvb_frontend *fe)
dev_dbg(fe->dvb->device, "%s:\n", __func__);
+ mutex_lock(&fe->remove_mutex);
+
if (fe->exit != DVB_FE_DEVICE_REMOVED)
fe->exit = DVB_FE_NORMAL_EXIT;
mb();
@@ -818,6 +820,13 @@ static void dvb_frontend_stop(struct dvb_frontend *fe)
kthread_stop(fepriv->thread);
+ mutex_unlock(&fe->remove_mutex);
+
+ if (fepriv->dvbdev->users < -1) {
+ wait_event(fepriv->dvbdev->wait_queue,
+ fepriv->dvbdev->users == -1);
+ }
+
sema_init(&fepriv->sem, 1);
fepriv->state = FESTATE_IDLE;
@@ -2750,9 +2759,13 @@ static int dvb_frontend_open(struct inode *inode, struct file *file)
struct dvb_adapter *adapter = fe->dvb;
int ret;
+ mutex_lock(&fe->remove_mutex);
+
dev_dbg(fe->dvb->device, "%s:\n", __func__);
- if (fe->exit == DVB_FE_DEVICE_REMOVED)
+ if (fe->exit == DVB_FE_DEVICE_REMOVED) {
+ mutex_unlock(&fe->remove_mutex);
return -ENODEV;
+ }
if (adapter->mfe_shared) {
mutex_lock(&adapter->mfe_lock);
@@ -2773,8 +2786,10 @@ static int dvb_frontend_open(struct inode *inode, struct file *file)
while (mferetry-- && (mfedev->users != -1 ||
mfepriv->thread)) {
if (msleep_interruptible(500)) {
- if (signal_pending(current))
+ if (signal_pending(current)) {
+ mutex_unlock(&fe->remove_mutex);
return -EINTR;
+ }
}
}
@@ -2786,6 +2801,7 @@ static int dvb_frontend_open(struct inode *inode, struct file *file)
if (mfedev->users != -1 ||
mfepriv->thread) {
mutex_unlock(&adapter->mfe_lock);
+ mutex_unlock(&fe->remove_mutex);
return -EBUSY;
}
adapter->mfe_dvbdev = dvbdev;
@@ -2845,6 +2861,8 @@ static int dvb_frontend_open(struct inode *inode, struct file *file)
if (adapter->mfe_shared)
mutex_unlock(&adapter->mfe_lock);
+
+ mutex_unlock(&fe->remove_mutex);
return ret;
err3:
@@ -2866,6 +2884,8 @@ static int dvb_frontend_open(struct inode *inode, struct file *file)
err0:
if (adapter->mfe_shared)
mutex_unlock(&adapter->mfe_lock);
+
+ mutex_unlock(&fe->remove_mutex);
return ret;
}
@@ -2876,6 +2896,8 @@ static int dvb_frontend_release(struct inode *inode, struct file *file)
struct dvb_frontend_private *fepriv = fe->frontend_priv;
int ret;
+ mutex_lock(&fe->remove_mutex);
+
dev_dbg(fe->dvb->device, "%s:\n", __func__);
if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
@@ -2897,11 +2919,17 @@ static int dvb_frontend_release(struct inode *inode, struct file *file)
}
mutex_unlock(&fe->dvb->mdev_lock);
#endif
- if (fe->exit != DVB_FE_NO_EXIT)
- wake_up(&dvbdev->wait_queue);
if (fe->ops.ts_bus_ctrl)
fe->ops.ts_bus_ctrl(fe, 0);
- }
+
+ if (fe->exit != DVB_FE_NO_EXIT) {
+ mutex_unlock(&fe->remove_mutex);
+ wake_up(&dvbdev->wait_queue);
+ } else
+ mutex_unlock(&fe->remove_mutex);
+
+ } else
+ mutex_unlock(&fe->remove_mutex);
dvb_frontend_put(fe);
@@ -3000,6 +3028,7 @@ int dvb_register_frontend(struct dvb_adapter *dvb,
fepriv = fe->frontend_priv;
kref_init(&fe->refcount);
+ mutex_init(&fe->remove_mutex);
/*
* After initialization, there need to be two references: one
diff --git a/include/media/dvb_frontend.h b/include/media/dvb_frontend.h
index e7c44870f20d..411ec32cd8df 100644
--- a/include/media/dvb_frontend.h
+++ b/include/media/dvb_frontend.h
@@ -686,7 +686,10 @@ struct dtv_frontend_properties {
* @id: Frontend ID
* @exit: Used to inform the DVB core that the frontend
* thread should exit (usually, means that the hardware
- * got disconnected.
+ * got disconnected.)
+ * @remove_mutex: mutex that avoids a race condition between a callback
+ * called when the hardware is disconnected and the
+ * file_operations of dvb_frontend
*/
struct dvb_frontend {
@@ -704,6 +707,7 @@ struct dvb_frontend {
int (*callback)(void *adapter_priv, int component, int cmd, int arg);
int id;
unsigned int exit;
+ struct mutex remove_mutex;
};
/**
--
2.25.1
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH 2/4] media: dvb-core: Fix use-after-free due to race condition occurring in dvb_net
2022-11-15 13:18 [PATCH 0/4] Fix multiple race condition vulnerabilities in dvb-core and device driver imv4bel
2022-11-15 13:18 ` [PATCH 1/4] media: dvb-core: Fix use-after-free due to race condition occurring in dvb_frontend imv4bel
@ 2022-11-15 13:18 ` imv4bel
2022-11-15 13:18 ` [PATCH 3/4] media: dvb-core: Fix use-after-free due to race condition occurring in dvb_register_device() imv4bel
2022-11-15 13:18 ` [PATCH 4/4] media: ttusb-dec: Fix memory leak in ttusb_dec_exit_dvb() imv4bel
3 siblings, 0 replies; 6+ messages in thread
From: imv4bel @ 2022-11-15 13:18 UTC (permalink / raw)
To: mchehab; +Cc: Hyunwoo Kim, kernel, linux-media, linux-usb, cai.huoqing, tiwai
From: Hyunwoo Kim <imv4bel@gmail.com>
A race condition may occur between the .disconnect function, which
is called when the device is disconnected, and the dvb_device_open()
function, which is called when the device node is open()ed.
This results in several types of UAFs.
The root cause of this is that you use the dvb_device_open() function,
which does not implement a conditional statement
that checks 'dvbnet->exit'.
So, add 'remove_mutex` to protect 'dvbnet->exit' and use
locked_dvb_net_open() function to check 'dvbnet->exit'.
Signed-off-by: Hyunwoo Kim <imv4bel@gmail.com>
---
drivers/media/dvb-core/dvb_net.c | 37 +++++++++++++++++++++++++++++---
include/media/dvb_net.h | 4 ++++
2 files changed, 38 insertions(+), 3 deletions(-)
diff --git a/drivers/media/dvb-core/dvb_net.c b/drivers/media/dvb-core/dvb_net.c
index 8a2febf33ce2..bdfc6609cb93 100644
--- a/drivers/media/dvb-core/dvb_net.c
+++ b/drivers/media/dvb-core/dvb_net.c
@@ -1564,15 +1564,42 @@ static long dvb_net_ioctl(struct file *file,
return dvb_usercopy(file, cmd, arg, dvb_net_do_ioctl);
}
+static int locked_dvb_net_open(struct inode *inode, struct file *file)
+{
+ struct dvb_device *dvbdev = file->private_data;
+ struct dvb_net *dvbnet = dvbdev->priv;
+ int ret;
+
+ if (mutex_lock_interruptible(&dvbnet->remove_mutex))
+ return -ERESTARTSYS;
+
+ if (dvbnet->exit) {
+ mutex_unlock(&dvbnet->remove_mutex);
+ return -ENODEV;
+ }
+
+ ret = dvb_generic_open(inode, file);
+
+ mutex_unlock(&dvbnet->remove_mutex);
+
+ return ret;
+}
+
static int dvb_net_close(struct inode *inode, struct file *file)
{
struct dvb_device *dvbdev = file->private_data;
struct dvb_net *dvbnet = dvbdev->priv;
+ mutex_lock(&dvbnet->remove_mutex);
+
dvb_generic_release(inode, file);
- if(dvbdev->users == 1 && dvbnet->exit == 1)
+ if (dvbdev->users == 1 && dvbnet->exit == 1) {
+ mutex_unlock(&dvbnet->remove_mutex);
wake_up(&dvbdev->wait_queue);
+ } else
+ mutex_unlock(&dvbnet->remove_mutex);
+
return 0;
}
@@ -1580,7 +1607,7 @@ static int dvb_net_close(struct inode *inode, struct file *file)
static const struct file_operations dvb_net_fops = {
.owner = THIS_MODULE,
.unlocked_ioctl = dvb_net_ioctl,
- .open = dvb_generic_open,
+ .open = locked_dvb_net_open,
.release = dvb_net_close,
.llseek = noop_llseek,
};
@@ -1599,10 +1626,13 @@ void dvb_net_release (struct dvb_net *dvbnet)
{
int i;
+ mutex_lock(&dvbnet->remove_mutex);
dvbnet->exit = 1;
+ mutex_unlock(&dvbnet->remove_mutex);
+
if (dvbnet->dvbdev->users < 1)
wait_event(dvbnet->dvbdev->wait_queue,
- dvbnet->dvbdev->users==1);
+ dvbnet->dvbdev->users == 1);
dvb_unregister_device(dvbnet->dvbdev);
@@ -1621,6 +1651,7 @@ int dvb_net_init (struct dvb_adapter *adap, struct dvb_net *dvbnet,
int i;
mutex_init(&dvbnet->ioctl_mutex);
+ mutex_init(&dvbnet->remove_mutex);
dvbnet->demux = dmx;
for (i=0; i<DVB_NET_DEVICES_MAX; i++)
diff --git a/include/media/dvb_net.h b/include/media/dvb_net.h
index 5e31d37f25fa..3e2eee5a05e5 100644
--- a/include/media/dvb_net.h
+++ b/include/media/dvb_net.h
@@ -41,6 +41,9 @@
* @exit: flag to indicate when the device is being removed.
* @demux: pointer to &struct dmx_demux.
* @ioctl_mutex: protect access to this struct.
+ * @remove_mutex: mutex that avoids a race condition between a callback
+ * called when the hardware is disconnected and the
+ * file_operations of dvb_net
*
* Currently, the core supports up to %DVB_NET_DEVICES_MAX (10) network
* devices.
@@ -53,6 +56,7 @@ struct dvb_net {
unsigned int exit:1;
struct dmx_demux *demux;
struct mutex ioctl_mutex;
+ struct mutex remove_mutex;
};
/**
--
2.25.1
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH 3/4] media: dvb-core: Fix use-after-free due to race condition occurring in dvb_register_device()
2022-11-15 13:18 [PATCH 0/4] Fix multiple race condition vulnerabilities in dvb-core and device driver imv4bel
2022-11-15 13:18 ` [PATCH 1/4] media: dvb-core: Fix use-after-free due to race condition occurring in dvb_frontend imv4bel
2022-11-15 13:18 ` [PATCH 2/4] media: dvb-core: Fix use-after-free due to race condition occurring in dvb_net imv4bel
@ 2022-11-15 13:18 ` imv4bel
2022-11-17 4:16 ` Dan Carpenter
2022-11-15 13:18 ` [PATCH 4/4] media: ttusb-dec: Fix memory leak in ttusb_dec_exit_dvb() imv4bel
3 siblings, 1 reply; 6+ messages in thread
From: imv4bel @ 2022-11-15 13:18 UTC (permalink / raw)
To: mchehab; +Cc: Hyunwoo Kim, kernel, linux-media, linux-usb, cai.huoqing, tiwai
From: Hyunwoo Kim <imv4bel@gmail.com>
dvb_register_device() dynamically allocates fops with kmemdup()
to set the fops->owner.
And these fops are registered in 'file->f_ops' using replace_fops()
in the dvb_device_open() process, and kfree()d in dvb_free_device().
However, it is not common to use dynamically allocated fops instead
of 'static const' fops as an argument of replace_fops(),
and UAF may occur.
These UAFs can occur on any dvb type using dvb_register_device(),
such as dvb_dvr, dvb_demux, dvb_frontend, dvb_net, etc.
So, instead of kfree() the fops dynamically allocated in
dvb_register_device() in dvb_free_device() called during the
.disconnect() process, kfree() it collectively in exit_dvbdev()
called when the dvbdev.c module is removed.
Signed-off-by: Hyunwoo Kim <imv4bel@gmail.com>
---
drivers/media/dvb-core/dvbdev.c | 83 ++++++++++++++++++++++++---------
include/media/dvbdev.h | 15 ++++++
2 files changed, 77 insertions(+), 21 deletions(-)
diff --git a/drivers/media/dvb-core/dvbdev.c b/drivers/media/dvb-core/dvbdev.c
index 675d877a67b2..424cf92c068e 100644
--- a/drivers/media/dvb-core/dvbdev.c
+++ b/drivers/media/dvb-core/dvbdev.c
@@ -27,6 +27,7 @@
#include <media/tuner.h>
static DEFINE_MUTEX(dvbdev_mutex);
+static LIST_HEAD(dvbdevfops_list);
static int dvbdev_debug;
module_param(dvbdev_debug, int, 0644);
@@ -448,14 +449,15 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
enum dvb_device_type type, int demux_sink_pads)
{
struct dvb_device *dvbdev;
- struct file_operations *dvbdevfops;
+ struct file_operations *dvbdevfops = NULL;
+ struct dvbdevfops_node *node, *new_node;
struct device *clsdev;
int minor;
int id, ret;
mutex_lock(&dvbdev_register_lock);
- if ((id = dvbdev_get_free_id (adap, type)) < 0){
+ if ((id = dvbdev_get_free_id (adap, type)) < 0) {
mutex_unlock(&dvbdev_register_lock);
*pdvbdev = NULL;
pr_err("%s: couldn't find free device id\n", __func__);
@@ -463,18 +465,45 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
}
*pdvbdev = dvbdev = kzalloc(sizeof(*dvbdev), GFP_KERNEL);
-
if (!dvbdev){
mutex_unlock(&dvbdev_register_lock);
return -ENOMEM;
}
- dvbdevfops = kmemdup(template->fops, sizeof(*dvbdevfops), GFP_KERNEL);
+ /*
+ * When a device of the same type is probe()d more than once,
+ * the first allocated fops are used. This prevents memory leaks
+ * that can occur when the same device is probe()d repeatedly.
+ */
+ list_for_each_entry(node, &dvbdevfops_list, list_head) {
+ if (node->fops->owner == adap->module &&
+ node->type == type &&
+ node->template == template) {
+ dvbdevfops = node->fops;
+ break;
+ }
+ }
- if (!dvbdevfops){
- kfree (dvbdev);
- mutex_unlock(&dvbdev_register_lock);
- return -ENOMEM;
+ if (dvbdevfops == NULL) {
+ dvbdevfops = kmemdup(template->fops, sizeof(*dvbdevfops), GFP_KERNEL);
+ if (!dvbdevfops) {
+ kfree(dvbdev);
+ mutex_unlock(&dvbdev_register_lock);
+ return -ENOMEM;
+ }
+
+ new_node = kzalloc(sizeof(struct dvbdevfops_node), GFP_KERNEL);
+ if (!new_node) {
+ kfree(dvbdevfops);
+ kfree(dvbdev);
+ mutex_unlock(&dvbdev_register_lock);
+ return -ENOMEM;
+ }
+
+ new_node->fops = dvbdevfops;
+ new_node->type = type;
+ new_node->template = template;
+ list_add_tail (&new_node->list_head, &dvbdevfops_list);
}
memcpy(dvbdev, template, sizeof(struct dvb_device));
@@ -484,20 +513,20 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
dvbdev->priv = priv;
dvbdev->fops = dvbdevfops;
init_waitqueue_head (&dvbdev->wait_queue);
-
dvbdevfops->owner = adap->module;
-
list_add_tail (&dvbdev->list_head, &adap->device_list);
-
down_write(&minor_rwsem);
#ifdef CONFIG_DVB_DYNAMIC_MINORS
for (minor = 0; minor < MAX_DVB_MINORS; minor++)
if (dvb_minors[minor] == NULL)
break;
-
if (minor == MAX_DVB_MINORS) {
+ if (new_node) {
+ list_del (&new_node->list_head);
+ kfree(dvbdevfops);
+ kfree(new_node);
+ }
list_del (&dvbdev->list_head);
- kfree(dvbdevfops);
kfree(dvbdev);
up_write(&minor_rwsem);
mutex_unlock(&dvbdev_register_lock);
@@ -506,41 +535,46 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
#else
minor = nums2minor(adap->num, type, id);
#endif
-
dvbdev->minor = minor;
dvb_minors[minor] = dvbdev;
up_write(&minor_rwsem);
-
ret = dvb_register_media_device(dvbdev, type, minor, demux_sink_pads);
if (ret) {
pr_err("%s: dvb_register_media_device failed to create the mediagraph\n",
__func__);
-
+ if (new_node) {
+ list_del (&new_node->list_head);
+ kfree(dvbdevfops);
+ kfree(new_node);
+ }
dvb_media_device_free(dvbdev);
list_del (&dvbdev->list_head);
- kfree(dvbdevfops);
kfree(dvbdev);
mutex_unlock(&dvbdev_register_lock);
return ret;
}
- mutex_unlock(&dvbdev_register_lock);
-
clsdev = device_create(dvb_class, adap->device,
MKDEV(DVB_MAJOR, minor),
dvbdev, "dvb%d.%s%d", adap->num, dnames[type], id);
if (IS_ERR(clsdev)) {
pr_err("%s: failed to create device dvb%d.%s%d (%ld)\n",
__func__, adap->num, dnames[type], id, PTR_ERR(clsdev));
+ if (new_node) {
+ list_del (&new_node->list_head);
+ kfree(dvbdevfops);
+ kfree(new_node);
+ }
dvb_media_device_free(dvbdev);
list_del (&dvbdev->list_head);
- kfree(dvbdevfops);
kfree(dvbdev);
return PTR_ERR(clsdev);
}
+
dprintk("DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n",
adap->num, dnames[type], id, minor, minor);
+ mutex_unlock(&dvbdev_register_lock);
return 0;
}
EXPORT_SYMBOL(dvb_register_device);
@@ -569,7 +603,6 @@ void dvb_free_device(struct dvb_device *dvbdev)
if (!dvbdev)
return;
- kfree (dvbdev->fops);
kfree (dvbdev);
}
EXPORT_SYMBOL(dvb_free_device);
@@ -1061,9 +1094,17 @@ static int __init init_dvbdev(void)
static void __exit exit_dvbdev(void)
{
+ struct dvbdevfops_node *node, *next;
+
class_destroy(dvb_class);
cdev_del(&dvb_device_cdev);
unregister_chrdev_region(MKDEV(DVB_MAJOR, 0), MAX_DVB_MINORS);
+
+ list_for_each_entry_safe(node, next, &dvbdevfops_list, list_head) {
+ list_del (&node->list_head);
+ kfree(node->fops);
+ kfree(node);
+ }
}
subsys_initcall(init_dvbdev);
diff --git a/include/media/dvbdev.h b/include/media/dvbdev.h
index 2f6b0861322a..1e5413303705 100644
--- a/include/media/dvbdev.h
+++ b/include/media/dvbdev.h
@@ -187,6 +187,21 @@ struct dvb_device {
void *priv;
};
+/**
+ * struct dvbdevfops_node - fops nodes registered in dvbdevfops_list
+ *
+ * @fops: Dynamically allocated fops for ->owner registration
+ * @type: type of dvb_device
+ * @template: dvb_device used for registration
+ * @list_head: list_head for dvbdevfops_list
+ */
+struct dvbdevfops_node {
+ struct file_operations *fops;
+ enum dvb_device_type type;
+ const struct dvb_device *template;
+ struct list_head list_head;
+};
+
/**
* dvb_register_adapter - Registers a new DVB adapter
*
--
2.25.1
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH 3/4] media: dvb-core: Fix use-after-free due to race condition occurring in dvb_register_device()
2022-11-15 13:18 ` [PATCH 3/4] media: dvb-core: Fix use-after-free due to race condition occurring in dvb_register_device() imv4bel
@ 2022-11-17 4:16 ` Dan Carpenter
0 siblings, 0 replies; 6+ messages in thread
From: Dan Carpenter @ 2022-11-17 4:16 UTC (permalink / raw)
To: oe-kbuild, imv4bel, mchehab
Cc: lkp, oe-kbuild-all, Hyunwoo Kim, kernel, linux-media, linux-usb,
cai.huoqing, tiwai
Hi,
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/imv4bel-gmail-com/Fix-multiple-race-condition-vulnerabilities-in-dvb-core-and-device-driver/20221115-212247
base: git://linuxtv.org/media_tree.git master
patch link: https://lore.kernel.org/r/20221115131822.6640-4-imv4bel%40gmail.com
patch subject: [PATCH 3/4] media: dvb-core: Fix use-after-free due to race condition occurring in dvb_register_device()
config: openrisc-randconfig-m041-20221115
compiler: or1k-linux-gcc (GCC) 12.1.0
If you fix the issue, kindly add following tag where applicable
| Reported-by: kernel test robot <lkp@intel.com>
| Reported-by: Dan Carpenter <error27@gmail.com>
New smatch warnings:
drivers/media/dvb-core/dvbdev.c:524 dvb_register_device() error: uninitialized symbol 'new_node'.
drivers/media/dvb-core/dvbdev.c:578 dvb_register_device() warn: inconsistent returns '&dvbdev_register_lock'.
vim +/new_node +524 drivers/media/dvb-core/dvbdev.c
8211b187ec6461 drivers/media/dvb-core/dvbdev.c Mauro Carvalho Chehab 2015-08-21 446
^1da177e4c3f41 drivers/media/dvb/dvb-core/dvbdev.c Linus Torvalds 2005-04-16 447 int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
6bbf7a855d200d drivers/media/dvb-core/dvbdev.c Mauro Carvalho Chehab 2017-09-19 448 const struct dvb_device *template, void *priv,
6bbf7a855d200d drivers/media/dvb-core/dvbdev.c Mauro Carvalho Chehab 2017-09-19 449 enum dvb_device_type type, int demux_sink_pads)
^1da177e4c3f41 drivers/media/dvb/dvb-core/dvbdev.c Linus Torvalds 2005-04-16 450 {
^1da177e4c3f41 drivers/media/dvb/dvb-core/dvbdev.c Linus Torvalds 2005-04-16 451 struct dvb_device *dvbdev;
4261180e3efbe4 drivers/media/dvb-core/dvbdev.c Hyunwoo Kim 2022-11-15 452 struct file_operations *dvbdevfops = NULL;
4261180e3efbe4 drivers/media/dvb-core/dvbdev.c Hyunwoo Kim 2022-11-15 453 struct dvbdevfops_node *node, *new_node;
Later code assumes this was initialized to NULL.
5f553388b06532 drivers/media/dvb/dvb-core/dvbdev.c Kay Sievers 2007-08-15 454 struct device *clsdev;
5dd3f3071070f5 drivers/media/dvb/dvb-core/dvbdev.c Andreas Oberritter 2008-10-23 455 int minor;
f50d51661af375 drivers/media/dvb-core/dvbdev.c Mauro Carvalho Chehab 2015-09-04 456 int id, ret;
^1da177e4c3f41 drivers/media/dvb/dvb-core/dvbdev.c Linus Torvalds 2005-04-16 457
c278850206fd9d drivers/media/dvb/dvb-core/dvbdev.c Simon Arlott 2007-03-10 458 mutex_lock(&dvbdev_register_lock);
^1da177e4c3f41 drivers/media/dvb/dvb-core/dvbdev.c Linus Torvalds 2005-04-16 459
^1da177e4c3f41 drivers/media/dvb/dvb-core/dvbdev.c Linus Torvalds 2005-04-16 460 if ((id = dvbdev_get_free_id (adap, type)) < 0) {
1e4baed379a2bf drivers/media/dvb/dvb-core/dvbdev.c Ingo Molnar 2006-01-15 461 mutex_unlock(&dvbdev_register_lock);
^1da177e4c3f41 drivers/media/dvb/dvb-core/dvbdev.c Linus Torvalds 2005-04-16 462 *pdvbdev = NULL;
b3ad24d2e0b039 drivers/media/dvb-core/dvbdev.c Mauro Carvalho Chehab 2016-10-13 463 pr_err("%s: couldn't find free device id\n", __func__);
^1da177e4c3f41 drivers/media/dvb/dvb-core/dvbdev.c Linus Torvalds 2005-04-16 464 return -ENFILE;
^1da177e4c3f41 drivers/media/dvb/dvb-core/dvbdev.c Linus Torvalds 2005-04-16 465 }
^1da177e4c3f41 drivers/media/dvb/dvb-core/dvbdev.c Linus Torvalds 2005-04-16 466
f50d51661af375 drivers/media/dvb-core/dvbdev.c Mauro Carvalho Chehab 2015-09-04 467 *pdvbdev = dvbdev = kzalloc(sizeof(*dvbdev), GFP_KERNEL);
^1da177e4c3f41 drivers/media/dvb/dvb-core/dvbdev.c Linus Torvalds 2005-04-16 468 if (!dvbdev){
1e4baed379a2bf drivers/media/dvb/dvb-core/dvbdev.c Ingo Molnar 2006-01-15 469 mutex_unlock(&dvbdev_register_lock);
^1da177e4c3f41 drivers/media/dvb/dvb-core/dvbdev.c Linus Torvalds 2005-04-16 470 return -ENOMEM;
^1da177e4c3f41 drivers/media/dvb/dvb-core/dvbdev.c Linus Torvalds 2005-04-16 471 }
^1da177e4c3f41 drivers/media/dvb/dvb-core/dvbdev.c Linus Torvalds 2005-04-16 472
4261180e3efbe4 drivers/media/dvb-core/dvbdev.c Hyunwoo Kim 2022-11-15 473 /*
4261180e3efbe4 drivers/media/dvb-core/dvbdev.c Hyunwoo Kim 2022-11-15 474 * When a device of the same type is probe()d more than once,
4261180e3efbe4 drivers/media/dvb-core/dvbdev.c Hyunwoo Kim 2022-11-15 475 * the first allocated fops are used. This prevents memory leaks
4261180e3efbe4 drivers/media/dvb-core/dvbdev.c Hyunwoo Kim 2022-11-15 476 * that can occur when the same device is probe()d repeatedly.
4261180e3efbe4 drivers/media/dvb-core/dvbdev.c Hyunwoo Kim 2022-11-15 477 */
4261180e3efbe4 drivers/media/dvb-core/dvbdev.c Hyunwoo Kim 2022-11-15 478 list_for_each_entry(node, &dvbdevfops_list, list_head) {
4261180e3efbe4 drivers/media/dvb-core/dvbdev.c Hyunwoo Kim 2022-11-15 479 if (node->fops->owner == adap->module &&
4261180e3efbe4 drivers/media/dvb-core/dvbdev.c Hyunwoo Kim 2022-11-15 480 node->type == type &&
4261180e3efbe4 drivers/media/dvb-core/dvbdev.c Hyunwoo Kim 2022-11-15 481 node->template == template) {
4261180e3efbe4 drivers/media/dvb-core/dvbdev.c Hyunwoo Kim 2022-11-15 482 dvbdevfops = node->fops;
4261180e3efbe4 drivers/media/dvb-core/dvbdev.c Hyunwoo Kim 2022-11-15 483 break;
4261180e3efbe4 drivers/media/dvb-core/dvbdev.c Hyunwoo Kim 2022-11-15 484 }
4261180e3efbe4 drivers/media/dvb-core/dvbdev.c Hyunwoo Kim 2022-11-15 485 }
b61901024776b2 drivers/media/dvb/dvb-core/dvbdev.c Marcel Siegert 2007-02-13 486
4261180e3efbe4 drivers/media/dvb-core/dvbdev.c Hyunwoo Kim 2022-11-15 487 if (dvbdevfops == NULL) {
4261180e3efbe4 drivers/media/dvb-core/dvbdev.c Hyunwoo Kim 2022-11-15 488 dvbdevfops = kmemdup(template->fops, sizeof(*dvbdevfops), GFP_KERNEL);
b61901024776b2 drivers/media/dvb/dvb-core/dvbdev.c Marcel Siegert 2007-02-13 489 if (!dvbdevfops) {
b61901024776b2 drivers/media/dvb/dvb-core/dvbdev.c Marcel Siegert 2007-02-13 490 kfree(dvbdev);
b61901024776b2 drivers/media/dvb/dvb-core/dvbdev.c Marcel Siegert 2007-02-13 491 mutex_unlock(&dvbdev_register_lock);
b61901024776b2 drivers/media/dvb/dvb-core/dvbdev.c Marcel Siegert 2007-02-13 492 return -ENOMEM;
b61901024776b2 drivers/media/dvb/dvb-core/dvbdev.c Marcel Siegert 2007-02-13 493 }
b61901024776b2 drivers/media/dvb/dvb-core/dvbdev.c Marcel Siegert 2007-02-13 494
4261180e3efbe4 drivers/media/dvb-core/dvbdev.c Hyunwoo Kim 2022-11-15 495 new_node = kzalloc(sizeof(struct dvbdevfops_node), GFP_KERNEL);
4261180e3efbe4 drivers/media/dvb-core/dvbdev.c Hyunwoo Kim 2022-11-15 496 if (!new_node) {
4261180e3efbe4 drivers/media/dvb-core/dvbdev.c Hyunwoo Kim 2022-11-15 497 kfree(dvbdevfops);
4261180e3efbe4 drivers/media/dvb-core/dvbdev.c Hyunwoo Kim 2022-11-15 498 kfree(dvbdev);
4261180e3efbe4 drivers/media/dvb-core/dvbdev.c Hyunwoo Kim 2022-11-15 499 mutex_unlock(&dvbdev_register_lock);
4261180e3efbe4 drivers/media/dvb-core/dvbdev.c Hyunwoo Kim 2022-11-15 500 return -ENOMEM;
4261180e3efbe4 drivers/media/dvb-core/dvbdev.c Hyunwoo Kim 2022-11-15 501 }
4261180e3efbe4 drivers/media/dvb-core/dvbdev.c Hyunwoo Kim 2022-11-15 502
4261180e3efbe4 drivers/media/dvb-core/dvbdev.c Hyunwoo Kim 2022-11-15 503 new_node->fops = dvbdevfops;
4261180e3efbe4 drivers/media/dvb-core/dvbdev.c Hyunwoo Kim 2022-11-15 504 new_node->type = type;
4261180e3efbe4 drivers/media/dvb-core/dvbdev.c Hyunwoo Kim 2022-11-15 505 new_node->template = template;
4261180e3efbe4 drivers/media/dvb-core/dvbdev.c Hyunwoo Kim 2022-11-15 506 list_add_tail (&new_node->list_head, &dvbdevfops_list);
4261180e3efbe4 drivers/media/dvb-core/dvbdev.c Hyunwoo Kim 2022-11-15 507 }
4261180e3efbe4 drivers/media/dvb-core/dvbdev.c Hyunwoo Kim 2022-11-15 508
^1da177e4c3f41 drivers/media/dvb/dvb-core/dvbdev.c Linus Torvalds 2005-04-16 509 memcpy(dvbdev, template, sizeof(struct dvb_device));
^1da177e4c3f41 drivers/media/dvb/dvb-core/dvbdev.c Linus Torvalds 2005-04-16 510 dvbdev->type = type;
^1da177e4c3f41 drivers/media/dvb/dvb-core/dvbdev.c Linus Torvalds 2005-04-16 511 dvbdev->id = id;
^1da177e4c3f41 drivers/media/dvb/dvb-core/dvbdev.c Linus Torvalds 2005-04-16 512 dvbdev->adapter = adap;
^1da177e4c3f41 drivers/media/dvb/dvb-core/dvbdev.c Linus Torvalds 2005-04-16 513 dvbdev->priv = priv;
b61901024776b2 drivers/media/dvb/dvb-core/dvbdev.c Marcel Siegert 2007-02-13 514 dvbdev->fops = dvbdevfops;
ca5be9cd051662 drivers/media/dvb/dvb-core/dvbdev.c Markus Rechberger 2007-04-14 515 init_waitqueue_head (&dvbdev->wait_queue);
784e29d2031b53 drivers/media/dvb/dvb-core/dvbdev.c Jan Engelhardt 2009-01-11 516 dvbdevfops->owner = adap->module;
^1da177e4c3f41 drivers/media/dvb/dvb-core/dvbdev.c Linus Torvalds 2005-04-16 517 list_add_tail (&dvbdev->list_head, &adap->device_list);
5dd3f3071070f5 drivers/media/dvb/dvb-core/dvbdev.c Andreas Oberritter 2008-10-23 518 down_write(&minor_rwsem);
5dd3f3071070f5 drivers/media/dvb/dvb-core/dvbdev.c Andreas Oberritter 2008-10-23 519 #ifdef CONFIG_DVB_DYNAMIC_MINORS
5dd3f3071070f5 drivers/media/dvb/dvb-core/dvbdev.c Andreas Oberritter 2008-10-23 520 for (minor = 0; minor < MAX_DVB_MINORS; minor++)
5dd3f3071070f5 drivers/media/dvb/dvb-core/dvbdev.c Andreas Oberritter 2008-10-23 521 if (dvb_minors[minor] == NULL)
5dd3f3071070f5 drivers/media/dvb/dvb-core/dvbdev.c Andreas Oberritter 2008-10-23 522 break;
5dd3f3071070f5 drivers/media/dvb/dvb-core/dvbdev.c Andreas Oberritter 2008-10-23 523 if (minor == MAX_DVB_MINORS) {
4261180e3efbe4 drivers/media/dvb-core/dvbdev.c Hyunwoo Kim 2022-11-15 @524 if (new_node) {
new_node is either non-NULL or uninitialized.
4261180e3efbe4 drivers/media/dvb-core/dvbdev.c Hyunwoo Kim 2022-11-15 525 list_del (&new_node->list_head);
5dd3f3071070f5 drivers/media/dvb/dvb-core/dvbdev.c Andreas Oberritter 2008-10-23 526 kfree(dvbdevfops);
4261180e3efbe4 drivers/media/dvb-core/dvbdev.c Hyunwoo Kim 2022-11-15 527 kfree(new_node);
4261180e3efbe4 drivers/media/dvb-core/dvbdev.c Hyunwoo Kim 2022-11-15 528 }
4261180e3efbe4 drivers/media/dvb-core/dvbdev.c Hyunwoo Kim 2022-11-15 529 list_del (&dvbdev->list_head);
5dd3f3071070f5 drivers/media/dvb/dvb-core/dvbdev.c Andreas Oberritter 2008-10-23 530 kfree(dvbdev);
82163edcdfa4eb drivers/media/dvb/dvb-core/dvbdev.c Santosh Nayak 2012-06-23 531 up_write(&minor_rwsem);
5dd3f3071070f5 drivers/media/dvb/dvb-core/dvbdev.c Andreas Oberritter 2008-10-23 532 mutex_unlock(&dvbdev_register_lock);
5dd3f3071070f5 drivers/media/dvb/dvb-core/dvbdev.c Andreas Oberritter 2008-10-23 533 return -EINVAL;
5dd3f3071070f5 drivers/media/dvb/dvb-core/dvbdev.c Andreas Oberritter 2008-10-23 534 }
5dd3f3071070f5 drivers/media/dvb/dvb-core/dvbdev.c Andreas Oberritter 2008-10-23 535 #else
5dd3f3071070f5 drivers/media/dvb/dvb-core/dvbdev.c Andreas Oberritter 2008-10-23 536 minor = nums2minor(adap->num, type, id);
5dd3f3071070f5 drivers/media/dvb/dvb-core/dvbdev.c Andreas Oberritter 2008-10-23 537 #endif
5dd3f3071070f5 drivers/media/dvb/dvb-core/dvbdev.c Andreas Oberritter 2008-10-23 538 dvbdev->minor = minor;
5dd3f3071070f5 drivers/media/dvb/dvb-core/dvbdev.c Andreas Oberritter 2008-10-23 539 dvb_minors[minor] = dvbdev;
5dd3f3071070f5 drivers/media/dvb/dvb-core/dvbdev.c Andreas Oberritter 2008-10-23 540 up_write(&minor_rwsem);
f50d51661af375 drivers/media/dvb-core/dvbdev.c Mauro Carvalho Chehab 2015-09-04 541 ret = dvb_register_media_device(dvbdev, type, minor, demux_sink_pads);
f50d51661af375 drivers/media/dvb-core/dvbdev.c Mauro Carvalho Chehab 2015-09-04 542 if (ret) {
b3ad24d2e0b039 drivers/media/dvb-core/dvbdev.c Mauro Carvalho Chehab 2016-10-13 543 pr_err("%s: dvb_register_media_device failed to create the mediagraph\n",
f50d51661af375 drivers/media/dvb-core/dvbdev.c Mauro Carvalho Chehab 2015-09-04 544 __func__);
4261180e3efbe4 drivers/media/dvb-core/dvbdev.c Hyunwoo Kim 2022-11-15 545 if (new_node) {
4261180e3efbe4 drivers/media/dvb-core/dvbdev.c Hyunwoo Kim 2022-11-15 546 list_del (&new_node->list_head);
4261180e3efbe4 drivers/media/dvb-core/dvbdev.c Hyunwoo Kim 2022-11-15 547 kfree(dvbdevfops);
4261180e3efbe4 drivers/media/dvb-core/dvbdev.c Hyunwoo Kim 2022-11-15 548 kfree(new_node);
4261180e3efbe4 drivers/media/dvb-core/dvbdev.c Hyunwoo Kim 2022-11-15 549 }
f50d51661af375 drivers/media/dvb-core/dvbdev.c Mauro Carvalho Chehab 2015-09-04 550 dvb_media_device_free(dvbdev);
1fec2ecc252301 drivers/media/dvb-core/dvbdev.c Mauro Carvalho Chehab 2021-06-09 551 list_del (&dvbdev->list_head);
f50d51661af375 drivers/media/dvb-core/dvbdev.c Mauro Carvalho Chehab 2015-09-04 552 kfree(dvbdev);
f50d51661af375 drivers/media/dvb-core/dvbdev.c Mauro Carvalho Chehab 2015-09-04 553 mutex_unlock(&dvbdev_register_lock);
f50d51661af375 drivers/media/dvb-core/dvbdev.c Mauro Carvalho Chehab 2015-09-04 554 return ret;
f50d51661af375 drivers/media/dvb-core/dvbdev.c Mauro Carvalho Chehab 2015-09-04 555 }
f50d51661af375 drivers/media/dvb-core/dvbdev.c Mauro Carvalho Chehab 2015-09-04 556
a9b12619f7b6f1 drivers/media/dvb/dvb-core/dvbdev.c Greg Kroah-Hartman 2008-07-21 557 clsdev = device_create(dvb_class, adap->device,
b7496780e80006 drivers/media/dvb/dvb-core/dvbdev.c Hans Verkuil 2008-11-03 558 MKDEV(DVB_MAJOR, minor),
a5f4c0ce682efa drivers/media/dvb/dvb-core/dvbdev.c Kay Sievers 2008-10-27 559 dvbdev, "dvb%d.%s%d", adap->num, dnames[type], id);
4abdcf933f6477 drivers/media/dvb/dvb-core/dvbdev.c Simon Arlott 2007-05-06 560 if (IS_ERR(clsdev)) {
b3ad24d2e0b039 drivers/media/dvb-core/dvbdev.c Mauro Carvalho Chehab 2016-10-13 561 pr_err("%s: failed to create device dvb%d.%s%d (%ld)\n",
46b4f7c176a2dd drivers/media/dvb/dvb-core/dvbdev.c Harvey Harrison 2008-04-08 562 __func__, adap->num, dnames[type], id, PTR_ERR(clsdev));
4261180e3efbe4 drivers/media/dvb-core/dvbdev.c Hyunwoo Kim 2022-11-15 563 if (new_node) {
4261180e3efbe4 drivers/media/dvb-core/dvbdev.c Hyunwoo Kim 2022-11-15 564 list_del (&new_node->list_head);
4261180e3efbe4 drivers/media/dvb-core/dvbdev.c Hyunwoo Kim 2022-11-15 565 kfree(dvbdevfops);
4261180e3efbe4 drivers/media/dvb-core/dvbdev.c Hyunwoo Kim 2022-11-15 566 kfree(new_node);
4261180e3efbe4 drivers/media/dvb-core/dvbdev.c Hyunwoo Kim 2022-11-15 567 }
167faadfcf9339 drivers/media/dvb-core/dvbdev.c Dinghao Liu 2020-08-24 568 dvb_media_device_free(dvbdev);
1fec2ecc252301 drivers/media/dvb-core/dvbdev.c Mauro Carvalho Chehab 2021-06-09 569 list_del (&dvbdev->list_head);
167faadfcf9339 drivers/media/dvb-core/dvbdev.c Dinghao Liu 2020-08-24 570 kfree(dvbdev);
4abdcf933f6477 drivers/media/dvb/dvb-core/dvbdev.c Simon Arlott 2007-05-06 571 return PTR_ERR(clsdev);
Needs a mutex_unlock(&dvbdev_register_lock);
4abdcf933f6477 drivers/media/dvb/dvb-core/dvbdev.c Simon Arlott 2007-05-06 572 }
4261180e3efbe4 drivers/media/dvb-core/dvbdev.c Hyunwoo Kim 2022-11-15 573
b3ad24d2e0b039 drivers/media/dvb-core/dvbdev.c Mauro Carvalho Chehab 2016-10-13 574 dprintk("DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n",
5dd3f3071070f5 drivers/media/dvb/dvb-core/dvbdev.c Andreas Oberritter 2008-10-23 575 adap->num, dnames[type], id, minor, minor);
^1da177e4c3f41 drivers/media/dvb/dvb-core/dvbdev.c Linus Torvalds 2005-04-16 576
4261180e3efbe4 drivers/media/dvb-core/dvbdev.c Hyunwoo Kim 2022-11-15 577 mutex_unlock(&dvbdev_register_lock);
^1da177e4c3f41 drivers/media/dvb/dvb-core/dvbdev.c Linus Torvalds 2005-04-16 @578 return 0;
^1da177e4c3f41 drivers/media/dvb/dvb-core/dvbdev.c Linus Torvalds 2005-04-16 579 }
--
0-DAY CI Kernel Test Service
https://01.org/lkp
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH 4/4] media: ttusb-dec: Fix memory leak in ttusb_dec_exit_dvb()
2022-11-15 13:18 [PATCH 0/4] Fix multiple race condition vulnerabilities in dvb-core and device driver imv4bel
` (2 preceding siblings ...)
2022-11-15 13:18 ` [PATCH 3/4] media: dvb-core: Fix use-after-free due to race condition occurring in dvb_register_device() imv4bel
@ 2022-11-15 13:18 ` imv4bel
3 siblings, 0 replies; 6+ messages in thread
From: imv4bel @ 2022-11-15 13:18 UTC (permalink / raw)
To: mchehab; +Cc: Hyunwoo Kim, kernel, linux-media, linux-usb, cai.huoqing, tiwai
From: Hyunwoo Kim <imv4bel@gmail.com>
Since dvb_frontend_detach() is not called in ttusb_dec_exit_dvb(),
which is called when the device is disconnected, dvb_frontend_free()
is not finally called.
This causes a memory leak just by repeatedly plugging and
unplugging the device.
Fix this issue by adding dvb_frontend_detach() to ttusb_dec_exit_dvb().
Signed-off-by: Hyunwoo Kim <imv4bel@gmail.com>
---
drivers/media/usb/ttusb-dec/ttusb_dec.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/drivers/media/usb/ttusb-dec/ttusb_dec.c b/drivers/media/usb/ttusb-dec/ttusb_dec.c
index 38822cedd93a..c4474d4c44e2 100644
--- a/drivers/media/usb/ttusb-dec/ttusb_dec.c
+++ b/drivers/media/usb/ttusb-dec/ttusb_dec.c
@@ -1544,8 +1544,7 @@ static void ttusb_dec_exit_dvb(struct ttusb_dec *dec)
dvb_dmx_release(&dec->demux);
if (dec->fe) {
dvb_unregister_frontend(dec->fe);
- if (dec->fe->ops.release)
- dec->fe->ops.release(dec->fe);
+ dvb_frontend_detach(dec->fe);
}
dvb_unregister_adapter(&dec->adapter);
}
--
2.25.1
^ permalink raw reply related [flat|nested] 6+ messages in thread