diff mbox series

watch_queue: fix pipe accounting mismatch

Message ID 206682a8-0604-49e5-8224-fdbe0c12b460@redhat.com (mailing list archive)
State New
Headers show
Series watch_queue: fix pipe accounting mismatch | expand

Commit Message

Eric Sandeen Feb. 27, 2025, 5:41 p.m. UTC
Currently, watch_queue_set_size() modifies the pipe buffers charged to
user->pipe_bufs without updating the pipe->nr_accounted on the pipe
itself, due to the if (!pipe_has_watch_queue()) test in
pipe_resize_ring(). This means that when the pipe is ultimately freed,
we decrement user->pipe_bufs by something other than what than we had
charged to it, potentially leading to an underflow. This in turn can
cause subsequent too_many_pipe_buffers_soft() tests to fail with -EPERM.

To remedy this, explicitly account for the pipe usage in
watch_queue_set_size() to match the number set via account_pipe_buffers()

(It's unclear why watch_queue_set_size() does not update nr_accounted;
it may be due to intentional overprovisioning in watch_queue_set_size()?)

Fixes: e95aada4cb93d ("pipe: wakeup wr_wait after setting max_usage")
Signed-off-by: Eric Sandeen <sandeen@redhat.com
---

Comments

Christian Brauner Feb. 28, 2025, 10:17 a.m. UTC | #1
On Thu, 27 Feb 2025 11:41:08 -0600, Eric Sandeen wrote:
> Currently, watch_queue_set_size() modifies the pipe buffers charged to
> user->pipe_bufs without updating the pipe->nr_accounted on the pipe
> itself, due to the if (!pipe_has_watch_queue()) test in
> pipe_resize_ring(). This means that when the pipe is ultimately freed,
> we decrement user->pipe_bufs by something other than what than we had
> charged to it, potentially leading to an underflow. This in turn can
> cause subsequent too_many_pipe_buffers_soft() tests to fail with -EPERM.
> 
> [...]

Applied to the vfs-6.15.misc branch of the vfs/vfs.git tree.
Patches in the vfs-6.15.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.

Note that commit hashes shown below are subject to change due to rebase,
trailer updates or similar. If in doubt, please check the listed branch.

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

[1/1] watch_queue: fix pipe accounting mismatch
      https://git.kernel.org/vfs/vfs/c/483b7214f602
diff mbox series

Patch

diff --git a/kernel/watch_queue.c b/kernel/watch_queue.c
index 5267adeaa403..41e4e8070923 100644
--- a/kernel/watch_queue.c
+++ b/kernel/watch_queue.c
@@ -269,6 +269,15 @@  long watch_queue_set_size(struct pipe_inode_info *pipe, unsigned int nr_notes)
 	if (ret < 0)
 		goto error;
 
+	/*
+	 * pipe_resize_ring() does not update nr_accounted for watch_queue
+	 * pipes, because the above vastly overprovisions. Set nr_accounted on
+	 * and max_usage this pipe to the number that was actually charged to
+	 * the user above via account_pipe_buffers.
+	 */
+	pipe->max_usage = nr_pages;
+	pipe->nr_accounted = nr_pages;
+
 	ret = -ENOMEM;
 	pages = kcalloc(nr_pages, sizeof(struct page *), GFP_KERNEL);
 	if (!pages)