Skip to content

Commit 353f798

Browse files
committed
watchqueue: make sure to serialize 'wqueue->defunct' properly
When the pipe is closed, we mark the associated watchqueue defunct by calling watch_queue_clear(). However, while that is protected by the watchqueue lock, new watchqueue entries aren't actually added under that lock at all: they use the pipe->rd_wait.lock instead, and looking up that pipe happens without any locking. The watchqueue code uses the RCU read-side section to make sure that the wqueue entry itself hasn't disappeared, but that does not protect the pipe_info in any way. So make sure to actually hold the wqueue lock when posting watch events, properly serializing against the pipe being torn down. Reported-by: Noam Rathaus <[email protected]> Cc: Greg KH <[email protected]> Cc: David Howells <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent 543ce63 commit 353f798

File tree

1 file changed

+37
-16
lines changed

1 file changed

+37
-16
lines changed

kernel/watch_queue.c

Lines changed: 37 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,27 @@ MODULE_LICENSE("GPL");
3434
#define WATCH_QUEUE_NOTE_SIZE 128
3535
#define WATCH_QUEUE_NOTES_PER_PAGE (PAGE_SIZE / WATCH_QUEUE_NOTE_SIZE)
3636

37+
/*
38+
* This must be called under the RCU read-lock, which makes
39+
* sure that the wqueue still exists. It can then take the lock,
40+
* and check that the wqueue hasn't been destroyed, which in
41+
* turn makes sure that the notification pipe still exists.
42+
*/
43+
static inline bool lock_wqueue(struct watch_queue *wqueue)
44+
{
45+
spin_lock_bh(&wqueue->lock);
46+
if (unlikely(wqueue->defunct)) {
47+
spin_unlock_bh(&wqueue->lock);
48+
return false;
49+
}
50+
return true;
51+
}
52+
53+
static inline void unlock_wqueue(struct watch_queue *wqueue)
54+
{
55+
spin_unlock_bh(&wqueue->lock);
56+
}
57+
3758
static void watch_queue_pipe_buf_release(struct pipe_inode_info *pipe,
3859
struct pipe_buffer *buf)
3960
{
@@ -69,6 +90,10 @@ static const struct pipe_buf_operations watch_queue_pipe_buf_ops = {
6990

7091
/*
7192
* Post a notification to a watch queue.
93+
*
94+
* Must be called with the RCU lock for reading, and the
95+
* watch_queue lock held, which guarantees that the pipe
96+
* hasn't been released.
7297
*/
7398
static bool post_one_notification(struct watch_queue *wqueue,
7499
struct watch_notification *n)
@@ -85,9 +110,6 @@ static bool post_one_notification(struct watch_queue *wqueue,
85110

86111
spin_lock_irq(&pipe->rd_wait.lock);
87112

88-
if (wqueue->defunct)
89-
goto out;
90-
91113
mask = pipe->ring_size - 1;
92114
head = pipe->head;
93115
tail = pipe->tail;
@@ -203,7 +225,10 @@ void __post_watch_notification(struct watch_list *wlist,
203225
if (security_post_notification(watch->cred, cred, n) < 0)
204226
continue;
205227

206-
post_one_notification(wqueue, n);
228+
if (lock_wqueue(wqueue)) {
229+
post_one_notification(wqueue, n);
230+
unlock_wqueue(wqueue);;
231+
}
207232
}
208233

209234
rcu_read_unlock();
@@ -462,11 +487,12 @@ int add_watch_to_object(struct watch *watch, struct watch_list *wlist)
462487
return -EAGAIN;
463488
}
464489

465-
spin_lock_bh(&wqueue->lock);
466-
kref_get(&wqueue->usage);
467-
kref_get(&watch->usage);
468-
hlist_add_head(&watch->queue_node, &wqueue->watches);
469-
spin_unlock_bh(&wqueue->lock);
490+
if (lock_wqueue(wqueue)) {
491+
kref_get(&wqueue->usage);
492+
kref_get(&watch->usage);
493+
hlist_add_head(&watch->queue_node, &wqueue->watches);
494+
unlock_wqueue(wqueue);
495+
}
470496

471497
hlist_add_head(&watch->list_node, &wlist->watchers);
472498
return 0;
@@ -520,20 +546,15 @@ int remove_watch_from_object(struct watch_list *wlist, struct watch_queue *wq,
520546

521547
wqueue = rcu_dereference(watch->queue);
522548

523-
/* We don't need the watch list lock for the next bit as RCU is
524-
* protecting *wqueue from deallocation.
525-
*/
526-
if (wqueue) {
549+
if (lock_wqueue(wqueue)) {
527550
post_one_notification(wqueue, &n.watch);
528551

529-
spin_lock_bh(&wqueue->lock);
530-
531552
if (!hlist_unhashed(&watch->queue_node)) {
532553
hlist_del_init_rcu(&watch->queue_node);
533554
put_watch(watch);
534555
}
535556

536-
spin_unlock_bh(&wqueue->lock);
557+
unlock_wqueue(wqueue);
537558
}
538559

539560
if (wlist->release_watch) {

0 commit comments

Comments
 (0)