2023-06-05 15:01:50

by Siddh Raman Pant

[permalink] [raw]
Subject: [PATCH v5] kernel/watch_queue: NULL the dangling *pipe, and use it for clear check

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: [email protected] # 6.1
Signed-off-by: Siddh Raman Pant <[email protected]>
---
Changes in v5:
- Rebased to latest mainline.
- Added Cc to stable.
- Specify tests passing. Note that all tests in the keyutils testsuite
passed, except tests/features/builtin_trusted, which we should not
worry about as it requires some kernel preparation according to
David Howells in v4 discussion.

Changes in v4 (11 Jan 2023):
- Drop preceeding kerneldoc-changes patch and change appropriately.

Changes in v3 (8 Jan 2023):
- Minor rephrase of comment before NULLing in watch_queue_clear().

Changes in v2 (6 Aug 2022):
- Merged the NULLing and removing defunct patches.
- Removed READ_ONCE barrier in lock_wqueue().
- Better commit messages.

include/linux/watch_queue.h | 3 +--
kernel/watch_queue.c | 12 ++++++------
2 files changed, 7 insertions(+), 8 deletions(-)

diff --git a/include/linux/watch_queue.h b/include/linux/watch_queue.h
index fc6bba20273b..45cd42f55d49 100644
--- a/include/linux/watch_queue.h
+++ b/include/linux/watch_queue.h
@@ -38,7 +38,7 @@ struct watch_filter {
struct watch_queue {
struct rcu_head rcu;
struct watch_filter __rcu *filter;
- struct pipe_inode_info *pipe; /* The pipe we're using as a buffer */
+ struct pipe_inode_info *pipe; /* Pipe we use as a buffer, NULL if queue closed */
struct hlist_head watches; /* Contributory watches */
struct page **notes; /* Preallocated notifications */
unsigned long *notes_bitmap; /* Allocation bitmap for notes */
@@ -46,7 +46,6 @@ struct watch_queue {
spinlock_t lock;
unsigned int nr_notes; /* Number of notes */
unsigned int nr_pages; /* Number of pages in notes[] */
- bool defunct; /* T when queues closed */
};

/*
diff --git a/kernel/watch_queue.c b/kernel/watch_queue.c
index e91cb4c2833f..d0b6b390ee42 100644
--- a/kernel/watch_queue.c
+++ b/kernel/watch_queue.c
@@ -42,7 +42,7 @@ MODULE_AUTHOR("Red Hat, Inc.");
static inline bool lock_wqueue(struct watch_queue *wqueue)
{
spin_lock_bh(&wqueue->lock);
- if (unlikely(wqueue->defunct)) {
+ if (unlikely(!wqueue->pipe)) {
spin_unlock_bh(&wqueue->lock);
return false;
}
@@ -104,9 +104,6 @@ static bool post_one_notification(struct watch_queue *wqueue,
unsigned int head, tail, mask, note, offset, len;
bool done = false;

- if (!pipe)
- return false;
-
spin_lock_irq(&pipe->rd_wait.lock);

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

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

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




2023-06-06 09:26:58

by Christian Brauner

[permalink] [raw]
Subject: Re: [PATCH v5] kernel/watch_queue: NULL the dangling *pipe, and use it for clear check

On Mon, 05 Jun 2023 20:06:16 +0530, Siddh Raman Pant wrote:
> 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.
>
> [...]

Massaged the commit message a bit and applied David's Ack as requested.

---

Applied to the vfs.misc branch of the vfs/vfs.git tree.
Patches in the vfs.misc branch should appear in linux-next soon.

Please report any outstanding bugs that were missed during review in a
new review to the original patch series allowing us to drop it.

It's encouraged to provide Acked-bys and Reviewed-bys even though the
patch has now been applied. If possible patch trailers will be updated.

tree: https://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs.git
branch: vfs.misc

[1/1] kernel/watch_queue: NULL the dangling *pipe, and use it for clear check
https://git.kernel.org/vfs/vfs/c/ae33d3de5ff5

2023-06-06 09:37:30

by Siddh Raman Pant

[permalink] [raw]
Subject: Re: [PATCH v5] kernel/watch_queue: NULL the dangling *pipe, and use it for clear check

On Tue, 06 Jun 2023 14:22:49 +0530, Christian Brauner wrote:
> Massaged the commit message a bit and applied David's Ack as requested.
>
> ---
>
> Applied to the vfs.misc branch of the vfs/vfs.git tree.
> Patches in the vfs.misc branch should appear in linux-next soon.

Thank you!
-- Siddh