Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

media: dvb-core: Fix kernel WARNING for blocking operation in wait_event*()

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>

authored by

Takashi Iwai and committed by
Mauro Carvalho Chehab
b8c75e4a 627bb528

+12 -4
+12 -4
drivers/media/dvb-core/dvb_frontend.c
··· 293 293 } 294 294 295 295 if (events->eventw == events->eventr) { 296 - int ret; 296 + struct wait_queue_entry wait; 297 + int ret = 0; 297 298 298 299 if (flags & O_NONBLOCK) 299 300 return -EWOULDBLOCK; 300 301 301 - ret = wait_event_interruptible(events->wait_queue, 302 - dvb_frontend_test_event(fepriv, events)); 303 - 302 + init_waitqueue_entry(&wait, current); 303 + add_wait_queue(&events->wait_queue, &wait); 304 + while (!dvb_frontend_test_event(fepriv, events)) { 305 + wait_woken(&wait, TASK_INTERRUPTIBLE, 0); 306 + if (signal_pending(current)) { 307 + ret = -ERESTARTSYS; 308 + break; 309 + } 310 + } 311 + remove_wait_queue(&events->wait_queue, &wait); 304 312 if (ret < 0) 305 313 return ret; 306 314 }