summaryrefslogtreecommitdiff
path: root/kernel/watch_queue.c
diff options
context:
space:
mode:
authorZhiyu Zhang <zhiyuzhang999@gmail.com>2026-10-29 01:41:36 -0400
committerChristian Brauner <brauner@kernel.org>2026-10-30 15:53:44 +0100
commit53d72818f9e2aeb03a6053544ee6efa4eb2a3988 (patch)
treed1ed0a7f2b4b33ec05aea5b06f194c15cff55a6a /kernel/watch_queue.c
parent87d02f3e98a86abf70441b0a0418e01cb1d64b44 (diff)
downloadlinux-53d72818f9e2aeb03a6053544ee6efa4eb2a3988.tar.gz
linux-53d72818f9e2aeb03a6053544ee6efa4eb2a3988.zip
watch_queue: keep info_id separate from rcu_head
struct watch overlays info_id with rcu_head. A notification poster reads info_id under rcu_read_lock(), but a concurrent final put can enqueue the watch with call_rcu(). Enqueueing the callback writes rcu_head before the grace period has elapsed, so it can corrupt info_id while the object remains legally visible to the reader. __post_watch_notification() then merges that value into the notification info word without masking it. Pointer bits can corrupt WATCH_INFO_LENGTH and make post_one_notification() copy beyond the posting task's stack record. Give info_id storage separate from rcu_head so RCU enqueueing cannot modify it. Place it after the kref, which uses existing tail padding on x86-64. Mask info_id with WATCH_INFO_ID at the point of use as an additional invariant check. An unprivileged shell and keyctl reproducer was run for 30 seconds in QEMU. The vulnerable baseline produced malformed notification lengths, while this change completed with 288631 key notifications and no malformed record. Fixes: c73be61cede5 ("pipe: Add general notification queue support") Reported-by: Tong Liu <lyutoon@gmail.com> Reported-by: Qi Tang <tpluszz77@gmail.com> Reported-by: Zhiyu Zhang <zhiyuzhang999@gmail.com> Closes: https://lore.kernel.org/lkml/CALf2hKveij_sHgANY9Aktm1dPa4wfKjKNkHyp9yPbjORWFXagA@mail.gmail.com/ Link: https://lore.kernel.org/netdev/CALf2hKvp0NPVLwr=a3+jUHtPohxbra8gox+aYAfWathJnn-J+Q@mail.gmail.com/ Signed-off-by: Zhiyu Zhang <zhiyuzhang999@gmail.com> Link: https://patch.msgid.link/20261029054136.1174216-1-zhiyuzhang999@gmail.com Reviewed-by: Bradley Morgan <brads@mainlining.org> Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
Diffstat (limited to 'kernel/watch_queue.c')
-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 932a88ac1f39..453dcf613205 100644
--- a/kernel/watch_queue.c
+++ b/kernel/watch_queue.c
@@ -212,7 +212,7 @@ void __post_watch_notification(struct watch_list *wlist,
if (watch->id != id)
continue;
n->info &= ~WATCH_INFO_ID;
- n->info |= watch->info_id;
+ n->info |= watch->info_id & WATCH_INFO_ID;
wqueue = rcu_dereference(watch->queue);
wf = rcu_dereference(wqueue->filter);