Messages in this thread | | | Date | Mon, 10 Jul 2023 23:02:33 +0800 | Subject | Re: [PATCH] eventfd: avoid overflow to ULLONG_MAX when ctx->count is 0 | From | Wen Yang <> |
| |
On 2023/7/10 22:12, Christian Brauner wrote: > On Sun, Jul 09, 2023 at 02:54:51PM +0800, wenyang.linux@foxmail.com wrote: >> From: Wen Yang <wenyang.linux@foxmail.com> >> >> For eventfd with flag EFD_SEMAPHORE, when its ctx->count is 0, calling >> eventfd_ctx_do_read will cause ctx->count to overflow to ULLONG_MAX. >> >> Fixes: cb289d6244a3 ("eventfd - allow atomic read and waitqueue remove") >> Signed-off-by: Wen Yang <wenyang.linux@foxmail.com> >> Cc: Alexander Viro <viro@zeniv.linux.org.uk> >> Cc: Jens Axboe <axboe@kernel.dk> >> Cc: Christian Brauner <brauner@kernel.org> >> Cc: Christoph Hellwig <hch@lst.de> >> Cc: Dylan Yudaken <dylany@fb.com> >> Cc: David Woodhouse <dwmw@amazon.co.uk> >> Cc: Matthew Wilcox <willy@infradead.org> >> Cc: linux-fsdevel@vger.kernel.org >> Cc: linux-kernel@vger.kernel.org >> --- > So this looks ok but I would like to see an analysis how the overflow > can happen. I'm looking at the callers and it seems that once ctx->count > hits 0 eventfd_read() won't call eventfd_ctx_do_read() anymore. So is > there a caller that can call directly or indirectly > eventfd_ctx_do_read() on a ctx->count == 0? eventfd_read() ensures that ctx->count is not 0 before calling eventfd_ctx_do_read() and it is correct.
But it is not appropriate for eventfd_ctx_remove_wait_queue() to call eventfd_ctx_do_read() unconditionally,
as it may not only causes ctx->count to overflow, but also unnecessarily calls wake_up_locked_poll().
I am sorry for just adding the following string in the patch: Fixes: cb289d6244a3 ("eventfd - allow atomic read and waitqueue remove")
Looking forward to your suggestions.
--
Best wishes,
Wen
> I'm just slightly skeptical about patches that fix issues without an > analysis how this can happen. > >> fs/eventfd.c | 4 +++- >> 1 file changed, 3 insertions(+), 1 deletion(-) >> >> diff --git a/fs/eventfd.c b/fs/eventfd.c >> index 8aa36cd37351..10a101df19cd 100644 >> --- a/fs/eventfd.c >> +++ b/fs/eventfd.c >> @@ -189,7 +189,7 @@ void eventfd_ctx_do_read(struct eventfd_ctx *ctx, __u64 *cnt) >> { >> lockdep_assert_held(&ctx->wqh.lock); >> >> - *cnt = (ctx->flags & EFD_SEMAPHORE) ? 1 : ctx->count; >> + *cnt = ((ctx->flags & EFD_SEMAPHORE) && ctx->count) ? 1 : ctx->count; >> ctx->count -= *cnt; >> } >> EXPORT_SYMBOL_GPL(eventfd_ctx_do_read); >> @@ -269,6 +269,8 @@ static ssize_t eventfd_write(struct file *file, const char __user *buf, size_t c >> return -EFAULT; >> if (ucnt == ULLONG_MAX) >> return -EINVAL; >> + if ((ctx->flags & EFD_SEMAPHORE) && !ucnt) >> + return -EINVAL; >> spin_lock_irq(&ctx->wqh.lock); >> res = -EAGAIN; >> if (ULLONG_MAX - ctx->count > ucnt) >> -- >> 2.25.1 >>
| |