From 40bdfdc7cb514d79195e4e22a5bc00ea2b471278 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 9 Mar 2019 15:28:52 +0800 Subject: [PATCH] aio_poll(): sanitize the logics after vfs_poll(), get rid of leak on error euler inclusion category: bugfix bugzilla: 10679 CVE: NA --------------------------- We want iocb_put() happening on errors, to balance the extra reference we'd taken. As it is, we end up with a leak. The rules should be * error: iocb_put() to deal with the extra ref, return error, let the caller do another iocb_put(). * async: iocb_put() to deal with the extra ref, return 0. * no error, event present immediately: aio_poll_complete() to report it, iocb_put() to deal with the extra ref, return 0. Link: https://patchwork.kernel.org/patch/10842103/ Signed-off-by: Al Viro Signed-off-by: zhengbin Reviewed-by: zhangyi (F) Signed-off-by: Yang Yingliang --- fs/aio.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/fs/aio.c b/fs/aio.c index 8e624e3a7be9..471dd6abc679 100644 --- a/fs/aio.c +++ b/fs/aio.c @@ -1713,6 +1713,7 @@ static ssize_t aio_poll(struct aio_kiocb *aiocb, struct iocb *iocb) struct kioctx *ctx = aiocb->ki_ctx; struct poll_iocb *req = &aiocb->poll; struct aio_poll_table apt; + bool async = false; __poll_t mask; /* reject any unknown events outside the normal event mask. */ @@ -1754,18 +1755,19 @@ static ssize_t aio_poll(struct aio_kiocb *aiocb, struct iocb *iocb) spin_lock_irq(&ctx->ctx_lock); spin_lock(&req->head->lock); - if (req->woken) { - /* wake_up context handles the rest */ - mask = 0; + if (req->woken) { /* already taken up by aio_poll_wake() */ + async = true; apt.error = 0; - } else if (mask || apt.error) { - /* if we get an error or a mask we are done */ - WARN_ON_ONCE(list_empty(&req->wait.entry)); - list_del_init(&req->wait.entry); - } else { - /* actually waiting for an event */ + } else if (!mask && !apt.error) { /* actually waiting for an event */ list_add_tail(&aiocb->ki_list, &ctx->active_reqs); aiocb->ki_cancel = aio_poll_cancel; + async = true; + } else { /* if we get an error or a mask we are done */ + WARN_ON_ONCE(list_empty(&req->wait.entry)); + list_del_init(&req->wait.entry); + /* no wakeup in the future either; + * aiocb is ours to dispose of + */ } spin_unlock(&req->head->lock); spin_unlock_irq(&ctx->ctx_lock); @@ -1775,13 +1777,12 @@ static ssize_t aio_poll(struct aio_kiocb *aiocb, struct iocb *iocb) fput(req->file); if (unlikely(apt.error)) { fput(req->file); - return apt.error; } - if (mask) + if (!async && !apt.error) aio_poll_complete(aiocb, mask); iocb_put(aiocb); - return 0; + return apt.error; } static int io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb, -- GitLab