diff --git a/patches.suse/media-dvb-core-Fix-use-after-free-on-race-condition-.patch b/patches.suse/media-dvb-core-Fix-use-after-free-on-race-condition-.patch new file mode 100644 index 0000000..f80d11b --- /dev/null +++ b/patches.suse/media-dvb-core-Fix-use-after-free-on-race-condition-.patch @@ -0,0 +1,179 @@ +From 6769a0b7ee0c3b31e1b22c3fadff2bfb642de23f Mon Sep 17 00:00:00 2001 +From: Hyunwoo Kim +Date: Thu, 17 Nov 2022 04:59:22 +0000 +Subject: [PATCH] media: dvb-core: Fix use-after-free on race condition at dvb_frontend +Git-commit: 6769a0b7ee0c3b31e1b22c3fadff2bfb642de23f +Patch-mainline: v6.4-rc3 +References: CVE-2022-45885 bsc#1205758 + +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'. + +[mchehab: fix a couple of checkpatch warnings and some mistakes at the error handling logic] + +Link: https://lore.kernel.org/linux-media/20221117045925.14297-2-imv4bel@gmail.com +Signed-off-by: Hyunwoo Kim +Signed-off-by: Mauro Carvalho Chehab +Acked-by: Takashi Iwai + +--- + drivers/media/dvb-core/dvb_frontend.c | 50 ++++++++++++++++++++++++++++------ + include/media/dvb_frontend.h | 6 +++- + 2 files changed, 47 insertions(+), 9 deletions(-) + +--- a/drivers/media/dvb-core/dvb_frontend.c ++++ b/drivers/media/dvb-core/dvb_frontend.c +@@ -809,15 +809,26 @@ static void dvb_frontend_stop(struct dvb + + 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(); + +- if (!fepriv->thread) ++ if (!fepriv->thread) { ++ mutex_unlock(&fe->remove_mutex); + return; ++ } + + 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; + +@@ -2753,9 +2764,13 @@ static int dvb_frontend_open(struct inod + 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) +- return -ENODEV; ++ if (fe->exit == DVB_FE_DEVICE_REMOVED) { ++ ret = -ENODEV; ++ goto err_remove_mutex; ++ } + + if (adapter->mfe_shared) { + mutex_lock(&adapter->mfe_lock); +@@ -2776,8 +2791,10 @@ static int dvb_frontend_open(struct inod + while (mferetry-- && (mfedev->users != -1 || + mfepriv->thread)) { + if (msleep_interruptible(500)) { +- if (signal_pending(current)) +- return -EINTR; ++ if (signal_pending(current)) { ++ ret = -EINTR; ++ goto err_remove_mutex; ++ } + } + } + +@@ -2789,7 +2806,8 @@ static int dvb_frontend_open(struct inod + if (mfedev->users != -1 || + mfepriv->thread) { + mutex_unlock(&adapter->mfe_lock); +- return -EBUSY; ++ ret = -EBUSY; ++ goto err_remove_mutex; + } + adapter->mfe_dvbdev = dvbdev; + } +@@ -2848,6 +2866,8 @@ static int dvb_frontend_open(struct inod + + if (adapter->mfe_shared) + mutex_unlock(&adapter->mfe_lock); ++ ++ mutex_unlock(&fe->remove_mutex); + return ret; + + err3: +@@ -2869,6 +2889,9 @@ err1: + err0: + if (adapter->mfe_shared) + mutex_unlock(&adapter->mfe_lock); ++ ++err_remove_mutex: ++ mutex_unlock(&fe->remove_mutex); + return ret; + } + +@@ -2879,6 +2902,8 @@ static int dvb_frontend_release(struct i + 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) { +@@ -2900,10 +2925,18 @@ static int dvb_frontend_release(struct i + } + 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 +3033,7 @@ int dvb_register_frontend(struct dvb_ada + fepriv = fe->frontend_priv; + + kref_init(&fe->refcount); ++ mutex_init(&fe->remove_mutex); + + /* + * After initialization, there need to be two references: one +--- a/include/media/dvb_frontend.h ++++ b/include/media/dvb_frontend.h +@@ -680,7 +680,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 { +@@ -698,6 +701,7 @@ struct dvb_frontend { + int (*callback)(void *adapter_priv, int component, int cmd, int arg); + int id; + unsigned int exit; ++ struct mutex remove_mutex; + }; + + /** diff --git a/series.conf b/series.conf index 2ee8c40..d511927 100644 --- a/series.conf +++ b/series.conf @@ -23124,6 +23124,7 @@ patches.suse/0001-wifi-brcmfmac-slab-out-of-bounds-read-in-brcmf_get_a.patch patches.suse/xfs-verify-buffer-contents-when-we-skip-log-replay.patch patches.suse/netfilter-nf_tables-deactivate-anonymous-set-from-pr.patch + patches.suse/media-dvb-core-Fix-use-after-free-on-race-condition-.patch ######################################################## # end of sorted patches