]> git.ipfire.org Git - thirdparty/kernel/stable.git/commit
poll_wait: add mb() to fix theoretical race between waitqueue_active() and .poll()
authorOleg Nesterov <oleg@redhat.com>
Tue, 7 Jan 2025 16:27:17 +0000 (17:27 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 23 Jan 2025 16:16:00 +0000 (17:16 +0100)
commit7df94f7f9e22a47dde0b4abc21747f3f344e08da
tree4ec96a9f8ca6600c25b84a5a508fb7caa4b50c68
parent1c878c5527e1fc5d2cab9e45d6ae4f454f19238e
poll_wait: add mb() to fix theoretical race between waitqueue_active() and .poll()

[ Upstream commit cacd9ae4bf801ff4125d8961bb9a3ba955e51680 ]

As the comment above waitqueue_active() explains, it can only be used
if both waker and waiter have mb()'s that pair with each other. However
__pollwait() is broken in this respect.

This is not pipe-specific, but let's look at pipe_poll() for example:

poll_wait(...); // -> __pollwait() -> add_wait_queue()

LOAD(pipe->head);
LOAD(pipe->head);

In theory these LOAD()'s can leak into the critical section inside
add_wait_queue() and can happen before list_add(entry, wq_head), in this
case pipe_poll() can race with wakeup_pipe_readers/writers which do

smp_mb();
if (waitqueue_active(wq_head))
wake_up_interruptible(wq_head);

There are more __pollwait()-like functions (grep init_poll_funcptr), and
it seems that at least ep_ptable_queue_proc() has the same problem, so the
patch adds smp_mb() into poll_wait().

Link: https://lore.kernel.org/all/20250102163320.GA17691@redhat.com/
Signed-off-by: Oleg Nesterov <oleg@redhat.com>
Link: https://lore.kernel.org/r/20250107162717.GA18922@redhat.com
Signed-off-by: Christian Brauner <brauner@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
include/linux/poll.h