summaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2022-03-11 16:24:36 +0300
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2022-03-16 16:23:44 +0300
commiteb38c2e9fc740b5218dc94d2a6f43802d49e811c (patch)
treeeeae4b3150ec47f259f078820073e51d01e741e2 /kernel
parent82ff8a2243f79072178f6a741bdead88e0b0c324 (diff)
downloadlinux-eb38c2e9fc740b5218dc94d2a6f43802d49e811c.tar.xz
watch_queue: Fix lack of barrier/sync/lock between post and read
commit 2ed147f015af2b48f41c6f0b6746aa9ea85c19f3 upstream. There's nothing to synchronise post_one_notification() versus pipe_read(). Whilst posting is done under pipe->rd_wait.lock, the reader only takes pipe->mutex which cannot bar notification posting as that may need to be made from contexts that cannot sleep. Fix this by setting pipe->head with a barrier in post_one_notification() and reading pipe->head with a barrier in pipe_read(). If that's not sufficient, the rd_wait.lock will need to be taken, possibly in a ->confirm() op so that it only applies to notifications. The lock would, however, have to be dropped before copy_page_to_iter() is invoked. Fixes: c73be61cede5 ("pipe: Add general notification queue support") Reported-by: Jann Horn <jannh@google.com> Signed-off-by: David Howells <dhowells@redhat.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/watch_queue.c2
1 files changed, 1 insertions, 1 deletions
diff --git a/kernel/watch_queue.c b/kernel/watch_queue.c
index e4d7225f539e..1a13066bf6fa 100644
--- a/kernel/watch_queue.c
+++ b/kernel/watch_queue.c
@@ -113,7 +113,7 @@ static bool post_one_notification(struct watch_queue *wqueue,
buf->offset = offset;
buf->len = len;
buf->flags = PIPE_BUF_FLAG_WHOLE;
- pipe->head = head + 1;
+ smp_store_release(&pipe->head, head + 1); /* vs pipe_read() */
if (!test_and_clear_bit(note, wqueue->notes_bitmap)) {
spin_unlock_irq(&pipe->rd_wait.lock);