[RH7] vhost/net: don't read and process iotlb message with bad lenth

Submitted by Pavel Tikhomirov on Dec. 13, 2018, 8:28 a.m.

Details

Message ID 20181213082823.13464-1-ptikhomirov@virtuozzo.com
State New
Series "vhost/net: don't read and process iotlb message with bad lenth"
Headers show

Commit Message

Pavel Tikhomirov Dec. 13, 2018, 8:28 a.m.
Resend as first one missed the list.

On kernel vz7.73.18+ we had a stack:

Patch hide | download patch | download mbox

==================================================================
BUG: KASan: out of bounds on stack in memcpy_fromiovecend net/core/iovec.c:142 [inline] at addr ffff88000413fcd0
BUG: KASan: out of bounds on stack in memcpy_fromiovecend+0x18c/0x1c0 net/core/iovec.c:128 at addr ffff88000413fcd0
Read of size 8 by task syz-executor/757712
page:ffffea0000104fc0 count:0 mapcount:0 mapping:          (null) index:0x0
page flags: 0x1fffff00000000()
page dumped because: kasan: bad access detected
CPU: 1 PID: 757712 Comm: syz-executor ve: 0 Kdump: loaded Not tainted 3.10.0-862.20.2.ovz.73.18 #95 73.18
Hardware name: Virtuozzo KVM, BIOS rel-1.10.2-0-g5f4c7b1-prebuilt.qemu-project.org 04/01/2014
Call Trace:
 [<ffffffff893d44b9>] dump_stack+0x1e/0x20 lib/dump_stack.c:18
 [<ffffffff893c6fec>] print_address_description mm/kasan/report.c:188 [inline]
 [<ffffffff893c6fec>] kasan_report_error mm/kasan/report.c:263 [inline]
 [<ffffffff893c6fec>] kasan_report.cold+0x26e/0x3d6 mm/kasan/report.c:297
 [<ffffffff88281a39>] __asan_report_load8_noabort+0x19/0x20 mm/kasan/report.c:318
 [<ffffffff88f20bcc>] memcpy_fromiovecend net/core/iovec.c:142 [inline]
 [<ffffffff88f20bcc>] memcpy_fromiovecend+0x18c/0x1c0 net/core/iovec.c:128
 [<ffffffffc189eee0>] vhost_chr_write_iter+0x90/0xf50 [vhost]
 [<ffffffffc18b8d27>] vhost_net_aio_write+0xd7/0x120 [vhost_net]
 [<ffffffff882f3d0c>] do_sync_write+0x17c/0x270 fs/read_write.c:493
 [<ffffffff882f62ff>] vfs_write+0x4bf/0x630 fs/read_write.c:547
 [<ffffffff882f9065>] SYSC_write fs/read_write.c:594 [inline]
 [<ffffffff882f9065>] SyS_write+0x185/0x380 fs/read_write.c:586
 [<ffffffff894329db>] system_call_fastpath+0x22/0x27
Memory state around the buggy address:
 ffff88000413fb80: 00 00 00 00 00 00 00 00 00 f3 f3 f3 f3 00 00 00
 ffff88000413fc00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
>ffff88000413fc80: 00 00 f1 f1 f1 f1 f1 f1 00 00 f2 f2 00 00 00 00
                                                 ^
 ffff88000413fd00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 ffff88000413fd80: 00 00 f3 f3 f3 f3 f3 f3 f3 f3 00 00 00 00 00 00
==================================================================

The syzcaller process likely was 32-bit, that means it has vhost_msg -
sizeof(struct vhost_msg) == 0x44, but 64-bit kernel expects to see
sizeof(struct vhost_msg) == 0x48 because of 4 byte hole for alignment.
Thus len in memcpy_fromiovecend is 0x48 but there is only 0x44 bytes in
iov, and we do iov++ moving to next iovec (which does not exist) and
acces iov->iov_base out of bounds at net/core/iovec.c:142.

I think that commit 429711aec282 ("vhost: switch to use new message
format") fixes the problem only if VHOST_BACKEND_F_IOTLB_V2 is enabled
on vhost device and if also syzcaller uses new vhost_msg_v2 type,
I doubt that it is so now, as vhost_msg_v2 feature is only 5 months old.
For old vhost_msg path nothing is changed AFAICS and we will still fail.

MS kernel is not affected as they use copy_from_iter() instead of
memcpy_fromiovecend() and it does not allow reading more data than
given by iovecs.

So lets silently return if iovecs len is less than vhost_msg, ms does
effectively the same in vhost_chr_write_iter.

https://jira.sw.ru/browse/PSBM-90291
Signed-off-by: Pavel Tikhomirov <ptikhomirov@virtuozzo.com>
---
 drivers/vhost/net.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c
index ee3477aaf71b..c3010a82dfa1 100644
--- a/drivers/vhost/net.c
+++ b/drivers/vhost/net.c
@@ -1305,6 +1305,9 @@  static ssize_t vhost_net_aio_write(struct kiocb *iocb,
 	if (len < 0)
 		return -EINVAL;
 
+	if (len < sizeof(struct vhost_msg))
+		return len;
+
 	return vhost_chr_write_iter(dev, from);
 }