SECURITY: CVE-2015-5278, CVE-2015-5279, CVE-2015-6815
Some more fixes, mostly security related. from Brad (maintainer)
This commit is contained in:
parent
748fa28250
commit
15b06e762f
@ -1,11 +1,11 @@
|
||||
# $OpenBSD: Makefile,v 1.131 2015/09/16 07:08:41 ajacoutot Exp $
|
||||
# $OpenBSD: Makefile,v 1.132 2015/09/16 09:18:13 ajacoutot Exp $
|
||||
|
||||
ONLY_FOR_ARCHS= amd64 i386 powerpc sparc64
|
||||
|
||||
COMMENT= multi system emulator
|
||||
|
||||
DISTNAME= qemu-2.2.1
|
||||
REVISION= 7
|
||||
REVISION= 8
|
||||
CATEGORIES= emulators
|
||||
MASTER_SITES= http://wiki.qemu.org/download/
|
||||
EXTRACT_SUFX= .tar.bz2
|
||||
|
35
emulators/qemu/patches/patch-block_vmdk_c
Normal file
35
emulators/qemu/patches/patch-block_vmdk_c
Normal file
@ -0,0 +1,35 @@
|
||||
$OpenBSD: patch-block_vmdk_c,v 1.1 2015/09/16 09:18:13 ajacoutot Exp $
|
||||
|
||||
vmdk: Fix overflow if l1_size is 0x20000000
|
||||
|
||||
Richard Jones caught this bug with afl fuzzer.
|
||||
|
||||
In fact, that's the only possible value to overflow (extent->l1_size =
|
||||
0x20000000) l1_size:
|
||||
|
||||
l1_size = extent->l1_size * sizeof(long) => 0x80000000;
|
||||
|
||||
g_try_malloc returns NULL because l1_size is interpreted as negative
|
||||
during type casting from 'int' to 'gsize', which yields a enormous
|
||||
value. Hence, by coincidence, we get a "not too bad" behavior:
|
||||
|
||||
qemu-img: Could not open '/tmp/afl6.img': Could not open
|
||||
'/tmp/afl6.img': Cannot allocate memory
|
||||
|
||||
Values larger than 0x20000000 will be refused by the validation in
|
||||
vmdk_add_extent.
|
||||
|
||||
Values smaller than 0x20000000 will not overflow l1_size.
|
||||
|
||||
--- block/vmdk.c.orig Wed Sep 16 03:46:16 2015
|
||||
+++ block/vmdk.c Wed Sep 16 03:46:53 2015
|
||||
@@ -450,7 +450,8 @@ static int vmdk_init_tables(BlockDriverState *bs, Vmdk
|
||||
Error **errp)
|
||||
{
|
||||
int ret;
|
||||
- int l1_size, i;
|
||||
+ size_t l1_size;
|
||||
+ int i;
|
||||
|
||||
/* read the L1 table */
|
||||
l1_size = extent->l1_size * sizeof(uint32_t);
|
69
emulators/qemu/patches/patch-block_vpc_c
Normal file
69
emulators/qemu/patches/patch-block_vpc_c
Normal file
@ -0,0 +1,69 @@
|
||||
$OpenBSD: patch-block_vpc_c,v 1.1 2015/09/16 09:18:13 ajacoutot Exp $
|
||||
|
||||
block: vpc - prevent overflow if max_table_entries >= 0x40000000
|
||||
|
||||
When we allocate the pagetable based on max_table_entries, we multiply
|
||||
the max table entry value by 4 to accomodate a table of 32-bit integers.
|
||||
However, max_table_entries is a uint32_t, and the VPC driver accepts
|
||||
ranges for that entry over 0x40000000. So during this allocation:
|
||||
|
||||
s->pagetable = qemu_try_blockalign(bs->file, s->max_table_entries * 4);
|
||||
|
||||
The size arg overflows, allocating significantly less memory than
|
||||
expected.
|
||||
|
||||
Since qemu_try_blockalign() size argument is size_t, cast the
|
||||
multiplication correctly to prevent overflow.
|
||||
|
||||
The value of "max_table_entries * 4" is used elsewhere in the code as
|
||||
well, so store the correct value for use in all those cases.
|
||||
|
||||
We also check the Max Tables Entries value, to make sure that it is <
|
||||
SIZE_MAX / 4, so we know the pagetable size will fit in size_t.
|
||||
|
||||
--- block/vpc.c.orig Wed Sep 16 03:08:08 2015
|
||||
+++ block/vpc.c Wed Sep 16 03:11:21 2015
|
||||
@@ -167,6 +167,7 @@ static int vpc_open(BlockDriverState *bs, QDict *optio
|
||||
uint8_t buf[HEADER_SIZE];
|
||||
uint32_t checksum;
|
||||
uint64_t computed_size;
|
||||
+ uint64_t pagetable_size;
|
||||
int disk_type = VHD_DYNAMIC;
|
||||
int ret;
|
||||
|
||||
@@ -269,7 +270,17 @@ static int vpc_open(BlockDriverState *bs, QDict *optio
|
||||
goto fail;
|
||||
}
|
||||
|
||||
- s->pagetable = qemu_try_blockalign(bs->file, s->max_table_entries * 4);
|
||||
+ if (s->max_table_entries > SIZE_MAX / 4 ||
|
||||
+ s->max_table_entries > (int) INT_MAX / 4) {
|
||||
+ error_setg(errp, "Max Table Entries too large (%" PRId32 ")",
|
||||
+ s->max_table_entries);
|
||||
+ ret = -EINVAL;
|
||||
+ goto fail;
|
||||
+ }
|
||||
+
|
||||
+ pagetable_size = (uint64_t) s->max_table_entries * 4;
|
||||
+
|
||||
+ s->pagetable = qemu_try_blockalign(bs->file, pagetable_size);
|
||||
if (s->pagetable == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto fail;
|
||||
@@ -277,14 +288,13 @@ static int vpc_open(BlockDriverState *bs, QDict *optio
|
||||
|
||||
s->bat_offset = be64_to_cpu(dyndisk_header->table_offset);
|
||||
|
||||
- ret = bdrv_pread(bs->file, s->bat_offset, s->pagetable,
|
||||
- s->max_table_entries * 4);
|
||||
+ ret = bdrv_pread(bs->file, s->bat_offset, s->pagetable, pagetable_size);
|
||||
if (ret < 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
s->free_data_block_offset =
|
||||
- (s->bat_offset + (s->max_table_entries * 4) + 511) & ~511;
|
||||
+ ROUND_UP(s->bat_offset + pagetable_size, 512);
|
||||
|
||||
for (i = 0; i < s->max_table_entries; i++) {
|
||||
be32_to_cpus(&s->pagetable[i]);
|
22
emulators/qemu/patches/patch-hw_net_e1000_c
Normal file
22
emulators/qemu/patches/patch-hw_net_e1000_c
Normal file
@ -0,0 +1,22 @@
|
||||
$OpenBSD: patch-hw_net_e1000_c,v 1.1 2015/09/16 09:18:13 ajacoutot Exp $
|
||||
|
||||
e1000: Avoid infinite loop in processing transmit descriptor (CVE-2015-6815)
|
||||
|
||||
While processing transmit descriptors, it could lead to an infinite
|
||||
loop if 'bytes' was to become zero; Add a check to avoid it.
|
||||
|
||||
[The guest can force 'bytes' to 0 by setting the hdr_len and mss
|
||||
descriptor fields to 0.
|
||||
|
||||
--- hw/net/e1000.c.orig Wed Sep 16 03:27:05 2015
|
||||
+++ hw/net/e1000.c Wed Sep 16 03:28:19 2015
|
||||
@@ -736,7 +736,8 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *d
|
||||
memmove(tp->data, tp->header, tp->hdr_len);
|
||||
tp->size = tp->hdr_len;
|
||||
}
|
||||
- } while (split_size -= bytes);
|
||||
+ split_size -= bytes;
|
||||
+ } while (bytes && split_size);
|
||||
} else if (!tp->tse && tp->cptse) {
|
||||
// context descriptor TSE is not set, while data descriptor TSE is set
|
||||
DBGOUT(TXERR, "TCP segmentation error\n");
|
73
emulators/qemu/patches/patch-hw_net_ne2000_c
Normal file
73
emulators/qemu/patches/patch-hw_net_ne2000_c
Normal file
@ -0,0 +1,73 @@
|
||||
$OpenBSD: patch-hw_net_ne2000_c,v 1.1 2015/09/16 09:18:13 ajacoutot Exp $
|
||||
|
||||
net: add checks to validate ring buffer pointers(CVE-2015-5279)
|
||||
|
||||
Ne2000 NIC uses ring buffer of NE2000_MEM_SIZE(49152)
|
||||
bytes to process network packets. While receiving packets
|
||||
via ne2000_receive() routine, a local 'index' variable
|
||||
could exceed the ring buffer size, which could lead to a
|
||||
memory buffer overflow. Added other checks at initialisation.
|
||||
|
||||
net: avoid infinite loop when receiving packets(CVE-2015-5278)
|
||||
|
||||
Ne2000 NIC uses ring buffer of NE2000_MEM_SIZE(49152)
|
||||
bytes to process network packets. While receiving packets
|
||||
via ne2000_receive() routine, a local 'index' variable
|
||||
could exceed the ring buffer size, leading to an infinite
|
||||
loop situation.
|
||||
|
||||
--- hw/net/ne2000.c.orig Wed Sep 16 03:30:14 2015
|
||||
+++ hw/net/ne2000.c Wed Sep 16 03:35:01 2015
|
||||
@@ -230,6 +230,9 @@ ssize_t ne2000_receive(NetClientState *nc, const uint8
|
||||
}
|
||||
|
||||
index = s->curpag << 8;
|
||||
+ if (index >= NE2000_PMEM_END) {
|
||||
+ index = s->start;
|
||||
+ }
|
||||
/* 4 bytes for header */
|
||||
total_len = size + 4;
|
||||
/* address for next packet (4 bytes for CRC) */
|
||||
@@ -253,7 +256,7 @@ ssize_t ne2000_receive(NetClientState *nc, const uint8
|
||||
if (index <= s->stop)
|
||||
avail = s->stop - index;
|
||||
else
|
||||
- avail = 0;
|
||||
+ break;
|
||||
len = size;
|
||||
if (len > avail)
|
||||
len = avail;
|
||||
@@ -315,13 +318,19 @@ static void ne2000_ioport_write(void *opaque, uint32_t
|
||||
offset = addr | (page << 4);
|
||||
switch(offset) {
|
||||
case EN0_STARTPG:
|
||||
- s->start = val << 8;
|
||||
+ if (val << 8 <= NE2000_PMEM_END) {
|
||||
+ s->start = val << 8;
|
||||
+ }
|
||||
break;
|
||||
case EN0_STOPPG:
|
||||
- s->stop = val << 8;
|
||||
+ if (val << 8 <= NE2000_PMEM_END) {
|
||||
+ s->stop = val << 8;
|
||||
+ }
|
||||
break;
|
||||
case EN0_BOUNDARY:
|
||||
- s->boundary = val;
|
||||
+ if (val << 8 < NE2000_PMEM_END) {
|
||||
+ s->boundary = val;
|
||||
+ }
|
||||
break;
|
||||
case EN0_IMR:
|
||||
s->imr = val;
|
||||
@@ -362,7 +371,9 @@ static void ne2000_ioport_write(void *opaque, uint32_t
|
||||
s->phys[offset - EN1_PHYS] = val;
|
||||
break;
|
||||
case EN1_CURPAG:
|
||||
- s->curpag = val;
|
||||
+ if (val << 8 < NE2000_PMEM_END) {
|
||||
+ s->curpag = val;
|
||||
+ }
|
||||
break;
|
||||
case EN1_MULT ... EN1_MULT + 7:
|
||||
s->mult[offset - EN1_MULT] = val;
|
63
emulators/qemu/patches/patch-hw_net_virtio-net_c
Normal file
63
emulators/qemu/patches/patch-hw_net_virtio-net_c
Normal file
@ -0,0 +1,63 @@
|
||||
$OpenBSD: patch-hw_net_virtio-net_c,v 1.1 2015/09/16 09:18:13 ajacoutot Exp $
|
||||
|
||||
virtio-net: unbreak any layout
|
||||
|
||||
Commit 032a74a1c0fcdd5fd1c69e56126b4c857ee36611
|
||||
("virtio-net: byteswap virtio-net header") breaks any layout by
|
||||
requiring out_sg[0].iov_len >= n->guest_hdr_len. Fixing this by
|
||||
copying header to temporary buffer if swap is needed, and then use
|
||||
this buffer as part of out_sg.
|
||||
|
||||
Fixes 032a74a1c0fcdd5fd1c69e56126b4c857ee36611
|
||||
("virtio-net: byteswap virtio-net header")
|
||||
|
||||
--- hw/net/virtio-net.c.orig Wed Sep 16 03:14:46 2015
|
||||
+++ hw/net/virtio-net.c Wed Sep 16 03:17:00 2015
|
||||
@@ -1135,7 +1135,8 @@ static int32_t virtio_net_flush_tx(VirtIONetQueue *q)
|
||||
ssize_t ret, len;
|
||||
unsigned int out_num = elem.out_num;
|
||||
struct iovec *out_sg = &elem.out_sg[0];
|
||||
- struct iovec sg[VIRTQUEUE_MAX_SIZE];
|
||||
+ struct iovec sg[VIRTQUEUE_MAX_SIZE], sg2[VIRTQUEUE_MAX_SIZE + 1];
|
||||
+ struct virtio_net_hdr_mrg_rxbuf mhdr;
|
||||
|
||||
if (out_num < 1) {
|
||||
error_report("virtio-net header not in first element");
|
||||
@@ -1143,13 +1144,25 @@ static int32_t virtio_net_flush_tx(VirtIONetQueue *q)
|
||||
}
|
||||
|
||||
if (n->has_vnet_hdr) {
|
||||
- if (out_sg[0].iov_len < n->guest_hdr_len) {
|
||||
+ if (iov_to_buf(out_sg, out_num, 0, &mhdr, n->guest_hdr_len) <
|
||||
+ n->guest_hdr_len) {
|
||||
error_report("virtio-net header incorrect");
|
||||
exit(1);
|
||||
}
|
||||
- virtio_net_hdr_swap(vdev, (void *) out_sg[0].iov_base);
|
||||
+ if (virtio_needs_swap(vdev)) {
|
||||
+ virtio_net_hdr_swap(vdev, (void *) &mhdr);
|
||||
+ sg2[0].iov_base = &mhdr;
|
||||
+ sg2[0].iov_len = n->guest_hdr_len;
|
||||
+ out_num = iov_copy(&sg2[1], ARRAY_SIZE(sg2) - 1,
|
||||
+ out_sg, out_num,
|
||||
+ n->guest_hdr_len, -1);
|
||||
+ if (out_num == VIRTQUEUE_MAX_SIZE) {
|
||||
+ goto drop;
|
||||
+ }
|
||||
+ out_num += 1;
|
||||
+ out_sg = sg2;
|
||||
+ }
|
||||
}
|
||||
-
|
||||
/*
|
||||
* If host wants to see the guest header as is, we can
|
||||
* pass it on unchanged. Otherwise, copy just the parts
|
||||
@@ -1179,7 +1192,7 @@ static int32_t virtio_net_flush_tx(VirtIONetQueue *q)
|
||||
}
|
||||
|
||||
len += ret;
|
||||
-
|
||||
+drop:
|
||||
virtqueue_push(q->tx_vq, &elem, 0);
|
||||
virtio_notify(vdev, q->tx_vq);
|
||||
|
@ -0,0 +1,31 @@
|
||||
$OpenBSD: patch-include_hw_virtio_virtio-access_h,v 1.1 2015/09/16 09:18:13 ajacoutot Exp $
|
||||
|
||||
virtio-net: unbreak any layout
|
||||
|
||||
Commit 032a74a1c0fcdd5fd1c69e56126b4c857ee36611
|
||||
("virtio-net: byteswap virtio-net header") breaks any layout by
|
||||
requiring out_sg[0].iov_len >= n->guest_hdr_len. Fixing this by
|
||||
copying header to temporary buffer if swap is needed, and then use
|
||||
this buffer as part of out_sg.
|
||||
|
||||
Fixes 032a74a1c0fcdd5fd1c69e56126b4c857ee36611
|
||||
("virtio-net: byteswap virtio-net header")
|
||||
|
||||
--- include/hw/virtio/virtio-access.h.orig Wed Sep 16 03:17:28 2015
|
||||
+++ include/hw/virtio/virtio-access.h Wed Sep 16 03:18:03 2015
|
||||
@@ -126,6 +126,15 @@ static inline uint64_t virtio_ldq_p(VirtIODevice *vdev
|
||||
}
|
||||
}
|
||||
|
||||
+static inline bool virtio_needs_swap(VirtIODevice *vdev)
|
||||
+{
|
||||
+#ifdef HOST_WORDS_BIGENDIAN
|
||||
+ return virtio_access_is_big_endian(vdev) ? false : true;
|
||||
+#else
|
||||
+ return virtio_access_is_big_endian(vdev) ? true : false;
|
||||
+#endif
|
||||
+}
|
||||
+
|
||||
static inline uint16_t virtio_tswap16(VirtIODevice *vdev, uint16_t s)
|
||||
{
|
||||
#ifdef HOST_WORDS_BIGENDIAN
|
Loading…
Reference in New Issue
Block a user