Re: [PATCH 1/4] virtio_console: copy pipe buffers in splice_write()
From: Christian Brauner
Date: Wed Nov 11 2026 - 07:45:24 EST
On Tue, Nov 10, 2026 at 07:19:30PM +0000, Matthew Wilcox wrote:
> On Tue, Nov 10, 2026 at 02:52:36PM +0000, Kiryl Shutsemau (Meta) wrote:
> > + src = kmap_local_page(buf->page);
> > + memcpy(page_address(page) + offset, src + buf->offset, len);
> > + kunmap_local(src);
>
> memcpy_from_page(page_address(page) + offset, buf->page, buf->offset,
> len);
I don't think that works. pipe_to_sg() only clamps len to the
destination page. A pipe buffer however can span multiple pages of a
compound page iircu. And buf->offset can point past the first one.
I found two exmples:
(1) skb_splice_bits() for AF_UNIX and TCP
(2) tracing_buffers_splice_read() with buffer_subbuf_size_kb > 4,
And virtio-trace splices that stuff.
Which means VM_BUG_ON() in memcpy_from_page() fires:
kernel BUG at include/linux/highmem.h:542!
Oops: invalid opcode: 0000 [#1] SMP NOPTI
RIP: 0010:pipe_to_sg+0x130/0x150
Call Trace:
<TASK>
__splice_from_pipe+0x92/0x1e0
port_fops_splice_write+0x13f/0x1a0
do_splice+0x3b6/0x8e0
__do_splice+0x20a/0x230
__x64_sys_splice+0x97/0x130
do_syscall_64+0xde/0x4b0
entry_SYSCALL_64_after_hwframe+0x77/0x7f
Fwiw, the open-coded copy is broken as well. Just on HIGHMEM...
Starting with b46e09667411 ("fuse: enable large folios")
fuse_dev_splice_read() hands out large page cache folios and
kmap_local_page() only maps the first page.
So a fuse server on a 32-bit HIGHMEM guest that splices a WRITE request
into a virtio port crashes mainline:
BUG: unable to handle page fault for address: fffab000
#PF: supervisor read access in kernel mode
#PF: error_code(0x0000) - not-present page
EIP: pipe_to_sg+0x184/0x2b0
Call Trace:
__splice_from_pipe+0xd6/0x1f0
port_fops_splice_write+0xf9/0x170
do_splice+0x2c1/0x810
__ia32_sys_splice+0x2e7/0x310
So we need to copy per page which would fix both.