summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorMichael S. Tsirkin <mst@redhat.com>2016-08-01 23:20:53 +0300
committerMichael S. Tsirkin <mst@redhat.com>2016-08-02 16:54:28 +0300
commitec33d031a14b3c5dd516627139c9550350dbba3e (patch)
tree7f8913c2a0b5524836f31385f0a879e1ec6ed7ce /drivers
parent6b1e6cc7855b09a0a9bfa1d9f30172ba366f161c (diff)
downloadlinux-ec33d031a14b3c5dd516627139c9550350dbba3e.tar.gz
linux-ec33d031a14b3c5dd516627139c9550350dbba3e.tar.bz2
linux-ec33d031a14b3c5dd516627139c9550350dbba3e.zip
vhost: detect 32 bit integer wrap around
Detect and fail early if long wrap around is triggered. Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/vhost/vhost.c16
1 files changed, 14 insertions, 2 deletions
diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c
index d02c1614921f..c6f2d89c0e97 100644
--- a/drivers/vhost/vhost.c
+++ b/drivers/vhost/vhost.c
@@ -657,6 +657,12 @@ static int log_access_ok(void __user *log_base, u64 addr, unsigned long sz)
(sz + VHOST_PAGE_SIZE * 8 - 1) / VHOST_PAGE_SIZE / 8);
}
+static bool vhost_overflow(u64 uaddr, u64 size)
+{
+ /* Make sure 64 bit math will not overflow. */
+ return uaddr > ULONG_MAX || size > ULONG_MAX || uaddr > ULONG_MAX - size;
+}
+
/* Caller should have vq mutex and device mutex. */
static int vq_memory_access_ok(void __user *log_base, struct vhost_umem *umem,
int log_all)
@@ -669,9 +675,11 @@ static int vq_memory_access_ok(void __user *log_base, struct vhost_umem *umem,
list_for_each_entry(node, &umem->umem_list, link) {
unsigned long a = node->userspace_addr;
- if (node->size > ULONG_MAX)
+ if (vhost_overflow(node->userspace_addr, node->size))
return 0;
- else if (!access_ok(VERIFY_WRITE, (void __user *)a,
+
+
+ if (!access_ok(VERIFY_WRITE, (void __user *)a,
node->size))
return 0;
else if (log_all && !log_access_ok(log_base,
@@ -913,6 +921,10 @@ static int umem_access_ok(u64 uaddr, u64 size, int access)
{
unsigned long a = uaddr;
+ /* Make sure 64 bit math will not overflow. */
+ if (vhost_overflow(uaddr, size))
+ return -EFAULT;
+
if ((access & VHOST_ACCESS_RO) &&
!access_ok(VERIFY_READ, (void __user *)a, size))
return -EFAULT;