|
Takashi Iwai |
33f605 |
From 280a8ab81733da8bc442253c700a52c4c0886ffd Mon Sep 17 00:00:00 2001
|
|
Takashi Iwai |
33f605 |
From: Hyunwoo Kim <v4bel@theori.io>
|
|
Takashi Iwai |
33f605 |
Date: Mon, 21 Nov 2022 06:33:08 +0000
|
|
Takashi Iwai |
33f605 |
Subject: [PATCH] media: dvb-core: Fix use-after-free due to race condition at dvb_ca_en50221
|
|
Takashi Iwai |
33f605 |
Git-commit: 280a8ab81733da8bc442253c700a52c4c0886ffd
|
|
Takashi Iwai |
33f605 |
Patch-mainline: v6.4-rc3
|
|
Takashi Iwai |
33f605 |
References: CVE-2022-45919 bsc#1205803
|
|
Takashi Iwai |
33f605 |
|
|
Takashi Iwai |
33f605 |
If the device node of dvb_ca_en50221 is open() and the
|
|
Takashi Iwai |
33f605 |
device is disconnected, a UAF may occur when calling
|
|
Takashi Iwai |
33f605 |
close() on the device node.
|
|
Takashi Iwai |
33f605 |
|
|
Takashi Iwai |
33f605 |
The root cause is that wake_up() and wait_event() for
|
|
Takashi Iwai |
33f605 |
dvbdev->wait_queue are not implemented.
|
|
Takashi Iwai |
33f605 |
|
|
Takashi Iwai |
33f605 |
So implement wait_event() function in dvb_ca_en50221_release()
|
|
Takashi Iwai |
33f605 |
and add 'remove_mutex' which prevents race condition
|
|
Takashi Iwai |
33f605 |
for 'ca->exit'.
|
|
Takashi Iwai |
33f605 |
|
|
Takashi Iwai |
33f605 |
[mchehab: fix a checkpatch warning]
|
|
Takashi Iwai |
33f605 |
|
|
Takashi Iwai |
33f605 |
Link: https://lore.kernel.org/linux-media/20221121063308.GA33821@ubuntu
|
|
Takashi Iwai |
33f605 |
Signed-off-by: Hyunwoo Kim <v4bel@theori.io>
|
|
Takashi Iwai |
33f605 |
Signed-off-by: Mauro Carvalho Chehab <mchehab@kernel.org>
|
|
Takashi Iwai |
33f605 |
Acked-by: Takashi Iwai <tiwai@suse.de>
|
|
Takashi Iwai |
33f605 |
|
|
Takashi Iwai |
33f605 |
---
|
|
Takashi Iwai |
33f605 |
drivers/media/dvb-core/dvb_ca_en50221.c | 37 ++++++++++++++++++++++++-
|
|
Takashi Iwai |
33f605 |
1 file changed, 36 insertions(+), 1 deletion(-)
|
|
Takashi Iwai |
33f605 |
|
|
Takashi Iwai |
33f605 |
diff --git a/drivers/media/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb-core/dvb_ca_en50221.c
|
|
Takashi Iwai |
33f605 |
index b6ca29dfb184..baf64540dc00 100644
|
|
Takashi Iwai |
33f605 |
--- a/drivers/media/dvb-core/dvb_ca_en50221.c
|
|
Takashi Iwai |
33f605 |
+++ b/drivers/media/dvb-core/dvb_ca_en50221.c
|
|
Takashi Iwai |
33f605 |
@@ -151,6 +151,12 @@ struct dvb_ca_private {
|
|
Takashi Iwai |
33f605 |
|
|
Takashi Iwai |
33f605 |
/* mutex serializing ioctls */
|
|
Takashi Iwai |
33f605 |
struct mutex ioctl_mutex;
|
|
Takashi Iwai |
33f605 |
+
|
|
Takashi Iwai |
33f605 |
+ /* A mutex used when a device is disconnected */
|
|
Takashi Iwai |
33f605 |
+ struct mutex remove_mutex;
|
|
Takashi Iwai |
33f605 |
+
|
|
Takashi Iwai |
33f605 |
+ /* Whether the device is disconnected */
|
|
Takashi Iwai |
33f605 |
+ int exit;
|
|
Takashi Iwai |
33f605 |
};
|
|
Takashi Iwai |
33f605 |
|
|
Takashi Iwai |
33f605 |
static void dvb_ca_private_free(struct dvb_ca_private *ca)
|
|
Takashi Iwai |
33f605 |
@@ -1711,12 +1717,22 @@ static int dvb_ca_en50221_io_open(struct inode *inode, struct file *file)
|
|
Takashi Iwai |
33f605 |
|
|
Takashi Iwai |
33f605 |
dprintk("%s\n", __func__);
|
|
Takashi Iwai |
33f605 |
|
|
Takashi Iwai |
33f605 |
- if (!try_module_get(ca->pub->owner))
|
|
Takashi Iwai |
33f605 |
+ mutex_lock(&ca->remove_mutex);
|
|
Takashi Iwai |
33f605 |
+
|
|
Takashi Iwai |
33f605 |
+ if (ca->exit) {
|
|
Takashi Iwai |
33f605 |
+ mutex_unlock(&ca->remove_mutex);
|
|
Takashi Iwai |
33f605 |
+ return -ENODEV;
|
|
Takashi Iwai |
33f605 |
+ }
|
|
Takashi Iwai |
33f605 |
+
|
|
Takashi Iwai |
33f605 |
+ if (!try_module_get(ca->pub->owner)) {
|
|
Takashi Iwai |
33f605 |
+ mutex_unlock(&ca->remove_mutex);
|
|
Takashi Iwai |
33f605 |
return -EIO;
|
|
Takashi Iwai |
33f605 |
+ }
|
|
Takashi Iwai |
33f605 |
|
|
Takashi Iwai |
33f605 |
err = dvb_generic_open(inode, file);
|
|
Takashi Iwai |
33f605 |
if (err < 0) {
|
|
Takashi Iwai |
33f605 |
module_put(ca->pub->owner);
|
|
Takashi Iwai |
33f605 |
+ mutex_unlock(&ca->remove_mutex);
|
|
Takashi Iwai |
33f605 |
return err;
|
|
Takashi Iwai |
33f605 |
}
|
|
Takashi Iwai |
33f605 |
|
|
Takashi Iwai |
33f605 |
@@ -1741,6 +1757,7 @@ static int dvb_ca_en50221_io_open(struct inode *inode, struct file *file)
|
|
Takashi Iwai |
33f605 |
|
|
Takashi Iwai |
33f605 |
dvb_ca_private_get(ca);
|
|
Takashi Iwai |
33f605 |
|
|
Takashi Iwai |
33f605 |
+ mutex_unlock(&ca->remove_mutex);
|
|
Takashi Iwai |
33f605 |
return 0;
|
|
Takashi Iwai |
33f605 |
}
|
|
Takashi Iwai |
33f605 |
|
|
Takashi Iwai |
33f605 |
@@ -1760,6 +1777,8 @@ static int dvb_ca_en50221_io_release(struct inode *inode, struct file *file)
|
|
Takashi Iwai |
33f605 |
|
|
Takashi Iwai |
33f605 |
dprintk("%s\n", __func__);
|
|
Takashi Iwai |
33f605 |
|
|
Takashi Iwai |
33f605 |
+ mutex_lock(&ca->remove_mutex);
|
|
Takashi Iwai |
33f605 |
+
|
|
Takashi Iwai |
33f605 |
/* mark the CA device as closed */
|
|
Takashi Iwai |
33f605 |
ca->open = 0;
|
|
Takashi Iwai |
33f605 |
dvb_ca_en50221_thread_update_delay(ca);
|
|
Takashi Iwai |
33f605 |
@@ -1770,6 +1789,13 @@ static int dvb_ca_en50221_io_release(struct inode *inode, struct file *file)
|
|
Takashi Iwai |
33f605 |
|
|
Takashi Iwai |
33f605 |
dvb_ca_private_put(ca);
|
|
Takashi Iwai |
33f605 |
|
|
Takashi Iwai |
33f605 |
+ if (dvbdev->users == 1 && ca->exit == 1) {
|
|
Takashi Iwai |
33f605 |
+ mutex_unlock(&ca->remove_mutex);
|
|
Takashi Iwai |
33f605 |
+ wake_up(&dvbdev->wait_queue);
|
|
Takashi Iwai |
33f605 |
+ } else {
|
|
Takashi Iwai |
33f605 |
+ mutex_unlock(&ca->remove_mutex);
|
|
Takashi Iwai |
33f605 |
+ }
|
|
Takashi Iwai |
33f605 |
+
|
|
Takashi Iwai |
33f605 |
return err;
|
|
Takashi Iwai |
33f605 |
}
|
|
Takashi Iwai |
33f605 |
|
|
Takashi Iwai |
33f605 |
@@ -1893,6 +1919,7 @@ int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter,
|
|
Takashi Iwai |
33f605 |
}
|
|
Takashi Iwai |
33f605 |
|
|
Takashi Iwai |
33f605 |
mutex_init(&ca->ioctl_mutex);
|
|
Takashi Iwai |
33f605 |
+ mutex_init(&ca->remove_mutex);
|
|
Takashi Iwai |
33f605 |
|
|
Takashi Iwai |
33f605 |
if (signal_pending(current)) {
|
|
Takashi Iwai |
33f605 |
ret = -EINTR;
|
|
Takashi Iwai |
33f605 |
@@ -1935,6 +1962,14 @@ void dvb_ca_en50221_release(struct dvb_ca_en50221 *pubca)
|
|
Takashi Iwai |
33f605 |
|
|
Takashi Iwai |
33f605 |
dprintk("%s\n", __func__);
|
|
Takashi Iwai |
33f605 |
|
|
Takashi Iwai |
33f605 |
+ mutex_lock(&ca->remove_mutex);
|
|
Takashi Iwai |
33f605 |
+ ca->exit = 1;
|
|
Takashi Iwai |
33f605 |
+ mutex_unlock(&ca->remove_mutex);
|
|
Takashi Iwai |
33f605 |
+
|
|
Takashi Iwai |
33f605 |
+ if (ca->dvbdev->users < 1)
|
|
Takashi Iwai |
33f605 |
+ wait_event(ca->dvbdev->wait_queue,
|
|
Takashi Iwai |
33f605 |
+ ca->dvbdev->users == 1);
|
|
Takashi Iwai |
33f605 |
+
|
|
Takashi Iwai |
33f605 |
/* shutdown the thread if there was one */
|
|
Takashi Iwai |
33f605 |
kthread_stop(ca->thread);
|
|
Takashi Iwai |
33f605 |
|
|
Takashi Iwai |
33f605 |
--
|
|
Takashi Iwai |
33f605 |
2.35.3
|
|
Takashi Iwai |
33f605 |
|