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..53ded79 --- /dev/null +++ b/patches.suse/media-dvb-core-Fix-use-after-free-on-race-condition-.patch @@ -0,0 +1,180 @@ +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 +Git-repo: git://linuxtv.org/media_tree.git +Patch-mainline: Queued in subsystem maintainer repo +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 ++++++++++++++++++++++++++++------ + drivers/media/dvb-core/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 +@@ -808,15 +808,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; + +@@ -2488,9 +2499,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); +@@ -2511,8 +2526,10 @@ static int dvb_frontend_open(struct inod + while (mferetry-- && (mfedev->users != -1 || + mfepriv->thread != NULL)) { + if(msleep_interruptible(500)) { +- if(signal_pending(current)) +- return -EINTR; ++ if(signal_pending(current)) { ++ ret = -EINTR; ++ goto err_remove_mutex; ++ } + } + } + +@@ -2524,7 +2541,8 @@ static int dvb_frontend_open(struct inod + if (mfedev->users != -1 || + mfepriv->thread != NULL) { + mutex_unlock (&adapter->mfe_lock); +- return -EBUSY; ++ ret = -EBUSY; ++ goto err_remove_mutex; + } + adapter->mfe_dvbdev = dvbdev; + } +@@ -2580,6 +2598,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: +@@ -2599,6 +2619,9 @@ err1: + err0: + if (adapter->mfe_shared) + mutex_unlock (&adapter->mfe_lock); ++ ++err_remove_mutex: ++ mutex_unlock(&fe->remove_mutex); + return ret; + } + +@@ -2609,6 +2632,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) { +@@ -2628,10 +2653,18 @@ static int dvb_frontend_release(struct i + mutex_unlock(&fe->dvb->mdev->graph_mutex); + } + #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); +@@ -2725,6 +2758,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/drivers/media/dvb-core/dvb_frontend.h ++++ b/drivers/media/dvb-core/dvb_frontend.h +@@ -658,7 +658,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 { +@@ -676,6 +679,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 541babe..9400d52 100644 --- a/series.conf +++ b/series.conf @@ -27432,6 +27432,7 @@ patches.suse/media-dvb-core-Fix-UAF-due-to-refcount-races-at-rele.patch patches.suse/char-pcmcia-synclink_cs-Fix-use-after-free-in-mgslpc.patch patches.suse/misc-sgi-gru-fix-use-after-free-error-in-gru_set_con.patch + patches.suse/media-dvb-core-Fix-use-after-free-on-race-condition-.patch ######################################################## # Other drivers we have added to the tree