mirror of
https://gitlab.com/redhat/centos-stream/src/kernel/centos-stream-10.git
synced 2026-09-09 00:07:04 +08:00
io_uring/kbuf: limit legacy provided buffer lists to USHRT_MAX
JIRA: https://issues.redhat.com/browse/RHEL-161187 commit 607d09d1a01e9f29e91733e3a08b63ed240aacb2 Author: Jens Axboe <axboe@kernel.dk> Date: Tue Jun 3 07:42:28 2025 -0600 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 <axboe@kernel.dk> Signed-off-by: Jeff Moyer <jmoyer@redhat.com>
This commit is contained in:
+15
-2
@@ -113,6 +113,7 @@ bool io_kbuf_recycle_legacy(struct io_kiocb *req, unsigned issue_flags)
|
||||
buf = req->kbuf;
|
||||
bl = io_buffer_get_list(ctx, buf->bgid);
|
||||
list_add(&buf->list, &bl->buf_list);
|
||||
bl->nbufs++;
|
||||
req->flags &= ~REQ_F_BUFFER_SELECTED;
|
||||
req->buf_index = buf->bgid;
|
||||
|
||||
@@ -128,6 +129,7 @@ static void __user *io_provided_buffer_select(struct io_kiocb *req, size_t *len,
|
||||
|
||||
kbuf = list_first_entry(&bl->buf_list, struct io_buffer, list);
|
||||
list_del(&kbuf->list);
|
||||
bl->nbufs--;
|
||||
if (*len == 0 || *len > kbuf->len)
|
||||
*len = kbuf->len;
|
||||
if (list_empty(&bl->buf_list))
|
||||
@@ -411,6 +413,7 @@ static int __io_remove_buffers(struct io_ring_ctx *ctx,
|
||||
|
||||
nxt = list_first_entry(&bl->buf_list, struct io_buffer, list);
|
||||
list_del(&nxt->list);
|
||||
bl->nbufs--;
|
||||
kfree(nxt);
|
||||
|
||||
if (++i == nbufs)
|
||||
@@ -538,14 +541,24 @@ static int io_add_buffers(struct io_ring_ctx *ctx, struct io_provide_buf *pbuf,
|
||||
{
|
||||
struct io_buffer *buf;
|
||||
u64 addr = pbuf->addr;
|
||||
int i, bid = pbuf->bid;
|
||||
int ret = -ENOMEM, i, bid = pbuf->bid;
|
||||
|
||||
for (i = 0; i < pbuf->nbufs; i++) {
|
||||
/*
|
||||
* Nonsensical to have more than sizeof(bid) buffers in a
|
||||
* buffer list, as the application then has no way of knowing
|
||||
* which duplicate bid refers to what buffer.
|
||||
*/
|
||||
if (bl->nbufs == USHRT_MAX) {
|
||||
ret = -EOVERFLOW;
|
||||
break;
|
||||
}
|
||||
buf = kmalloc(sizeof(*buf), GFP_KERNEL_ACCOUNT);
|
||||
if (!buf)
|
||||
break;
|
||||
|
||||
list_add_tail(&buf->list, &bl->buf_list);
|
||||
bl->nbufs++;
|
||||
buf->addr = addr;
|
||||
buf->len = min_t(__u32, pbuf->len, MAX_RW_COUNT);
|
||||
buf->bid = bid;
|
||||
@@ -555,7 +568,7 @@ static int io_add_buffers(struct io_ring_ctx *ctx, struct io_provide_buf *pbuf,
|
||||
cond_resched();
|
||||
}
|
||||
|
||||
return i ? 0 : -ENOMEM;
|
||||
return i ? 0 : ret;
|
||||
}
|
||||
|
||||
int io_provide_buffers(struct io_kiocb *req, unsigned int issue_flags)
|
||||
|
||||
@@ -21,6 +21,9 @@ struct io_buffer_list {
|
||||
struct list_head buf_list;
|
||||
struct io_uring_buf_ring *buf_ring;
|
||||
};
|
||||
/* count of classic/legacy buffers in buffer list */
|
||||
int nbufs;
|
||||
|
||||
__u16 bgid;
|
||||
|
||||
/* below is for ring provided buffers */
|
||||
|
||||
Reference in New Issue
Block a user