diff options
author | Jens Axboe <axboe@kernel.dk> | 2023-03-17 10:42:08 -0600 |
---|---|---|
committer | Jens Axboe <axboe@kernel.dk> | 2023-04-03 07:16:14 -0600 |
commit | fcb46c0ccc7c07af54f818fd498e461353ea50e7 (patch) | |
tree | 8053256e7e48f16be068cbfa3ef46ff06b885686 /io_uring | |
parent | e1fe7ee885dc0712e982ee465d9f8b96254c30c1 (diff) |
io_uring/kbuf: disallow mapping a badly aligned provided ring buffer
On at least parisc, we have strict requirements on how we virtually map
an address that is shared between the application and the kernel. On
these platforms, IOU_PBUF_RING_MMAP should be used when setting up a
shared ring buffer for provided buffers. If the application is mapping
these pages and asking the kernel to pin+map them as well, then we have
no control over what virtual address we get in the kernel.
For that case, do a sanity check if SHM_COLOUR is defined, and disallow
the mapping request. The application must fall back to using
IOU_PBUF_RING_MMAP for this case, and liburing will do that transparently
with the set of helpers that it has.
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Diffstat (limited to 'io_uring')
-rw-r--r-- | io_uring/kbuf.c | 18 |
1 files changed, 18 insertions, 0 deletions
diff --git a/io_uring/kbuf.c b/io_uring/kbuf.c index cd1d9dddf58e..79c25459e8de 100644 --- a/io_uring/kbuf.c +++ b/io_uring/kbuf.c @@ -491,6 +491,24 @@ static int io_pin_pbuf_ring(struct io_uring_buf_reg *reg, return PTR_ERR(pages); br = page_address(pages[0]); +#ifdef SHM_COLOUR + /* + * On platforms that have specific aliasing requirements, SHM_COLOUR + * is set and we must guarantee that the kernel and user side align + * nicely. We cannot do that if IOU_PBUF_RING_MMAP isn't set and + * the application mmap's the provided ring buffer. Fail the request + * if we, by chance, don't end up with aligned addresses. The app + * should use IOU_PBUF_RING_MMAP instead, and liburing will handle + * this transparently. + */ + if ((reg->ring_addr | (unsigned long) br) & (SHM_COLOUR - 1)) { + int i; + + for (i = 0; i < nr_pages; i++) + unpin_user_page(pages[i]); + return -EINVAL; + } +#endif bl->buf_pages = pages; bl->buf_nr_pages = nr_pages; bl->buf_ring = br; |