summaryrefslogtreecommitdiffstats
path: root/drivers/media/dvb-core
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2023-05-12 16:18:00 +0100
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2023-06-09 10:23:59 +0200
commitf3b5442184a0dab5cee9b2682f947393569e24b2 (patch)
treef32cc1b474dc0c4d3d53c3dd867dd69e56beb174 /drivers/media/dvb-core
parent7bb9c6e05efcecb15b0354d574efbc36ca321d75 (diff)
downloadlinux-stable-f3b5442184a0dab5cee9b2682f947393569e24b2.tar.gz
linux-stable-f3b5442184a0dab5cee9b2682f947393569e24b2.tar.bz2
linux-stable-f3b5442184a0dab5cee9b2682f947393569e24b2.zip
media: dvb-core: Fix kernel WARNING for blocking operation in wait_event*()
[ Upstream commit b8c75e4a1b325ea0a9433fa8834be97b5836b946 ] Using a semaphore in the wait_event*() condition is no good idea. It hits a kernel WARN_ON() at prepare_to_wait_event() like: do not call blocking ops when !TASK_RUNNING; state=1 set at prepare_to_wait_event+0x6d/0x690 For avoiding the potential deadlock, rewrite to an open-coded loop instead. Unlike the loop in wait_event*(), this uses wait_woken() after the condition check, hence the task state stays consistent. CVE-2023-31084 was assigned to this bug. Link: https://lore.kernel.org/r/CA+UBctCu7fXn4q41O_3=id1+OdyQ85tZY1x+TkT-6OVBL6KAUw@mail.gmail.com/ Link: https://lore.kernel.org/linux-media/20230512151800.1874-1-tiwai@suse.de Reported-by: Yu Hao <yhao016@ucr.edu> Closes: https://nvd.nist.gov/vuln/detail/CVE-2023-31084 Signed-off-by: Takashi Iwai <tiwai@suse.de> Signed-off-by: Mauro Carvalho Chehab <mchehab@kernel.org> Signed-off-by: Sasha Levin <sashal@kernel.org>
Diffstat (limited to 'drivers/media/dvb-core')
-rw-r--r--drivers/media/dvb-core/dvb_frontend.c16
1 files changed, 12 insertions, 4 deletions
diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c
index e0650bc2df61..90acf52cc253 100644
--- a/drivers/media/dvb-core/dvb_frontend.c
+++ b/drivers/media/dvb-core/dvb_frontend.c
@@ -304,14 +304,22 @@ static int dvb_frontend_get_event(struct dvb_frontend *fe,
}
if (events->eventw == events->eventr) {
- int ret;
+ struct wait_queue_entry wait;
+ int ret = 0;
if (flags & O_NONBLOCK)
return -EWOULDBLOCK;
- ret = wait_event_interruptible(events->wait_queue,
- dvb_frontend_test_event(fepriv, events));
-
+ init_waitqueue_entry(&wait, current);
+ add_wait_queue(&events->wait_queue, &wait);
+ while (!dvb_frontend_test_event(fepriv, events)) {
+ wait_woken(&wait, TASK_INTERRUPTIBLE, 0);
+ if (signal_pending(current)) {
+ ret = -ERESTARTSYS;
+ break;
+ }
+ }
+ remove_wait_queue(&events->wait_queue, &wait);
if (ret < 0)
return ret;
}