Skip to content

Commit 943211c

Browse files
siddhpantbrauner
authored andcommitted
watch_queue: prevent dangling pipe pointer
NULL the dangling pipe reference while clearing watch_queue. If not done, a reference to a freed pipe remains in the watch_queue, as this function is called before freeing a pipe in free_pipe_info() (see line 834 of fs/pipe.c). The sole use of wqueue->defunct is for checking if the watch queue has been cleared, but wqueue->pipe is also NULLed while clearing. Thus, wqueue->defunct is superfluous, as wqueue->pipe can be checked for NULL. Hence, the former can be removed. Tested with keyutils testsuite. Cc: stable@vger.kernel.org # 6.1 Signed-off-by: Siddh Raman Pant <code@siddh.me> Acked-by: David Howells <dhowells@redhat.com> Message-Id: <20230605143616.640517-1-code@siddh.me> Signed-off-by: Christian Brauner <brauner@kernel.org>
1 parent a7bc2e8 commit 943211c

2 files changed

Lines changed: 7 additions & 8 deletions

File tree

include/linux/watch_queue.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,15 +38,14 @@ struct watch_filter {
3838
struct watch_queue {
3939
struct rcu_head rcu;
4040
struct watch_filter __rcu *filter;
41-
struct pipe_inode_info *pipe; /* The pipe we're using as a buffer */
41+
struct pipe_inode_info *pipe; /* Pipe we use as a buffer, NULL if queue closed */
4242
struct hlist_head watches; /* Contributory watches */
4343
struct page **notes; /* Preallocated notifications */
4444
unsigned long *notes_bitmap; /* Allocation bitmap for notes */
4545
struct kref usage; /* Object usage count */
4646
spinlock_t lock;
4747
unsigned int nr_notes; /* Number of notes */
4848
unsigned int nr_pages; /* Number of pages in notes[] */
49-
bool defunct; /* T when queues closed */
5049
};
5150

5251
/*

kernel/watch_queue.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ MODULE_AUTHOR("Red Hat, Inc.");
4242
static inline bool lock_wqueue(struct watch_queue *wqueue)
4343
{
4444
spin_lock_bh(&wqueue->lock);
45-
if (unlikely(wqueue->defunct)) {
45+
if (unlikely(!wqueue->pipe)) {
4646
spin_unlock_bh(&wqueue->lock);
4747
return false;
4848
}
@@ -104,9 +104,6 @@ static bool post_one_notification(struct watch_queue *wqueue,
104104
unsigned int head, tail, mask, note, offset, len;
105105
bool done = false;
106106

107-
if (!pipe)
108-
return false;
109-
110107
spin_lock_irq(&pipe->rd_wait.lock);
111108

112109
mask = pipe->ring_size - 1;
@@ -603,8 +600,11 @@ void watch_queue_clear(struct watch_queue *wqueue)
603600
rcu_read_lock();
604601
spin_lock_bh(&wqueue->lock);
605602

606-
/* Prevent new notifications from being stored. */
607-
wqueue->defunct = true;
603+
/*
604+
* This pipe can be freed by callers like free_pipe_info().
605+
* Removing this reference also prevents new notifications.
606+
*/
607+
wqueue->pipe = NULL;
608608

609609
while (!hlist_empty(&wqueue->watches)) {
610610
watch = hlist_entry(wqueue->watches.first, struct watch, queue_node);

0 commit comments

Comments
 (0)