Skip to content

Commit 607d09d

Browse files
committed
io_uring/kbuf: limit legacy provided buffer lists to USHRT_MAX
The buffer ID for a provided buffer is an unsigned short, and hence there can only be 64k added to any given buffer list before having duplicate BIDs. Cap the legacy provided buffers at 64k in the list. This is mostly to prevent silly stall reports from syzbot, which likes to dump tons of buffers into a list and then have kernels with lockdep and kasan churning through them and hitting long wait times for buffer pruning at ring exit time. Signed-off-by: Jens Axboe <[email protected]>
1 parent e931d3a commit 607d09d

File tree

2 files changed

+18
-2
lines changed

2 files changed

+18
-2
lines changed

io_uring/kbuf.c

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ bool io_kbuf_recycle_legacy(struct io_kiocb *req, unsigned issue_flags)
108108
buf = req->kbuf;
109109
bl = io_buffer_get_list(ctx, buf->bgid);
110110
list_add(&buf->list, &bl->buf_list);
111+
bl->nbufs++;
111112
req->flags &= ~REQ_F_BUFFER_SELECTED;
112113

113114
io_ring_submit_unlock(ctx, issue_flags);
@@ -122,6 +123,7 @@ static void __user *io_provided_buffer_select(struct io_kiocb *req, size_t *len,
122123

123124
kbuf = list_first_entry(&bl->buf_list, struct io_buffer, list);
124125
list_del(&kbuf->list);
126+
bl->nbufs--;
125127
if (*len == 0 || *len > kbuf->len)
126128
*len = kbuf->len;
127129
if (list_empty(&bl->buf_list))
@@ -390,6 +392,7 @@ static int io_remove_buffers_legacy(struct io_ring_ctx *ctx,
390392
for (i = 0; i < nbufs && !list_empty(&bl->buf_list); i++) {
391393
nxt = list_first_entry(&bl->buf_list, struct io_buffer, list);
392394
list_del(&nxt->list);
395+
bl->nbufs--;
393396
kfree(nxt);
394397
cond_resched();
395398
}
@@ -491,14 +494,24 @@ static int io_add_buffers(struct io_ring_ctx *ctx, struct io_provide_buf *pbuf,
491494
{
492495
struct io_buffer *buf;
493496
u64 addr = pbuf->addr;
494-
int i, bid = pbuf->bid;
497+
int ret = -ENOMEM, i, bid = pbuf->bid;
495498

496499
for (i = 0; i < pbuf->nbufs; i++) {
500+
/*
501+
* Nonsensical to have more than sizeof(bid) buffers in a
502+
* buffer list, as the application then has no way of knowing
503+
* which duplicate bid refers to what buffer.
504+
*/
505+
if (bl->nbufs == USHRT_MAX) {
506+
ret = -EOVERFLOW;
507+
break;
508+
}
497509
buf = kmalloc(sizeof(*buf), GFP_KERNEL_ACCOUNT);
498510
if (!buf)
499511
break;
500512

501513
list_add_tail(&buf->list, &bl->buf_list);
514+
bl->nbufs++;
502515
buf->addr = addr;
503516
buf->len = min_t(__u32, pbuf->len, MAX_RW_COUNT);
504517
buf->bid = bid;
@@ -508,7 +521,7 @@ static int io_add_buffers(struct io_ring_ctx *ctx, struct io_provide_buf *pbuf,
508521
cond_resched();
509522
}
510523

511-
return i ? 0 : -ENOMEM;
524+
return i ? 0 : ret;
512525
}
513526

514527
static int __io_manage_buffers_legacy(struct io_kiocb *req,

io_uring/kbuf.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ struct io_buffer_list {
2121
struct list_head buf_list;
2222
struct io_uring_buf_ring *buf_ring;
2323
};
24+
/* count of classic/legacy buffers in buffer list */
25+
int nbufs;
26+
2427
__u16 bgid;
2528

2629
/* below is for ring provided buffers */

0 commit comments

Comments
 (0)