io_uring: remove double poll entry on arm failure
authorPavel Begunkov <asml.silence@gmail.com>
Tue, 20 Jul 2021 09:50:44 +0000 (10:50 +0100)
committerJens Axboe <axboe@kernel.dk>
Tue, 20 Jul 2021 13:50:42 +0000 (07:50 -0600)
__io_queue_proc() can enqueue both poll entries and still fail
afterwards, so the callers trying to cancel it should also try to remove
the second poll entry (if any).

For example, it may leave the request alive referencing a io_uring
context but not accessible for cancellation:

[  282.599913][ T1620] task:iou-sqp-23145   state:D stack:28720 pid:23155 ppid:  8844 flags:0x00004004
[  282.609927][ T1620] Call Trace:
[  282.613711][ T1620]  __schedule+0x93a/0x26f0
[  282.634647][ T1620]  schedule+0xd3/0x270
[  282.638874][ T1620]  io_uring_cancel_generic+0x54d/0x890
[  282.660346][ T1620]  io_sq_thread+0xaac/0x1250
[  282.696394][ T1620]  ret_from_fork+0x1f/0x30

Cc: stable@vger.kernel.org
Fixes: 18bceab101add ("io_uring: allow POLL_ADD with double poll_wait() users")
Reported-and-tested-by: syzbot+ac957324022b7132accf@syzkaller.appspotmail.com
Signed-off-by: Pavel Begunkov <asml.silence@gmail.com>
Link: https://lore.kernel.org/r/0ec1228fc5eda4cb524eeda857da8efdc43c331c.1626774457.git.asml.silence@gmail.com
Signed-off-by: Jens Axboe <axboe@kernel.dk>
fs/io_uring.c

index 6668902cf50c0c61851b8660663880505dff4180..6486b54a0f620163d9b0ccd9aa6b1c755b01bcee 100644 (file)
@@ -5113,6 +5113,8 @@ static __poll_t __io_arm_poll_handler(struct io_kiocb *req,
                ipt->error = -EINVAL;
 
        spin_lock_irq(&ctx->completion_lock);
+       if (ipt->error)
+               io_poll_remove_double(req);
        if (likely(poll->head)) {
                spin_lock(&poll->head->lock);
                if (unlikely(list_empty(&poll->wait.entry))) {