Messages in this thread Patch in this message | | | From | Siddh Raman Pant <> | Subject | [PATCH 1/3 v4] kernel/watch_queue: Remove dangling pipe reference while clearing watch_queue | Date | Thu, 4 Aug 2022 19:00:22 +0530 |
| |
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).
We also need to use READ_ONCE() in post_one_notification() to prevent the compiler from optimising and loading a non-NULL value from wqueue->pipe.
Signed-off-by: Siddh Raman Pant <code@siddh.me> --- Changes in v4: - Brought the lines towards the start rather than the end. - Removed incorrect NULLing of wqueue->pipe->watch_queue. The latter was pointed out by Eric Biggers <ebiggers@kernel.org> in reply to v3.
Changes in v3: - Restored the original unlock order, and clear before unlock. - Used READ_ONCE() in post path. This was explained by David Howells <dhowells@redhat.com> in reply to v1.
Changes in v2: - Removed the superfluous ifdef guard.
kernel/watch_queue.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/kernel/watch_queue.c b/kernel/watch_queue.c index a6f9bdd956c3..8999c4e3076d 100644 --- a/kernel/watch_queue.c +++ b/kernel/watch_queue.c @@ -99,7 +99,7 @@ static bool post_one_notification(struct watch_queue *wqueue, struct watch_notification *n) { void *p; - struct pipe_inode_info *pipe = wqueue->pipe; + struct pipe_inode_info *pipe = READ_ONCE(wqueue->pipe); struct pipe_buffer *buf; struct page *page; unsigned int head, tail, mask, note, offset, len; @@ -606,6 +606,9 @@ void watch_queue_clear(struct watch_queue *wqueue) /* Prevent new notifications from being stored. */ wqueue->defunct = true; + /* This pipe will get freed by caller, and we are anyways clearing. */ + wqueue->pipe = NULL; + while (!hlist_empty(&wqueue->watches)) { watch = hlist_entry(wqueue->watches.first, struct watch, queue_node); hlist_del_init_rcu(&watch->queue_node); -- 2.35.1
| |