bump version to 2.11.1-1
Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>master
parent
db442fc8d3
commit
6838f03890
19
Makefile
19
Makefile
|
@ -1,6 +1,6 @@
|
|||
# also update debian/changelog
|
||||
KVMVER=2.9.1
|
||||
KVMPKGREL=9
|
||||
KVMVER=2.11.1
|
||||
KVMPKGREL=1
|
||||
|
||||
KVMPACKAGE = pve-qemu-kvm
|
||||
KVMSRC = qemu
|
||||
|
@ -25,18 +25,31 @@ submodule:
|
|||
.PHONY: deb kvm
|
||||
deb kvm: $(DEBS)
|
||||
$(DEB_DBG): $(DEB)
|
||||
$(DEB): | submodule
|
||||
$(DEB): keycodemapdb | submodule
|
||||
rm -f *.deb
|
||||
rm -rf $(BUILDSRC)
|
||||
mkdir $(BUILDSRC)
|
||||
cp -a $(KVMSRC)/* $(BUILDSRC)/
|
||||
cp -a debian $(BUILDSRC)/debian
|
||||
rm -rf $(BUILDSRC)/ui/keycodemapdb
|
||||
cp -a keycodemapdb $(BUILDSRC)/ui/
|
||||
echo "git clone git://git.proxmox.com/git/pve-qemu-kvm.git\\ngit checkout $(GITVERSION)" > $(BUILDSRC)/debian/SOURCE
|
||||
# set package version
|
||||
sed -i 's/^pkgversion="".*/pkgversion="${KVMPACKAGE}_${KVMVER}-${KVMPKGREL}"/' $(BUILDSRC)/configure
|
||||
cd $(BUILDSRC); dpkg-buildpackage -b -rfakeroot -us -uc
|
||||
lintian $(DEBS) || true
|
||||
|
||||
.PHONY: update
|
||||
update:
|
||||
cd $(KVMSRC) && git submodule deinit ui/keycodemapdb || true
|
||||
rm -rf $(KVMSRC)/ui/keycodemapdb
|
||||
mkdir $(KVMSRC)/ui/keycodemapdb
|
||||
cd $(KVMSRC) && git submodule update --init ui/keycodemapdb
|
||||
rm -rf keycodemapdb
|
||||
mkdir keycodemapdb
|
||||
cp -R $(KVMSRC)/ui/keycodemapdb/* keycodemapdb/
|
||||
git add keycodemapdb
|
||||
|
||||
.PHONY: upload
|
||||
upload: $(DEBS)
|
||||
tar cf - ${DEBS} | ssh repoman@repo.proxmox.com upload --product pve --dist stretch
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
pve-qemu-kvm (2.11.1-1) stable; urgency=medium
|
||||
|
||||
* update to 2.11.1
|
||||
|
||||
-- Proxmox Support Team <support@proxmox.com> Thu, 22 Feb 2018 12:34:43 +0100
|
||||
|
||||
pve-qemu-kvm (2.9.1-9) stable; urgency=medium
|
||||
|
||||
* add EPYC and EPYC-IPBP cpu models
|
||||
|
|
|
@ -9,7 +9,7 @@ This reverts commit b8eb5512fd8a115f164edbbe897cdf8884920ccb.
|
|||
1 file changed, 9 insertions(+)
|
||||
|
||||
diff --git a/hw/intc/apic_common.c b/hw/intc/apic_common.c
|
||||
index 1ef56f8d10..31fb73e9fb 100644
|
||||
index 78903ea909..cdfbec5e47 100644
|
||||
--- a/hw/intc/apic_common.c
|
||||
+++ b/hw/intc/apic_common.c
|
||||
@@ -257,6 +257,15 @@ static void apic_reset_common(DeviceState *dev)
|
||||
|
|
|
@ -13,10 +13,10 @@ Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
|
|||
1 file changed, 5 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/include/qemu/ratelimit.h b/include/qemu/ratelimit.h
|
||||
index 8da1232574..324ff04fe2 100644
|
||||
index 8dece483f5..1b38291823 100644
|
||||
--- a/include/qemu/ratelimit.h
|
||||
+++ b/include/qemu/ratelimit.h
|
||||
@@ -35,7 +35,7 @@ typedef struct {
|
||||
@@ -36,7 +36,7 @@ typedef struct {
|
||||
static inline int64_t ratelimit_calculate_delay(RateLimit *limit, uint64_t n)
|
||||
{
|
||||
int64_t now = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
|
||||
|
@ -25,7 +25,7 @@ index 8da1232574..324ff04fe2 100644
|
|||
|
||||
assert(limit->slice_quota && limit->slice_ns);
|
||||
|
||||
@@ -54,12 +54,11 @@ static inline int64_t ratelimit_calculate_delay(RateLimit *limit, uint64_t n)
|
||||
@@ -55,12 +55,11 @@ static inline int64_t ratelimit_calculate_delay(RateLimit *limit, uint64_t n)
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,74 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
Date: Fri, 2 Jun 2017 10:54:24 +0100
|
||||
Subject: [PATCH] virtio-serial: fix segfault on disconnect
|
||||
|
||||
Since commit d4c19cdeeb2f1e474bc426a6da261f1d7346eb5b ("virtio-serial:
|
||||
add missing virtio_detach_element() call") the following commands may
|
||||
cause QEMU to segfault:
|
||||
|
||||
$ qemu -M accel=kvm -cpu host -m 1G \
|
||||
-drive if=virtio,file=test.img,format=raw \
|
||||
-device virtio-serial-pci,id=virtio-serial0 \
|
||||
-chardev socket,id=channel1,path=/tmp/chardev.sock,server,nowait \
|
||||
-device virtserialport,chardev=channel1,bus=virtio-serial0.0,id=port1
|
||||
$ nc -U /tmp/chardev.sock
|
||||
^C
|
||||
|
||||
(guest)$ cat /dev/zero >/dev/vport0p1
|
||||
|
||||
The segfault is non-deterministic: if the event loop notices the socket
|
||||
has been closed then there is no crash. The disconnect has to happen
|
||||
right before QEMU attempts to write data to the socket.
|
||||
|
||||
The backtrace is as follows:
|
||||
|
||||
Thread 1 "qemu-system-x86" received signal SIGSEGV, Segmentation fault.
|
||||
0x00005555557e0698 in do_flush_queued_data (port=0x5555582cedf0, vq=0x7fffcc854290, vdev=0x55555807b1d0) at hw/char/virtio-serial-bus.c:180
|
||||
180 for (i = port->iov_idx; i < port->elem->out_num; i++) {
|
||||
#1 0x000055555580d363 in virtio_queue_notify_vq (vq=0x7fffcc854290) at hw/virtio/virtio.c:1524
|
||||
#2 0x000055555580d363 in virtio_queue_host_notifier_read (n=0x7fffcc8542f8) at hw/virtio/virtio.c:2430
|
||||
#3 0x0000555555b3482c in aio_dispatch_handlers (ctx=ctx@entry=0x5555566b8c80) at util/aio-posix.c:399
|
||||
#4 0x0000555555b350d8 in aio_dispatch (ctx=0x5555566b8c80) at util/aio-posix.c:430
|
||||
#5 0x0000555555b3212e in aio_ctx_dispatch (source=<optimized out>, callback=<optimized out>, user_data=<optimized out>) at util/async.c:261
|
||||
#6 0x00007fffde71de52 in g_main_context_dispatch () at /lib64/libglib-2.0.so.0
|
||||
#7 0x0000555555b34353 in glib_pollfds_poll () at util/main-loop.c:213
|
||||
#8 0x0000555555b34353 in os_host_main_loop_wait (timeout=<optimized out>) at util/main-loop.c:261
|
||||
#9 0x0000555555b34353 in main_loop_wait (nonblocking=<optimized out>) at util/main-loop.c:517
|
||||
#10 0x0000555555773207 in main_loop () at vl.c:1917
|
||||
#11 0x0000555555773207 in main (argc=<optimized out>, argv=<optimized out>, envp=<optimized out>) at vl.c:4751
|
||||
|
||||
The do_flush_queued_data() function does not anticipate chardev close
|
||||
events during vsc->have_data(). It expects port->elem to remain
|
||||
non-NULL for the duration its for loop.
|
||||
|
||||
The fix is simply to return from do_flush_queued_data() if the port
|
||||
closes because the close event already frees port->elem and drains the
|
||||
virtqueue - there is nothing left for do_flush_queued_data() to do.
|
||||
|
||||
Reported-by: Sitong Liu <siliu@redhat.com>
|
||||
Reported-by: Min Deng <mdeng@redhat.com>
|
||||
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
|
||||
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
|
||||
---
|
||||
hw/char/virtio-serial-bus.c | 3 +++
|
||||
1 file changed, 3 insertions(+)
|
||||
|
||||
diff --git a/hw/char/virtio-serial-bus.c b/hw/char/virtio-serial-bus.c
|
||||
index aa9c11ae92..f5bc173844 100644
|
||||
--- a/hw/char/virtio-serial-bus.c
|
||||
+++ b/hw/char/virtio-serial-bus.c
|
||||
@@ -186,6 +186,9 @@ static void do_flush_queued_data(VirtIOSerialPort *port, VirtQueue *vq,
|
||||
port->elem->out_sg[i].iov_base
|
||||
+ port->iov_offset,
|
||||
buf_size);
|
||||
+ if (!port->elem) { /* bail if we got disconnected */
|
||||
+ return;
|
||||
+ }
|
||||
if (port->throttled) {
|
||||
port->iov_idx = i;
|
||||
if (ret > 0) {
|
||||
--
|
||||
2.11.0
|
||||
|
|
@ -1,125 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Paolo Bonzini <pbonzini@redhat.com>
|
||||
Date: Thu, 1 Jun 2017 17:26:14 +0200
|
||||
Subject: [PATCH] megasas: always store SCSIRequest* into MegasasCmd
|
||||
|
||||
This ensures that the request is unref'ed properly, and avoids a
|
||||
segmentation fault in the new qtest testcase that is added.
|
||||
This is CVE-2017-9503.
|
||||
|
||||
Reported-by: Zhangyanyu <zyy4013@stu.ouc.edu.cn>
|
||||
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
|
||||
---
|
||||
hw/scsi/megasas.c | 31 ++++++++++++++++---------------
|
||||
1 file changed, 16 insertions(+), 15 deletions(-)
|
||||
|
||||
diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c
|
||||
index 135662df31..734fdaef90 100644
|
||||
--- a/hw/scsi/megasas.c
|
||||
+++ b/hw/scsi/megasas.c
|
||||
@@ -609,6 +609,9 @@ static void megasas_reset_frames(MegasasState *s)
|
||||
static void megasas_abort_command(MegasasCmd *cmd)
|
||||
{
|
||||
/* Never abort internal commands. */
|
||||
+ if (cmd->dcmd_opcode != -1) {
|
||||
+ return;
|
||||
+ }
|
||||
if (cmd->req != NULL) {
|
||||
scsi_req_cancel(cmd->req);
|
||||
}
|
||||
@@ -1017,7 +1020,6 @@ static int megasas_pd_get_info_submit(SCSIDevice *sdev, int lun,
|
||||
uint64_t pd_size;
|
||||
uint16_t pd_id = ((sdev->id & 0xFF) << 8) | (lun & 0xFF);
|
||||
uint8_t cmdbuf[6];
|
||||
- SCSIRequest *req;
|
||||
size_t len, resid;
|
||||
|
||||
if (!cmd->iov_buf) {
|
||||
@@ -1026,8 +1028,8 @@ static int megasas_pd_get_info_submit(SCSIDevice *sdev, int lun,
|
||||
info->inquiry_data[0] = 0x7f; /* Force PQual 0x3, PType 0x1f */
|
||||
info->vpd_page83[0] = 0x7f;
|
||||
megasas_setup_inquiry(cmdbuf, 0, sizeof(info->inquiry_data));
|
||||
- req = scsi_req_new(sdev, cmd->index, lun, cmdbuf, cmd);
|
||||
- if (!req) {
|
||||
+ cmd->req = scsi_req_new(sdev, cmd->index, lun, cmdbuf, cmd);
|
||||
+ if (!cmd->req) {
|
||||
trace_megasas_dcmd_req_alloc_failed(cmd->index,
|
||||
"PD get info std inquiry");
|
||||
g_free(cmd->iov_buf);
|
||||
@@ -1036,26 +1038,26 @@ static int megasas_pd_get_info_submit(SCSIDevice *sdev, int lun,
|
||||
}
|
||||
trace_megasas_dcmd_internal_submit(cmd->index,
|
||||
"PD get info std inquiry", lun);
|
||||
- len = scsi_req_enqueue(req);
|
||||
+ len = scsi_req_enqueue(cmd->req);
|
||||
if (len > 0) {
|
||||
cmd->iov_size = len;
|
||||
- scsi_req_continue(req);
|
||||
+ scsi_req_continue(cmd->req);
|
||||
}
|
||||
return MFI_STAT_INVALID_STATUS;
|
||||
} else if (info->inquiry_data[0] != 0x7f && info->vpd_page83[0] == 0x7f) {
|
||||
megasas_setup_inquiry(cmdbuf, 0x83, sizeof(info->vpd_page83));
|
||||
- req = scsi_req_new(sdev, cmd->index, lun, cmdbuf, cmd);
|
||||
- if (!req) {
|
||||
+ cmd->req = scsi_req_new(sdev, cmd->index, lun, cmdbuf, cmd);
|
||||
+ if (!cmd->req) {
|
||||
trace_megasas_dcmd_req_alloc_failed(cmd->index,
|
||||
"PD get info vpd inquiry");
|
||||
return MFI_STAT_FLASH_ALLOC_FAIL;
|
||||
}
|
||||
trace_megasas_dcmd_internal_submit(cmd->index,
|
||||
"PD get info vpd inquiry", lun);
|
||||
- len = scsi_req_enqueue(req);
|
||||
+ len = scsi_req_enqueue(cmd->req);
|
||||
if (len > 0) {
|
||||
cmd->iov_size = len;
|
||||
- scsi_req_continue(req);
|
||||
+ scsi_req_continue(cmd->req);
|
||||
}
|
||||
return MFI_STAT_INVALID_STATUS;
|
||||
}
|
||||
@@ -1217,7 +1219,6 @@ static int megasas_ld_get_info_submit(SCSIDevice *sdev, int lun,
|
||||
struct mfi_ld_info *info = cmd->iov_buf;
|
||||
size_t dcmd_size = sizeof(struct mfi_ld_info);
|
||||
uint8_t cdb[6];
|
||||
- SCSIRequest *req;
|
||||
ssize_t len, resid;
|
||||
uint16_t sdev_id = ((sdev->id & 0xFF) << 8) | (lun & 0xFF);
|
||||
uint64_t ld_size;
|
||||
@@ -1226,8 +1227,8 @@ static int megasas_ld_get_info_submit(SCSIDevice *sdev, int lun,
|
||||
cmd->iov_buf = g_malloc0(dcmd_size);
|
||||
info = cmd->iov_buf;
|
||||
megasas_setup_inquiry(cdb, 0x83, sizeof(info->vpd_page83));
|
||||
- req = scsi_req_new(sdev, cmd->index, lun, cdb, cmd);
|
||||
- if (!req) {
|
||||
+ cmd->req = scsi_req_new(sdev, cmd->index, lun, cdb, cmd);
|
||||
+ if (!cmd->req) {
|
||||
trace_megasas_dcmd_req_alloc_failed(cmd->index,
|
||||
"LD get info vpd inquiry");
|
||||
g_free(cmd->iov_buf);
|
||||
@@ -1236,10 +1237,10 @@ static int megasas_ld_get_info_submit(SCSIDevice *sdev, int lun,
|
||||
}
|
||||
trace_megasas_dcmd_internal_submit(cmd->index,
|
||||
"LD get info vpd inquiry", lun);
|
||||
- len = scsi_req_enqueue(req);
|
||||
+ len = scsi_req_enqueue(cmd->req);
|
||||
if (len > 0) {
|
||||
cmd->iov_size = len;
|
||||
- scsi_req_continue(req);
|
||||
+ scsi_req_continue(cmd->req);
|
||||
}
|
||||
return MFI_STAT_INVALID_STATUS;
|
||||
}
|
||||
@@ -1851,7 +1852,7 @@ static void megasas_command_complete(SCSIRequest *req, uint32_t status,
|
||||
return;
|
||||
}
|
||||
|
||||
- if (cmd->req == NULL) {
|
||||
+ if (cmd->dcmd_opcode != -1) {
|
||||
/*
|
||||
* Internal command complete
|
||||
*/
|
||||
--
|
||||
2.11.0
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Prasad J Pandit <pjp@fedoraproject.org>
|
||||
Date: Mon, 17 Jul 2017 17:33:26 +0530
|
||||
Subject: [PATCH] slirp: check len against dhcp options array end
|
||||
|
||||
While parsing dhcp options string in 'dhcp_decode', if an options'
|
||||
length 'len' appeared towards the end of 'bp_vend' array, ensuing
|
||||
read could lead to an OOB memory access issue. Add check to avoid it.
|
||||
|
||||
This is CVE-2017-11434.
|
||||
|
||||
Reported-by: Reno Robert <renorobert@gmail.com>
|
||||
Signed-off-by: Prasad J Pandit <pjp@fedoraproject.org>
|
||||
Signed-off-by: Samuel Thibault <samuel.thibault@ens-lyon.org>
|
||||
---
|
||||
slirp/bootp.c | 3 +++
|
||||
1 file changed, 3 insertions(+)
|
||||
|
||||
diff --git a/slirp/bootp.c b/slirp/bootp.c
|
||||
index 5a4646c182..5dd1a415b5 100644
|
||||
--- a/slirp/bootp.c
|
||||
+++ b/slirp/bootp.c
|
||||
@@ -123,6 +123,9 @@ static void dhcp_decode(const struct bootp_t *bp, int *pmsg_type,
|
||||
if (p >= p_end)
|
||||
break;
|
||||
len = *p++;
|
||||
+ if (p + len > p_end) {
|
||||
+ break;
|
||||
+ }
|
||||
DPRINTF("dhcp: tag=%d len=%d\n", tag, len);
|
||||
|
||||
switch(tag) {
|
||||
--
|
||||
2.11.0
|
||||
|
|
@ -1,44 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
Date: Wed, 9 Aug 2017 17:02:11 +0100
|
||||
Subject: [PATCH] IDE: Do not flush empty CDROM drives
|
||||
|
||||
The block backend changed in a way that flushing empty CDROM drives now
|
||||
crashes. Amend IDE to avoid doing so until the root problem can be
|
||||
addressed for 2.11.
|
||||
|
||||
Original patch by John Snow <jsnow@redhat.com>.
|
||||
|
||||
Reported-by: Kieron Shorrock <kshorrock@paloaltonetworks.com>
|
||||
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
Reviewed-by: Eric Blake <eblake@redhat.com>
|
||||
Message-id: 20170809160212.29976-2-stefanha@redhat.com
|
||||
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
---
|
||||
hw/ide/core.c | 10 +++++++++-
|
||||
1 file changed, 9 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/hw/ide/core.c b/hw/ide/core.c
|
||||
index 0b48b64d3a..bea39536b0 100644
|
||||
--- a/hw/ide/core.c
|
||||
+++ b/hw/ide/core.c
|
||||
@@ -1063,7 +1063,15 @@ static void ide_flush_cache(IDEState *s)
|
||||
s->status |= BUSY_STAT;
|
||||
ide_set_retry(s);
|
||||
block_acct_start(blk_get_stats(s->blk), &s->acct, 0, BLOCK_ACCT_FLUSH);
|
||||
- s->pio_aiocb = blk_aio_flush(s->blk, ide_flush_cb, s);
|
||||
+
|
||||
+ if (blk_bs(s->blk)) {
|
||||
+ s->pio_aiocb = blk_aio_flush(s->blk, ide_flush_cb, s);
|
||||
+ } else {
|
||||
+ /* XXX blk_aio_flush() crashes when blk_bs(blk) is NULL, remove this
|
||||
+ * temporary workaround when blk_aio_*() functions handle NULL blk_bs.
|
||||
+ */
|
||||
+ ide_flush_cb(s, 0);
|
||||
+ }
|
||||
}
|
||||
|
||||
static void ide_cfata_metadata_inquiry(IDEState *s)
|
||||
--
|
||||
2.11.0
|
||||
|
|
@ -1,51 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Gerd Hoffmann <kraxel@redhat.com>
|
||||
Date: Fri, 21 Apr 2017 11:16:24 +0200
|
||||
Subject: [PATCH] bitmap: add bitmap_copy_and_clear_atomic
|
||||
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
Message-id: 20170421091632.30900-2-kraxel@redhat.com
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
---
|
||||
include/qemu/bitmap.h | 2 ++
|
||||
util/bitmap.c | 11 +++++++++++
|
||||
2 files changed, 13 insertions(+)
|
||||
|
||||
diff --git a/include/qemu/bitmap.h b/include/qemu/bitmap.h
|
||||
index 63ea2d0b1e..c318da12d7 100644
|
||||
--- a/include/qemu/bitmap.h
|
||||
+++ b/include/qemu/bitmap.h
|
||||
@@ -220,6 +220,8 @@ void bitmap_set(unsigned long *map, long i, long len);
|
||||
void bitmap_set_atomic(unsigned long *map, long i, long len);
|
||||
void bitmap_clear(unsigned long *map, long start, long nr);
|
||||
bool bitmap_test_and_clear_atomic(unsigned long *map, long start, long nr);
|
||||
+void bitmap_copy_and_clear_atomic(unsigned long *dst, unsigned long *src,
|
||||
+ long nr);
|
||||
unsigned long bitmap_find_next_zero_area(unsigned long *map,
|
||||
unsigned long size,
|
||||
unsigned long start,
|
||||
diff --git a/util/bitmap.c b/util/bitmap.c
|
||||
index c1a84ca5e3..efced9a7d8 100644
|
||||
--- a/util/bitmap.c
|
||||
+++ b/util/bitmap.c
|
||||
@@ -287,6 +287,17 @@ bool bitmap_test_and_clear_atomic(unsigned long *map, long start, long nr)
|
||||
return dirty != 0;
|
||||
}
|
||||
|
||||
+void bitmap_copy_and_clear_atomic(unsigned long *dst, unsigned long *src,
|
||||
+ long nr)
|
||||
+{
|
||||
+ while (nr > 0) {
|
||||
+ *dst = atomic_xchg(src, 0);
|
||||
+ dst++;
|
||||
+ src++;
|
||||
+ nr -= BITS_PER_LONG;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
#define ALIGN_MASK(x,mask) (((x)+(mask))&~(mask))
|
||||
|
||||
/**
|
||||
--
|
||||
2.11.0
|
||||
|
|
@ -1,241 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Gerd Hoffmann <kraxel@redhat.com>
|
||||
Date: Fri, 21 Apr 2017 11:16:25 +0200
|
||||
Subject: [PATCH] memory: add support getting and using a dirty bitmap copy.
|
||||
|
||||
This patch adds support for getting and using a local copy of the dirty
|
||||
bitmap.
|
||||
|
||||
memory_region_snapshot_and_clear_dirty() will create a snapshot of the
|
||||
dirty bitmap for the specified range, clear the dirty bitmap and return
|
||||
the copy. The returned bitmap can be a bit larger than requested, the
|
||||
range is expanded so the code can copy unsigned longs from the bitmap
|
||||
and avoid atomic bit update operations.
|
||||
|
||||
memory_region_snapshot_get_dirty() will return the dirty status of
|
||||
pages, pretty much like memory_region_get_dirty(), but using the copy
|
||||
returned by memory_region_copy_and_clear_dirty().
|
||||
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
Message-id: 20170421091632.30900-3-kraxel@redhat.com
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
---
|
||||
exec.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
include/exec/memory.h | 47 +++++++++++++++++++++++++++++++
|
||||
include/exec/ram_addr.h | 7 +++++
|
||||
include/qemu/typedefs.h | 1 +
|
||||
memory.c | 17 +++++++++++
|
||||
5 files changed, 147 insertions(+)
|
||||
|
||||
diff --git a/exec.c b/exec.c
|
||||
index fcb5b16131..07c2c8ea88 100644
|
||||
--- a/exec.c
|
||||
+++ b/exec.c
|
||||
@@ -223,6 +223,12 @@ struct CPUAddressSpace {
|
||||
MemoryListener tcg_as_listener;
|
||||
};
|
||||
|
||||
+struct DirtyBitmapSnapshot {
|
||||
+ ram_addr_t start;
|
||||
+ ram_addr_t end;
|
||||
+ unsigned long dirty[];
|
||||
+};
|
||||
+
|
||||
#endif
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
@@ -1061,6 +1067,75 @@ bool cpu_physical_memory_test_and_clear_dirty(ram_addr_t start,
|
||||
return dirty;
|
||||
}
|
||||
|
||||
+DirtyBitmapSnapshot *cpu_physical_memory_snapshot_and_clear_dirty
|
||||
+ (ram_addr_t start, ram_addr_t length, unsigned client)
|
||||
+{
|
||||
+ DirtyMemoryBlocks *blocks;
|
||||
+ unsigned long align = 1UL << (TARGET_PAGE_BITS + BITS_PER_LEVEL);
|
||||
+ ram_addr_t first = QEMU_ALIGN_DOWN(start, align);
|
||||
+ ram_addr_t last = QEMU_ALIGN_UP(start + length, align);
|
||||
+ DirtyBitmapSnapshot *snap;
|
||||
+ unsigned long page, end, dest;
|
||||
+
|
||||
+ snap = g_malloc0(sizeof(*snap) +
|
||||
+ ((last - first) >> (TARGET_PAGE_BITS + 3)));
|
||||
+ snap->start = first;
|
||||
+ snap->end = last;
|
||||
+
|
||||
+ page = first >> TARGET_PAGE_BITS;
|
||||
+ end = last >> TARGET_PAGE_BITS;
|
||||
+ dest = 0;
|
||||
+
|
||||
+ rcu_read_lock();
|
||||
+
|
||||
+ blocks = atomic_rcu_read(&ram_list.dirty_memory[client]);
|
||||
+
|
||||
+ while (page < end) {
|
||||
+ unsigned long idx = page / DIRTY_MEMORY_BLOCK_SIZE;
|
||||
+ unsigned long offset = page % DIRTY_MEMORY_BLOCK_SIZE;
|
||||
+ unsigned long num = MIN(end - page, DIRTY_MEMORY_BLOCK_SIZE - offset);
|
||||
+
|
||||
+ assert(QEMU_IS_ALIGNED(offset, (1 << BITS_PER_LEVEL)));
|
||||
+ assert(QEMU_IS_ALIGNED(num, (1 << BITS_PER_LEVEL)));
|
||||
+ offset >>= BITS_PER_LEVEL;
|
||||
+
|
||||
+ bitmap_copy_and_clear_atomic(snap->dirty + dest,
|
||||
+ blocks->blocks[idx] + offset,
|
||||
+ num);
|
||||
+ page += num;
|
||||
+ dest += num >> BITS_PER_LEVEL;
|
||||
+ }
|
||||
+
|
||||
+ rcu_read_unlock();
|
||||
+
|
||||
+ if (tcg_enabled()) {
|
||||
+ tlb_reset_dirty_range_all(start, length);
|
||||
+ }
|
||||
+
|
||||
+ return snap;
|
||||
+}
|
||||
+
|
||||
+bool cpu_physical_memory_snapshot_get_dirty(DirtyBitmapSnapshot *snap,
|
||||
+ ram_addr_t start,
|
||||
+ ram_addr_t length)
|
||||
+{
|
||||
+ unsigned long page, end;
|
||||
+
|
||||
+ assert(start >= snap->start);
|
||||
+ assert(start + length <= snap->end);
|
||||
+
|
||||
+ end = TARGET_PAGE_ALIGN(start + length - snap->start) >> TARGET_PAGE_BITS;
|
||||
+ page = (start - snap->start) >> TARGET_PAGE_BITS;
|
||||
+
|
||||
+ while (page < end) {
|
||||
+ if (test_bit(page, snap->dirty)) {
|
||||
+ return true;
|
||||
+ }
|
||||
+ page++;
|
||||
+ }
|
||||
+ return false;
|
||||
+}
|
||||
+
|
||||
/* Called from RCU critical section */
|
||||
hwaddr memory_region_section_get_iotlb(CPUState *cpu,
|
||||
MemoryRegionSection *section,
|
||||
diff --git a/include/exec/memory.h b/include/exec/memory.h
|
||||
index f20b191793..1e15e79d00 100644
|
||||
--- a/include/exec/memory.h
|
||||
+++ b/include/exec/memory.h
|
||||
@@ -871,6 +871,53 @@ void memory_region_set_dirty(MemoryRegion *mr, hwaddr addr,
|
||||
*/
|
||||
bool memory_region_test_and_clear_dirty(MemoryRegion *mr, hwaddr addr,
|
||||
hwaddr size, unsigned client);
|
||||
+
|
||||
+/**
|
||||
+ * memory_region_snapshot_and_clear_dirty: Get a snapshot of the dirty
|
||||
+ * bitmap and clear it.
|
||||
+ *
|
||||
+ * Creates a snapshot of the dirty bitmap, clears the dirty bitmap and
|
||||
+ * returns the snapshot. The snapshot can then be used to query dirty
|
||||
+ * status, using memory_region_snapshot_get_dirty. Unlike
|
||||
+ * memory_region_test_and_clear_dirty this allows to query the same
|
||||
+ * page multiple times, which is especially useful for display updates
|
||||
+ * where the scanlines often are not page aligned.
|
||||
+ *
|
||||
+ * The dirty bitmap region which gets copyed into the snapshot (and
|
||||
+ * cleared afterwards) can be larger than requested. The boundaries
|
||||
+ * are rounded up/down so complete bitmap longs (covering 64 pages on
|
||||
+ * 64bit hosts) can be copied over into the bitmap snapshot. Which
|
||||
+ * isn't a problem for display updates as the extra pages are outside
|
||||
+ * the visible area, and in case the visible area changes a full
|
||||
+ * display redraw is due anyway. Should other use cases for this
|
||||
+ * function emerge we might have to revisit this implementation
|
||||
+ * detail.
|
||||
+ *
|
||||
+ * Use g_free to release DirtyBitmapSnapshot.
|
||||
+ *
|
||||
+ * @mr: the memory region being queried.
|
||||
+ * @addr: the address (relative to the start of the region) being queried.
|
||||
+ * @size: the size of the range being queried.
|
||||
+ * @client: the user of the logging information; typically %DIRTY_MEMORY_VGA.
|
||||
+ */
|
||||
+DirtyBitmapSnapshot *memory_region_snapshot_and_clear_dirty(MemoryRegion *mr,
|
||||
+ hwaddr addr,
|
||||
+ hwaddr size,
|
||||
+ unsigned client);
|
||||
+
|
||||
+/**
|
||||
+ * memory_region_snapshot_get_dirty: Check whether a range of bytes is dirty
|
||||
+ * in the specified dirty bitmap snapshot.
|
||||
+ *
|
||||
+ * @mr: the memory region being queried.
|
||||
+ * @snap: the dirty bitmap snapshot
|
||||
+ * @addr: the address (relative to the start of the region) being queried.
|
||||
+ * @size: the size of the range being queried.
|
||||
+ */
|
||||
+bool memory_region_snapshot_get_dirty(MemoryRegion *mr,
|
||||
+ DirtyBitmapSnapshot *snap,
|
||||
+ hwaddr addr, hwaddr size);
|
||||
+
|
||||
/**
|
||||
* memory_region_sync_dirty_bitmap: Synchronize a region's dirty bitmap with
|
||||
* any external TLBs (e.g. kvm)
|
||||
diff --git a/include/exec/ram_addr.h b/include/exec/ram_addr.h
|
||||
index b05dc84ab9..2b63d7f59e 100644
|
||||
--- a/include/exec/ram_addr.h
|
||||
+++ b/include/exec/ram_addr.h
|
||||
@@ -343,6 +343,13 @@ bool cpu_physical_memory_test_and_clear_dirty(ram_addr_t start,
|
||||
ram_addr_t length,
|
||||
unsigned client);
|
||||
|
||||
+DirtyBitmapSnapshot *cpu_physical_memory_snapshot_and_clear_dirty
|
||||
+ (ram_addr_t start, ram_addr_t length, unsigned client);
|
||||
+
|
||||
+bool cpu_physical_memory_snapshot_get_dirty(DirtyBitmapSnapshot *snap,
|
||||
+ ram_addr_t start,
|
||||
+ ram_addr_t length);
|
||||
+
|
||||
static inline void cpu_physical_memory_clear_dirty_range(ram_addr_t start,
|
||||
ram_addr_t length)
|
||||
{
|
||||
diff --git a/include/qemu/typedefs.h b/include/qemu/typedefs.h
|
||||
index e95f28cfec..f08d327aec 100644
|
||||
--- a/include/qemu/typedefs.h
|
||||
+++ b/include/qemu/typedefs.h
|
||||
@@ -23,6 +23,7 @@ typedef struct CPUAddressSpace CPUAddressSpace;
|
||||
typedef struct CPUState CPUState;
|
||||
typedef struct DeviceListener DeviceListener;
|
||||
typedef struct DeviceState DeviceState;
|
||||
+typedef struct DirtyBitmapSnapshot DirtyBitmapSnapshot;
|
||||
typedef struct DisplayChangeListener DisplayChangeListener;
|
||||
typedef struct DisplayState DisplayState;
|
||||
typedef struct DisplaySurface DisplaySurface;
|
||||
diff --git a/memory.c b/memory.c
|
||||
index 4c95aaf39c..8a0648551f 100644
|
||||
--- a/memory.c
|
||||
+++ b/memory.c
|
||||
@@ -1716,6 +1716,23 @@ bool memory_region_test_and_clear_dirty(MemoryRegion *mr, hwaddr addr,
|
||||
memory_region_get_ram_addr(mr) + addr, size, client);
|
||||
}
|
||||
|
||||
+DirtyBitmapSnapshot *memory_region_snapshot_and_clear_dirty(MemoryRegion *mr,
|
||||
+ hwaddr addr,
|
||||
+ hwaddr size,
|
||||
+ unsigned client)
|
||||
+{
|
||||
+ assert(mr->ram_block);
|
||||
+ return cpu_physical_memory_snapshot_and_clear_dirty(
|
||||
+ memory_region_get_ram_addr(mr) + addr, size, client);
|
||||
+}
|
||||
+
|
||||
+bool memory_region_snapshot_get_dirty(MemoryRegion *mr, DirtyBitmapSnapshot *snap,
|
||||
+ hwaddr addr, hwaddr size)
|
||||
+{
|
||||
+ assert(mr->ram_block);
|
||||
+ return cpu_physical_memory_snapshot_get_dirty(snap,
|
||||
+ memory_region_get_ram_addr(mr) + addr, size);
|
||||
+}
|
||||
|
||||
void memory_region_sync_dirty_bitmap(MemoryRegion *mr)
|
||||
{
|
||||
--
|
||||
2.11.0
|
||||
|
|
@ -1,63 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Gerd Hoffmann <kraxel@redhat.com>
|
||||
Date: Fri, 21 Apr 2017 11:16:26 +0200
|
||||
Subject: [PATCH] vga: add vga_scanline_invalidated helper
|
||||
|
||||
Add vga_scanline_invalidated helper to check whenever a scanline was
|
||||
invalidated. Add a sanity check to fix OOB read access for display
|
||||
heights larger than 2048.
|
||||
|
||||
Only cirrus uses this, for hardware cursor rendering, so having this
|
||||
work properly for the first 2048 scanlines only shouldn't be a problem
|
||||
as the cirrus can't handle large resolutions anyway. Also changing the
|
||||
invalidated_y_table size would break live migration.
|
||||
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
Message-id: 20170421091632.30900-4-kraxel@redhat.com
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
---
|
||||
hw/display/vga.c | 14 +++++++++++---
|
||||
1 file changed, 11 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/hw/display/vga.c b/hw/display/vga.c
|
||||
index 69c3e1d674..3991b88aac 100644
|
||||
--- a/hw/display/vga.c
|
||||
+++ b/hw/display/vga.c
|
||||
@@ -1434,6 +1434,14 @@ void vga_invalidate_scanlines(VGACommonState *s, int y1, int y2)
|
||||
}
|
||||
}
|
||||
|
||||
+static bool vga_scanline_invalidated(VGACommonState *s, int y)
|
||||
+{
|
||||
+ if (y >= VGA_MAX_HEIGHT) {
|
||||
+ return false;
|
||||
+ }
|
||||
+ return s->invalidated_y_table[y >> 5] & (1 << (y & 0x1f));
|
||||
+}
|
||||
+
|
||||
void vga_sync_dirty_bitmap(VGACommonState *s)
|
||||
{
|
||||
memory_region_sync_dirty_bitmap(&s->vram);
|
||||
@@ -1638,8 +1646,8 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
|
||||
page1 = addr + bwidth - 1;
|
||||
update |= memory_region_get_dirty(&s->vram, page0, page1 - page0,
|
||||
DIRTY_MEMORY_VGA);
|
||||
- /* explicit invalidation for the hardware cursor */
|
||||
- update |= (s->invalidated_y_table[y >> 5] >> (y & 0x1f)) & 1;
|
||||
+ /* explicit invalidation for the hardware cursor (cirrus only) */
|
||||
+ update |= vga_scanline_invalidated(s, y);
|
||||
if (update) {
|
||||
if (y_start < 0)
|
||||
y_start = y;
|
||||
@@ -1686,7 +1694,7 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
|
||||
page_max - page_min,
|
||||
DIRTY_MEMORY_VGA);
|
||||
}
|
||||
- memset(s->invalidated_y_table, 0, ((height + 31) >> 5) * 4);
|
||||
+ memset(s->invalidated_y_table, 0, sizeof(s->invalidated_y_table));
|
||||
}
|
||||
|
||||
static void vga_draw_blank(VGACommonState *s, int full_update)
|
||||
--
|
||||
2.11.0
|
||||
|
|
@ -1,114 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Gerd Hoffmann <kraxel@redhat.com>
|
||||
Date: Fri, 21 Apr 2017 11:16:27 +0200
|
||||
Subject: [PATCH] vga: make display updates thread safe.
|
||||
|
||||
The vga code clears the dirty bits *after* reading the framebuffer
|
||||
memory. So if the guest framebuffer updates hits the race window
|
||||
between vga reading the framebuffer and vga clearing the dirty bits
|
||||
vga will miss that update
|
||||
|
||||
Fix it by using the new memory_region_copy_and_clear_dirty()
|
||||
memory_region_copy_get_dirty() functions. That way we clear the
|
||||
dirty bitmap before reading the framebuffer. Any guest display
|
||||
updates happening in parallel will be properly tracked in the
|
||||
dirty bitmap then and the next display refresh will pick them up.
|
||||
|
||||
Problem triggers with mttcg only. Before mttcg was merged tcg
|
||||
never ran in parallel to vga emulation. Using kvm will hide the
|
||||
problem too, due to qemu operating on a userspace copy of the
|
||||
kernel's dirty bitmap.
|
||||
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
Message-id: 20170421091632.30900-5-kraxel@redhat.com
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
---
|
||||
hw/display/vga.c | 36 +++++++++++++++++-------------------
|
||||
1 file changed, 17 insertions(+), 19 deletions(-)
|
||||
|
||||
diff --git a/hw/display/vga.c b/hw/display/vga.c
|
||||
index 3991b88aac..b2516c8d21 100644
|
||||
--- a/hw/display/vga.c
|
||||
+++ b/hw/display/vga.c
|
||||
@@ -1465,7 +1465,8 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
|
||||
DisplaySurface *surface = qemu_console_surface(s->con);
|
||||
int y1, y, update, linesize, y_start, double_scan, mask, depth;
|
||||
int width, height, shift_control, line_offset, bwidth, bits;
|
||||
- ram_addr_t page0, page1, page_min, page_max;
|
||||
+ ram_addr_t page0, page1;
|
||||
+ DirtyBitmapSnapshot *snap = NULL;
|
||||
int disp_width, multi_scan, multi_run;
|
||||
uint8_t *d;
|
||||
uint32_t v, addr1, addr;
|
||||
@@ -1480,9 +1481,6 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
|
||||
|
||||
full_update |= update_basic_params(s);
|
||||
|
||||
- if (!full_update)
|
||||
- vga_sync_dirty_bitmap(s);
|
||||
-
|
||||
s->get_resolution(s, &width, &height);
|
||||
disp_width = width;
|
||||
|
||||
@@ -1625,11 +1623,17 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
|
||||
addr1 = (s->start_addr * 4);
|
||||
bwidth = (width * bits + 7) / 8;
|
||||
y_start = -1;
|
||||
- page_min = -1;
|
||||
- page_max = 0;
|
||||
d = surface_data(surface);
|
||||
linesize = surface_stride(surface);
|
||||
y1 = 0;
|
||||
+
|
||||
+ if (!full_update) {
|
||||
+ vga_sync_dirty_bitmap(s);
|
||||
+ snap = memory_region_snapshot_and_clear_dirty(&s->vram, addr1,
|
||||
+ bwidth * height,
|
||||
+ DIRTY_MEMORY_VGA);
|
||||
+ }
|
||||
+
|
||||
for(y = 0; y < height; y++) {
|
||||
addr = addr1;
|
||||
if (!(s->cr[VGA_CRTC_MODE] & 1)) {
|
||||
@@ -1644,17 +1648,17 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
|
||||
update = full_update;
|
||||
page0 = addr;
|
||||
page1 = addr + bwidth - 1;
|
||||
- update |= memory_region_get_dirty(&s->vram, page0, page1 - page0,
|
||||
- DIRTY_MEMORY_VGA);
|
||||
+ if (full_update) {
|
||||
+ update = 1;
|
||||
+ } else {
|
||||
+ update = memory_region_snapshot_get_dirty(&s->vram, snap,
|
||||
+ page0, page1 - page0);
|
||||
+ }
|
||||
/* explicit invalidation for the hardware cursor (cirrus only) */
|
||||
update |= vga_scanline_invalidated(s, y);
|
||||
if (update) {
|
||||
if (y_start < 0)
|
||||
y_start = y;
|
||||
- if (page0 < page_min)
|
||||
- page_min = page0;
|
||||
- if (page1 > page_max)
|
||||
- page_max = page1;
|
||||
if (!(is_buffer_shared(surface))) {
|
||||
vga_draw_line(s, d, s->vram_ptr + addr, width);
|
||||
if (s->cursor_draw_line)
|
||||
@@ -1687,13 +1691,7 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
|
||||
dpy_gfx_update(s->con, 0, y_start,
|
||||
disp_width, y - y_start);
|
||||
}
|
||||
- /* reset modified pages */
|
||||
- if (page_max >= page_min) {
|
||||
- memory_region_reset_dirty(&s->vram,
|
||||
- page_min,
|
||||
- page_max - page_min,
|
||||
- DIRTY_MEMORY_VGA);
|
||||
- }
|
||||
+ g_free(snap);
|
||||
memset(s->invalidated_y_table, 0, sizeof(s->invalidated_y_table));
|
||||
}
|
||||
|
||||
--
|
||||
2.11.0
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Gerd Hoffmann <kraxel@redhat.com>
|
||||
Date: Tue, 9 May 2017 12:48:39 +0200
|
||||
Subject: [PATCH] vga: fix display update region calculation
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
vga display update mis-calculated the region for the dirty bitmap
|
||||
snapshot in case the scanlines are padded. This can triggere an
|
||||
assert in cpu_physical_memory_snapshot_get_dirty().
|
||||
|
||||
Fixes: fec5e8c92becad223df9d972770522f64aafdb72
|
||||
Reported-by: Kevin Wolf <kwolf@redhat.com>
|
||||
Reported-by: 李强 <liqiang6-s@360.cn>
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
Message-id: 20170509104839.19415-1-kraxel@redhat.com
|
||||
---
|
||||
hw/display/vga.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/hw/display/vga.c b/hw/display/vga.c
|
||||
index b2516c8d21..dcc95f88e2 100644
|
||||
--- a/hw/display/vga.c
|
||||
+++ b/hw/display/vga.c
|
||||
@@ -1630,7 +1630,7 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
|
||||
if (!full_update) {
|
||||
vga_sync_dirty_bitmap(s);
|
||||
snap = memory_region_snapshot_and_clear_dirty(&s->vram, addr1,
|
||||
- bwidth * height,
|
||||
+ line_offset * height,
|
||||
DIRTY_MEMORY_VGA);
|
||||
}
|
||||
|
||||
--
|
||||
2.11.0
|
||||
|
|
@ -1,46 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Gerd Hoffmann <kraxel@redhat.com>
|
||||
Date: Fri, 1 Sep 2017 14:57:38 +0200
|
||||
Subject: [PATCH] vga: fix display update region calculation (split screen)
|
||||
|
||||
vga display update mis-calculated the region for the dirty bitmap
|
||||
snapshot in case split screen mode is used. This can trigger an
|
||||
assert in cpu_physical_memory_snapshot_get_dirty().
|
||||
|
||||
Impact: DoS for privileged guest users.
|
||||
|
||||
Fixes: CVE-2017-13673
|
||||
Fixes: fec5e8c92becad223df9d972770522f64aafdb72
|
||||
Cc: P J P <ppandit@redhat.com>
|
||||
Reported-by: David Buchanan <d@vidbuchanan.co.uk>
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
Message-id: 20170828123307.15392-1-kraxel@redhat.com
|
||||
---
|
||||
hw/display/vga.c | 10 ++++++++--
|
||||
1 file changed, 8 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/hw/display/vga.c b/hw/display/vga.c
|
||||
index dcc95f88e2..533d8d7895 100644
|
||||
--- a/hw/display/vga.c
|
||||
+++ b/hw/display/vga.c
|
||||
@@ -1628,9 +1628,15 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
|
||||
y1 = 0;
|
||||
|
||||
if (!full_update) {
|
||||
+ ram_addr_t region_start = addr1;
|
||||
+ ram_addr_t region_end = addr1 + line_offset * height;
|
||||
vga_sync_dirty_bitmap(s);
|
||||
- snap = memory_region_snapshot_and_clear_dirty(&s->vram, addr1,
|
||||
- line_offset * height,
|
||||
+ if (s->line_compare < height) {
|
||||
+ /* split screen mode */
|
||||
+ region_start = 0;
|
||||
+ }
|
||||
+ snap = memory_region_snapshot_and_clear_dirty(&s->vram, region_start,
|
||||
+ region_end - region_start,
|
||||
DIRTY_MEMORY_VGA);
|
||||
}
|
||||
|
||||
--
|
||||
2.11.0
|
||||
|
|
@ -1,497 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Gerd Hoffmann <kraxel@redhat.com>
|
||||
Date: Fri, 1 Sep 2017 14:57:39 +0200
|
||||
Subject: [PATCH] vga: stop passing pointers to vga_draw_line* functions
|
||||
|
||||
Instead pass around the address (aka offset into vga memory).
|
||||
Add vga_read_* helper functions which apply vbe_size_mask to
|
||||
the address, to make sure the address stays within the valid
|
||||
range, similar to the cirrus blitter fixes (commits ffaf857778
|
||||
and 026aeffcb4).
|
||||
|
||||
Impact: DoS for privileged guest users. qemu crashes with
|
||||
a segfault, when hitting the guard page after vga memory
|
||||
allocation, while reading vga memory for display updates.
|
||||
|
||||
Fixes: CVE-2017-13672
|
||||
Cc: P J P <ppandit@redhat.com>
|
||||
Reported-by: David Buchanan <d@vidbuchanan.co.uk>
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
Message-id: 20170828122906.18993-1-kraxel@redhat.com
|
||||
---
|
||||
hw/display/vga-helpers.h | 202 ++++++++++++++++++++++++++---------------------
|
||||
hw/display/vga.c | 5 +-
|
||||
hw/display/vga_int.h | 1 +
|
||||
3 files changed, 114 insertions(+), 94 deletions(-)
|
||||
|
||||
diff --git a/hw/display/vga-helpers.h b/hw/display/vga-helpers.h
|
||||
index 94f6de2046..5a752b3f9e 100644
|
||||
--- a/hw/display/vga-helpers.h
|
||||
+++ b/hw/display/vga-helpers.h
|
||||
@@ -95,20 +95,46 @@ static void vga_draw_glyph9(uint8_t *d, int linesize,
|
||||
} while (--h);
|
||||
}
|
||||
|
||||
+static inline uint8_t vga_read_byte(VGACommonState *vga, uint32_t addr)
|
||||
+{
|
||||
+ return vga->vram_ptr[addr & vga->vbe_size_mask];
|
||||
+}
|
||||
+
|
||||
+static inline uint16_t vga_read_word_le(VGACommonState *vga, uint32_t addr)
|
||||
+{
|
||||
+ uint32_t offset = addr & vga->vbe_size_mask & ~1;
|
||||
+ uint16_t *ptr = (uint16_t *)(vga->vram_ptr + offset);
|
||||
+ return lduw_le_p(ptr);
|
||||
+}
|
||||
+
|
||||
+static inline uint16_t vga_read_word_be(VGACommonState *vga, uint32_t addr)
|
||||
+{
|
||||
+ uint32_t offset = addr & vga->vbe_size_mask & ~1;
|
||||
+ uint16_t *ptr = (uint16_t *)(vga->vram_ptr + offset);
|
||||
+ return lduw_be_p(ptr);
|
||||
+}
|
||||
+
|
||||
+static inline uint32_t vga_read_dword_le(VGACommonState *vga, uint32_t addr)
|
||||
+{
|
||||
+ uint32_t offset = addr & vga->vbe_size_mask & ~3;
|
||||
+ uint32_t *ptr = (uint32_t *)(vga->vram_ptr + offset);
|
||||
+ return ldl_le_p(ptr);
|
||||
+}
|
||||
+
|
||||
/*
|
||||
* 4 color mode
|
||||
*/
|
||||
-static void vga_draw_line2(VGACommonState *s1, uint8_t *d,
|
||||
- const uint8_t *s, int width)
|
||||
+static void vga_draw_line2(VGACommonState *vga, uint8_t *d,
|
||||
+ uint32_t addr, int width)
|
||||
{
|
||||
uint32_t plane_mask, *palette, data, v;
|
||||
int x;
|
||||
|
||||
- palette = s1->last_palette;
|
||||
- plane_mask = mask16[s1->ar[VGA_ATC_PLANE_ENABLE] & 0xf];
|
||||
+ palette = vga->last_palette;
|
||||
+ plane_mask = mask16[vga->ar[VGA_ATC_PLANE_ENABLE] & 0xf];
|
||||
width >>= 3;
|
||||
for(x = 0; x < width; x++) {
|
||||
- data = ((uint32_t *)s)[0];
|
||||
+ data = vga_read_dword_le(vga, addr);
|
||||
data &= plane_mask;
|
||||
v = expand2[GET_PLANE(data, 0)];
|
||||
v |= expand2[GET_PLANE(data, 2)] << 2;
|
||||
@@ -124,7 +150,7 @@ static void vga_draw_line2(VGACommonState *s1, uint8_t *d,
|
||||
((uint32_t *)d)[6] = palette[(v >> 4) & 0xf];
|
||||
((uint32_t *)d)[7] = palette[(v >> 0) & 0xf];
|
||||
d += 32;
|
||||
- s += 4;
|
||||
+ addr += 4;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,17 +160,17 @@ static void vga_draw_line2(VGACommonState *s1, uint8_t *d,
|
||||
/*
|
||||
* 4 color mode, dup2 horizontal
|
||||
*/
|
||||
-static void vga_draw_line2d2(VGACommonState *s1, uint8_t *d,
|
||||
- const uint8_t *s, int width)
|
||||
+static void vga_draw_line2d2(VGACommonState *vga, uint8_t *d,
|
||||
+ uint32_t addr, int width)
|
||||
{
|
||||
uint32_t plane_mask, *palette, data, v;
|
||||
int x;
|
||||
|
||||
- palette = s1->last_palette;
|
||||
- plane_mask = mask16[s1->ar[VGA_ATC_PLANE_ENABLE] & 0xf];
|
||||
+ palette = vga->last_palette;
|
||||
+ plane_mask = mask16[vga->ar[VGA_ATC_PLANE_ENABLE] & 0xf];
|
||||
width >>= 3;
|
||||
for(x = 0; x < width; x++) {
|
||||
- data = ((uint32_t *)s)[0];
|
||||
+ data = vga_read_dword_le(vga, addr);
|
||||
data &= plane_mask;
|
||||
v = expand2[GET_PLANE(data, 0)];
|
||||
v |= expand2[GET_PLANE(data, 2)] << 2;
|
||||
@@ -160,24 +186,24 @@ static void vga_draw_line2d2(VGACommonState *s1, uint8_t *d,
|
||||
PUT_PIXEL2(d, 6, palette[(v >> 4) & 0xf]);
|
||||
PUT_PIXEL2(d, 7, palette[(v >> 0) & 0xf]);
|
||||
d += 64;
|
||||
- s += 4;
|
||||
+ addr += 4;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 16 color mode
|
||||
*/
|
||||
-static void vga_draw_line4(VGACommonState *s1, uint8_t *d,
|
||||
- const uint8_t *s, int width)
|
||||
+static void vga_draw_line4(VGACommonState *vga, uint8_t *d,
|
||||
+ uint32_t addr, int width)
|
||||
{
|
||||
uint32_t plane_mask, data, v, *palette;
|
||||
int x;
|
||||
|
||||
- palette = s1->last_palette;
|
||||
- plane_mask = mask16[s1->ar[VGA_ATC_PLANE_ENABLE] & 0xf];
|
||||
+ palette = vga->last_palette;
|
||||
+ plane_mask = mask16[vga->ar[VGA_ATC_PLANE_ENABLE] & 0xf];
|
||||
width >>= 3;
|
||||
for(x = 0; x < width; x++) {
|
||||
- data = ((uint32_t *)s)[0];
|
||||
+ data = vga_read_dword_le(vga, addr);
|
||||
data &= plane_mask;
|
||||
v = expand4[GET_PLANE(data, 0)];
|
||||
v |= expand4[GET_PLANE(data, 1)] << 1;
|
||||
@@ -192,24 +218,24 @@ static void vga_draw_line4(VGACommonState *s1, uint8_t *d,
|
||||
((uint32_t *)d)[6] = palette[(v >> 4) & 0xf];
|
||||
((uint32_t *)d)[7] = palette[(v >> 0) & 0xf];
|
||||
d += 32;
|
||||
- s += 4;
|
||||
+ addr += 4;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 16 color mode, dup2 horizontal
|
||||
*/
|
||||
-static void vga_draw_line4d2(VGACommonState *s1, uint8_t *d,
|
||||
- const uint8_t *s, int width)
|
||||
+static void vga_draw_line4d2(VGACommonState *vga, uint8_t *d,
|
||||
+ uint32_t addr, int width)
|
||||
{
|
||||
uint32_t plane_mask, data, v, *palette;
|
||||
int x;
|
||||
|
||||
- palette = s1->last_palette;
|
||||
- plane_mask = mask16[s1->ar[VGA_ATC_PLANE_ENABLE] & 0xf];
|
||||
+ palette = vga->last_palette;
|
||||
+ plane_mask = mask16[vga->ar[VGA_ATC_PLANE_ENABLE] & 0xf];
|
||||
width >>= 3;
|
||||
for(x = 0; x < width; x++) {
|
||||
- data = ((uint32_t *)s)[0];
|
||||
+ data = vga_read_dword_le(vga, addr);
|
||||
data &= plane_mask;
|
||||
v = expand4[GET_PLANE(data, 0)];
|
||||
v |= expand4[GET_PLANE(data, 1)] << 1;
|
||||
@@ -224,7 +250,7 @@ static void vga_draw_line4d2(VGACommonState *s1, uint8_t *d,
|
||||
PUT_PIXEL2(d, 6, palette[(v >> 4) & 0xf]);
|
||||
PUT_PIXEL2(d, 7, palette[(v >> 0) & 0xf]);
|
||||
d += 64;
|
||||
- s += 4;
|
||||
+ addr += 4;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -233,21 +259,21 @@ static void vga_draw_line4d2(VGACommonState *s1, uint8_t *d,
|
||||
*
|
||||
* XXX: add plane_mask support (never used in standard VGA modes)
|
||||
*/
|
||||
-static void vga_draw_line8d2(VGACommonState *s1, uint8_t *d,
|
||||
- const uint8_t *s, int width)
|
||||
+static void vga_draw_line8d2(VGACommonState *vga, uint8_t *d,
|
||||
+ uint32_t addr, int width)
|
||||
{
|
||||
uint32_t *palette;
|
||||
int x;
|
||||
|
||||
- palette = s1->last_palette;
|
||||
+ palette = vga->last_palette;
|
||||
width >>= 3;
|
||||
for(x = 0; x < width; x++) {
|
||||
- PUT_PIXEL2(d, 0, palette[s[0]]);
|
||||
- PUT_PIXEL2(d, 1, palette[s[1]]);
|
||||
- PUT_PIXEL2(d, 2, palette[s[2]]);
|
||||
- PUT_PIXEL2(d, 3, palette[s[3]]);
|
||||
+ PUT_PIXEL2(d, 0, palette[vga_read_byte(vga, addr + 0)]);
|
||||
+ PUT_PIXEL2(d, 1, palette[vga_read_byte(vga, addr + 1)]);
|
||||
+ PUT_PIXEL2(d, 2, palette[vga_read_byte(vga, addr + 2)]);
|
||||
+ PUT_PIXEL2(d, 3, palette[vga_read_byte(vga, addr + 3)]);
|
||||
d += 32;
|
||||
- s += 4;
|
||||
+ addr += 4;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -256,63 +282,63 @@ static void vga_draw_line8d2(VGACommonState *s1, uint8_t *d,
|
||||
*
|
||||
* XXX: add plane_mask support (never used in standard VGA modes)
|
||||
*/
|
||||
-static void vga_draw_line8(VGACommonState *s1, uint8_t *d,
|
||||
- const uint8_t *s, int width)
|
||||
+static void vga_draw_line8(VGACommonState *vga, uint8_t *d,
|
||||
+ uint32_t addr, int width)
|
||||
{
|
||||
uint32_t *palette;
|
||||
int x;
|
||||
|
||||
- palette = s1->last_palette;
|
||||
+ palette = vga->last_palette;
|
||||
width >>= 3;
|
||||
for(x = 0; x < width; x++) {
|
||||
- ((uint32_t *)d)[0] = palette[s[0]];
|
||||
- ((uint32_t *)d)[1] = palette[s[1]];
|
||||
- ((uint32_t *)d)[2] = palette[s[2]];
|
||||
- ((uint32_t *)d)[3] = palette[s[3]];
|
||||
- ((uint32_t *)d)[4] = palette[s[4]];
|
||||
- ((uint32_t *)d)[5] = palette[s[5]];
|
||||
- ((uint32_t *)d)[6] = palette[s[6]];
|
||||
- ((uint32_t *)d)[7] = palette[s[7]];
|
||||
+ ((uint32_t *)d)[0] = palette[vga_read_byte(vga, addr + 0)];
|
||||
+ ((uint32_t *)d)[1] = palette[vga_read_byte(vga, addr + 1)];
|
||||
+ ((uint32_t *)d)[2] = palette[vga_read_byte(vga, addr + 2)];
|
||||
+ ((uint32_t *)d)[3] = palette[vga_read_byte(vga, addr + 3)];
|
||||
+ ((uint32_t *)d)[4] = palette[vga_read_byte(vga, addr + 4)];
|
||||
+ ((uint32_t *)d)[5] = palette[vga_read_byte(vga, addr + 5)];
|
||||
+ ((uint32_t *)d)[6] = palette[vga_read_byte(vga, addr + 6)];
|
||||
+ ((uint32_t *)d)[7] = palette[vga_read_byte(vga, addr + 7)];
|
||||
d += 32;
|
||||
- s += 8;
|
||||
+ addr += 8;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 15 bit color
|
||||
*/
|
||||
-static void vga_draw_line15_le(VGACommonState *s1, uint8_t *d,
|
||||
- const uint8_t *s, int width)
|
||||
+static void vga_draw_line15_le(VGACommonState *vga, uint8_t *d,
|
||||
+ uint32_t addr, int width)
|
||||
{
|
||||
int w;
|
||||
uint32_t v, r, g, b;
|
||||
|
||||
w = width;
|
||||
do {
|
||||
- v = lduw_le_p((void *)s);
|
||||
+ v = vga_read_word_le(vga, addr);
|
||||
r = (v >> 7) & 0xf8;
|
||||
g = (v >> 2) & 0xf8;
|
||||
b = (v << 3) & 0xf8;
|
||||
((uint32_t *)d)[0] = rgb_to_pixel32(r, g, b);
|
||||
- s += 2;
|
||||
+ addr += 2;
|
||||
d += 4;
|
||||
} while (--w != 0);
|
||||
}
|
||||
|
||||
-static void vga_draw_line15_be(VGACommonState *s1, uint8_t *d,
|
||||
- const uint8_t *s, int width)
|
||||
+static void vga_draw_line15_be(VGACommonState *vga, uint8_t *d,
|
||||
+ uint32_t addr, int width)
|
||||
{
|
||||
int w;
|
||||
uint32_t v, r, g, b;
|
||||
|
||||
w = width;
|
||||
do {
|
||||
- v = lduw_be_p((void *)s);
|
||||
+ v = vga_read_word_be(vga, addr);
|
||||
r = (v >> 7) & 0xf8;
|
||||
g = (v >> 2) & 0xf8;
|
||||
b = (v << 3) & 0xf8;
|
||||
((uint32_t *)d)[0] = rgb_to_pixel32(r, g, b);
|
||||
- s += 2;
|
||||
+ addr += 2;
|
||||
d += 4;
|
||||
} while (--w != 0);
|
||||
}
|
||||
@@ -320,38 +346,38 @@ static void vga_draw_line15_be(VGACommonState *s1, uint8_t *d,
|
||||
/*
|
||||
* 16 bit color
|
||||
*/
|
||||
-static void vga_draw_line16_le(VGACommonState *s1, uint8_t *d,
|
||||
- const uint8_t *s, int width)
|
||||
+static void vga_draw_line16_le(VGACommonState *vga, uint8_t *d,
|
||||
+ uint32_t addr, int width)
|
||||
{
|
||||
int w;
|
||||
uint32_t v, r, g, b;
|
||||
|
||||
w = width;
|
||||
do {
|
||||
- v = lduw_le_p((void *)s);
|
||||
+ v = vga_read_word_le(vga, addr);
|
||||
r = (v >> 8) & 0xf8;
|
||||
g = (v >> 3) & 0xfc;
|
||||
b = (v << 3) & 0xf8;
|
||||
((uint32_t *)d)[0] = rgb_to_pixel32(r, g, b);
|
||||
- s += 2;
|
||||
+ addr += 2;
|
||||
d += 4;
|
||||
} while (--w != 0);
|
||||
}
|
||||
|
||||
-static void vga_draw_line16_be(VGACommonState *s1, uint8_t *d,
|
||||
- const uint8_t *s, int width)
|
||||
+static void vga_draw_line16_be(VGACommonState *vga, uint8_t *d,
|
||||
+ uint32_t addr, int width)
|
||||
{
|
||||
int w;
|
||||
uint32_t v, r, g, b;
|
||||
|
||||
w = width;
|
||||
do {
|
||||
- v = lduw_be_p((void *)s);
|
||||
+ v = vga_read_word_be(vga, addr);
|
||||
r = (v >> 8) & 0xf8;
|
||||
g = (v >> 3) & 0xfc;
|
||||
b = (v << 3) & 0xf8;
|
||||
((uint32_t *)d)[0] = rgb_to_pixel32(r, g, b);
|
||||
- s += 2;
|
||||
+ addr += 2;
|
||||
d += 4;
|
||||
} while (--w != 0);
|
||||
}
|
||||
@@ -359,36 +385,36 @@ static void vga_draw_line16_be(VGACommonState *s1, uint8_t *d,
|
||||
/*
|
||||
* 24 bit color
|
||||
*/
|
||||
-static void vga_draw_line24_le(VGACommonState *s1, uint8_t *d,
|
||||
- const uint8_t *s, int width)
|
||||
+static void vga_draw_line24_le(VGACommonState *vga, uint8_t *d,
|
||||
+ uint32_t addr, int width)
|
||||
{
|
||||
int w;
|
||||
uint32_t r, g, b;
|
||||
|
||||
w = width;
|
||||
do {
|
||||
- b = s[0];
|
||||
- g = s[1];
|
||||
- r = s[2];
|
||||
+ b = vga_read_byte(vga, addr + 0);
|
||||
+ g = vga_read_byte(vga, addr + 1);
|
||||
+ r = vga_read_byte(vga, addr + 2);
|
||||
((uint32_t *)d)[0] = rgb_to_pixel32(r, g, b);
|
||||
- s += 3;
|
||||
+ addr += 3;
|
||||
d += 4;
|
||||
} while (--w != 0);
|
||||
}
|
||||
|
||||
-static void vga_draw_line24_be(VGACommonState *s1, uint8_t *d,
|
||||
- const uint8_t *s, int width)
|
||||
+static void vga_draw_line24_be(VGACommonState *vga, uint8_t *d,
|
||||
+ uint32_t addr, int width)
|
||||
{
|
||||
int w;
|
||||
uint32_t r, g, b;
|
||||
|
||||
w = width;
|
||||
do {
|
||||
- r = s[0];
|
||||
- g = s[1];
|
||||
- b = s[2];
|
||||
+ r = vga_read_byte(vga, addr + 0);
|
||||
+ g = vga_read_byte(vga, addr + 1);
|
||||
+ b = vga_read_byte(vga, addr + 2);
|
||||
((uint32_t *)d)[0] = rgb_to_pixel32(r, g, b);
|
||||
- s += 3;
|
||||
+ addr += 3;
|
||||
d += 4;
|
||||
} while (--w != 0);
|
||||
}
|
||||
@@ -396,44 +422,36 @@ static void vga_draw_line24_be(VGACommonState *s1, uint8_t *d,
|
||||
/*
|
||||
* 32 bit color
|
||||
*/
|
||||
-static void vga_draw_line32_le(VGACommonState *s1, uint8_t *d,
|
||||
- const uint8_t *s, int width)
|
||||
+static void vga_draw_line32_le(VGACommonState *vga, uint8_t *d,
|
||||
+ uint32_t addr, int width)
|
||||
{
|
||||
-#ifndef HOST_WORDS_BIGENDIAN
|
||||
- memcpy(d, s, width * 4);
|
||||
-#else
|
||||
int w;
|
||||
uint32_t r, g, b;
|
||||
|
||||
w = width;
|
||||
do {
|
||||
- b = s[0];
|
||||
- g = s[1];
|
||||
- r = s[2];
|
||||
+ b = vga_read_byte(vga, addr + 0);
|
||||
+ g = vga_read_byte(vga, addr + 1);
|
||||
+ r = vga_read_byte(vga, addr + 2);
|
||||
((uint32_t *)d)[0] = rgb_to_pixel32(r, g, b);
|
||||
- s += 4;
|
||||
+ addr += 4;
|
||||
d += 4;
|
||||
} while (--w != 0);
|
||||
-#endif
|
||||
}
|
||||
|
||||
-static void vga_draw_line32_be(VGACommonState *s1, uint8_t *d,
|
||||
- const uint8_t *s, int width)
|
||||
+static void vga_draw_line32_be(VGACommonState *vga, uint8_t *d,
|
||||
+ uint32_t addr, int width)
|
||||
{
|
||||
-#ifdef HOST_WORDS_BIGENDIAN
|
||||
- memcpy(d, s, width * 4);
|
||||
-#else
|
||||
int w;
|
||||
uint32_t r, g, b;
|
||||
|
||||
w = width;
|
||||
do {
|
||||
- r = s[1];
|
||||
- g = s[2];
|
||||
- b = s[3];
|
||||
+ r = vga_read_byte(vga, addr + 1);
|
||||
+ g = vga_read_byte(vga, addr + 2);
|
||||
+ b = vga_read_byte(vga, addr + 3);
|
||||
((uint32_t *)d)[0] = rgb_to_pixel32(r, g, b);
|
||||
- s += 4;
|
||||
+ addr += 4;
|
||||
d += 4;
|
||||
} while (--w != 0);
|
||||
-#endif
|
||||
}
|
||||
diff --git a/hw/display/vga.c b/hw/display/vga.c
|
||||
index 533d8d7895..13e4a5d55d 100644
|
||||
--- a/hw/display/vga.c
|
||||
+++ b/hw/display/vga.c
|
||||
@@ -1005,7 +1005,7 @@ void vga_mem_writeb(VGACommonState *s, hwaddr addr, uint32_t val)
|
||||
}
|
||||
|
||||
typedef void vga_draw_line_func(VGACommonState *s1, uint8_t *d,
|
||||
- const uint8_t *s, int width);
|
||||
+ uint32_t srcaddr, int width);
|
||||
|
||||
#include "vga-helpers.h"
|
||||
|
||||
@@ -1666,7 +1666,7 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
|
||||
if (y_start < 0)
|
||||
y_start = y;
|
||||
if (!(is_buffer_shared(surface))) {
|
||||
- vga_draw_line(s, d, s->vram_ptr + addr, width);
|
||||
+ vga_draw_line(s, d, addr, width);
|
||||
if (s->cursor_draw_line)
|
||||
s->cursor_draw_line(s, d, y);
|
||||
}
|
||||
@@ -2170,6 +2170,7 @@ void vga_common_init(VGACommonState *s, Object *obj, bool global_vmstate)
|
||||
if (!s->vbe_size) {
|
||||
s->vbe_size = s->vram_size;
|
||||
}
|
||||
+ s->vbe_size_mask = s->vbe_size - 1;
|
||||
|
||||
s->is_vbe_vmstate = 1;
|
||||
memory_region_init_ram(&s->vram, obj, "vga.vram", s->vram_size,
|
||||
diff --git a/hw/display/vga_int.h b/hw/display/vga_int.h
|
||||
index dd6c958da3..ad34a1f048 100644
|
||||
--- a/hw/display/vga_int.h
|
||||
+++ b/hw/display/vga_int.h
|
||||
@@ -94,6 +94,7 @@ typedef struct VGACommonState {
|
||||
uint32_t vram_size;
|
||||
uint32_t vram_size_mb; /* property */
|
||||
uint32_t vbe_size;
|
||||
+ uint32_t vbe_size_mask;
|
||||
uint32_t latch;
|
||||
bool has_chain4_alias;
|
||||
MemoryRegion chain4_alias;
|
||||
--
|
||||
2.11.0
|
||||
|
|
@ -1,61 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Prasad J Pandit <pjp@fedoraproject.org>
|
||||
Date: Thu, 7 Sep 2017 12:02:56 +0530
|
||||
Subject: [PATCH] multiboot: validate multiboot header address values
|
||||
|
||||
While loading kernel via multiboot-v1 image, (flags & 0x00010000)
|
||||
indicates that multiboot header contains valid addresses to load
|
||||
the kernel image. These addresses are used to compute kernel
|
||||
size and kernel text offset in the OS image. Validate these
|
||||
address values to avoid an OOB access issue.
|
||||
|
||||
This is CVE-2017-14167.
|
||||
|
||||
Reported-by: Thomas Garnier <thgarnie@google.com>
|
||||
Signed-off-by: Prasad J Pandit <pjp@fedoraproject.org>
|
||||
---
|
||||
hw/i386/multiboot.c | 19 +++++++++++++++++++
|
||||
1 file changed, 19 insertions(+)
|
||||
|
||||
diff --git a/hw/i386/multiboot.c b/hw/i386/multiboot.c
|
||||
index f13e23139b..22688d376d 100644
|
||||
--- a/hw/i386/multiboot.c
|
||||
+++ b/hw/i386/multiboot.c
|
||||
@@ -221,15 +221,34 @@ int load_multiboot(FWCfgState *fw_cfg,
|
||||
uint32_t mh_header_addr = ldl_p(header+i+12);
|
||||
uint32_t mh_load_end_addr = ldl_p(header+i+20);
|
||||
uint32_t mh_bss_end_addr = ldl_p(header+i+24);
|
||||
+
|
||||
mh_load_addr = ldl_p(header+i+16);
|
||||
+ if (mh_header_addr < mh_load_addr) {
|
||||
+ fprintf(stderr, "invalid mh_load_addr address\n");
|
||||
+ exit(1);
|
||||
+ }
|
||||
+
|
||||
uint32_t mb_kernel_text_offset = i - (mh_header_addr - mh_load_addr);
|
||||
uint32_t mb_load_size = 0;
|
||||
mh_entry_addr = ldl_p(header+i+28);
|
||||
|
||||
if (mh_load_end_addr) {
|
||||
+ if (mh_bss_end_addr < mh_load_addr) {
|
||||
+ fprintf(stderr, "invalid mh_bss_end_addr address\n");
|
||||
+ exit(1);
|
||||
+ }
|
||||
mb_kernel_size = mh_bss_end_addr - mh_load_addr;
|
||||
+
|
||||
+ if (mh_load_end_addr < mh_load_addr) {
|
||||
+ fprintf(stderr, "invalid mh_load_end_addr address\n");
|
||||
+ exit(1);
|
||||
+ }
|
||||
mb_load_size = mh_load_end_addr - mh_load_addr;
|
||||
} else {
|
||||
+ if (kernel_file_size < mb_kernel_text_offset) {
|
||||
+ fprintf(stderr, "invalid kernel_file_size\n");
|
||||
+ exit(1);
|
||||
+ }
|
||||
mb_kernel_size = kernel_file_size - mb_kernel_text_offset;
|
||||
mb_load_size = mb_kernel_size;
|
||||
}
|
||||
--
|
||||
2.11.0
|
||||
|
|
@ -1,57 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Wolfgang Bumiller <w.bumiller@proxmox.com>
|
||||
Date: Wed, 20 Sep 2017 08:09:33 +0200
|
||||
Subject: [PATCH] virtio: fix descriptor counting in virtqueue_pop
|
||||
|
||||
While changing the s/g list allocation, commit 3b3b0628
|
||||
also changed the descriptor counting to count iovec entries
|
||||
as split by cpu_physical_memory_map(). Previously only the
|
||||
actual descriptor entries were counted and the split into
|
||||
the iovec happened afterwards in virtqueue_map().
|
||||
Count the entries again instead to avoid erroneous
|
||||
"Looped descriptor" errors.
|
||||
|
||||
Reported-by: Hans Middelhoek <h.middelhoek@ospito.nl>
|
||||
Link: https://forum.proxmox.com/threads/vm-crash-with-memory-hotplug.35904/
|
||||
Fixes: 3b3b0628217e ("virtio: slim down allocation of VirtQueueElements")
|
||||
Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
|
||||
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
|
||||
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
|
||||
---
|
||||
hw/virtio/virtio.c | 6 +++---
|
||||
1 file changed, 3 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
|
||||
index 890b4d7eb7..33bb770177 100644
|
||||
--- a/hw/virtio/virtio.c
|
||||
+++ b/hw/virtio/virtio.c
|
||||
@@ -834,7 +834,7 @@ void *virtqueue_pop(VirtQueue *vq, size_t sz)
|
||||
int64_t len;
|
||||
VirtIODevice *vdev = vq->vdev;
|
||||
VirtQueueElement *elem = NULL;
|
||||
- unsigned out_num, in_num;
|
||||
+ unsigned out_num, in_num, elem_entries;
|
||||
hwaddr addr[VIRTQUEUE_MAX_SIZE];
|
||||
struct iovec iov[VIRTQUEUE_MAX_SIZE];
|
||||
VRingDesc desc;
|
||||
@@ -852,7 +852,7 @@ void *virtqueue_pop(VirtQueue *vq, size_t sz)
|
||||
smp_rmb();
|
||||
|
||||
/* When we start there are none of either input nor output. */
|
||||
- out_num = in_num = 0;
|
||||
+ out_num = in_num = elem_entries = 0;
|
||||
|
||||
max = vq->vring.num;
|
||||
|
||||
@@ -922,7 +922,7 @@ void *virtqueue_pop(VirtQueue *vq, size_t sz)
|
||||
}
|
||||
|
||||
/* If we've got too many, that implies a descriptor loop. */
|
||||
- if ((in_num + out_num) > max) {
|
||||
+ if (++elem_entries > max) {
|
||||
virtio_error(vdev, "Looped descriptor");
|
||||
goto err_undo_map;
|
||||
}
|
||||
--
|
||||
2.11.0
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Wolfgang Bumiller <w.bumiller@proxmox.com>
|
||||
Date: Wed, 29 Nov 2017 09:39:55 +0100
|
||||
Subject: [PATCH] nbd/server: CVE-2017-15119 Reject options larger than 32M
|
||||
|
||||
Backported-from: fdad35ef6c58
|
||||
---
|
||||
nbd/server.c | 6 ++++++
|
||||
1 file changed, 6 insertions(+)
|
||||
|
||||
diff --git a/nbd/server.c b/nbd/server.c
|
||||
index a98bb21a0a..4d6da8ac06 100644
|
||||
--- a/nbd/server.c
|
||||
+++ b/nbd/server.c
|
||||
@@ -489,6 +489,12 @@ static int nbd_negotiate_options(NBDClient *client)
|
||||
}
|
||||
length = be32_to_cpu(length);
|
||||
|
||||
+ if (length > NBD_MAX_BUFFER_SIZE) {
|
||||
+ LOG("len (%" PRIu32" ) is larger than max len (%u)",
|
||||
+ length, NBD_MAX_BUFFER_SIZE);
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
TRACE("Checking option 0x%" PRIx32, clientflags);
|
||||
if (client->tlscreds &&
|
||||
client->ioc == (QIOChannel *)client->sioc) {
|
||||
--
|
||||
2.11.0
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: "Dr. David Alan Gilbert" <dgilbert@redhat.com>
|
||||
Date: Fri, 4 Aug 2017 12:33:29 +0100
|
||||
Subject: [PATCH] vga/migration: Update memory map in post_load
|
||||
|
||||
After migration the chain4 alias mapping added by 80763888 (in 2011)
|
||||
might be missing, since there's no call to vga_update_memory_access
|
||||
in the post_load after the registers are updated. Add it back.
|
||||
|
||||
Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
|
||||
Reviewed-by: Juan Quintela <quintela@redhat.com>
|
||||
Message-id: 20170804113329.13609-1-dgilbert@redhat.com
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
---
|
||||
hw/display/vga.c | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/hw/display/vga.c b/hw/display/vga.c
|
||||
index 13e4a5d55d..a99d831e04 100644
|
||||
--- a/hw/display/vga.c
|
||||
+++ b/hw/display/vga.c
|
||||
@@ -2050,6 +2050,7 @@ static int vga_common_post_load(void *opaque, int version_id)
|
||||
/* force refresh */
|
||||
s->graphic_mode = -1;
|
||||
vbe_update_vgaregs(s);
|
||||
+ vga_update_memory_access(s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
--
|
||||
2.11.0
|
||||
|
|
@ -1,52 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Gerd Hoffmann <kraxel@redhat.com>
|
||||
Date: Tue, 10 Oct 2017 16:13:21 +0200
|
||||
Subject: [PATCH] vga: drop line_offset variable
|
||||
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
---
|
||||
hw/display/vga.c | 7 +++----
|
||||
1 file changed, 3 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/hw/display/vga.c b/hw/display/vga.c
|
||||
index a99d831e04..77af807a51 100644
|
||||
--- a/hw/display/vga.c
|
||||
+++ b/hw/display/vga.c
|
||||
@@ -1464,7 +1464,7 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
|
||||
{
|
||||
DisplaySurface *surface = qemu_console_surface(s->con);
|
||||
int y1, y, update, linesize, y_start, double_scan, mask, depth;
|
||||
- int width, height, shift_control, line_offset, bwidth, bits;
|
||||
+ int width, height, shift_control, bwidth, bits;
|
||||
ram_addr_t page0, page1;
|
||||
DirtyBitmapSnapshot *snap = NULL;
|
||||
int disp_width, multi_scan, multi_run;
|
||||
@@ -1614,7 +1614,6 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
|
||||
s->cursor_invalidate(s);
|
||||
}
|
||||
|
||||
- line_offset = s->line_offset;
|
||||
#if 0
|
||||
printf("w=%d h=%d v=%d line_offset=%d cr[0x09]=0x%02x cr[0x17]=0x%02x linecmp=%d sr[0x01]=0x%02x\n",
|
||||
width, height, v, line_offset, s->cr[9], s->cr[VGA_CRTC_MODE],
|
||||
@@ -1629,7 +1628,7 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
|
||||
|
||||
if (!full_update) {
|
||||
ram_addr_t region_start = addr1;
|
||||
- ram_addr_t region_end = addr1 + line_offset * height;
|
||||
+ ram_addr_t region_end = addr1 + s->line_offset * height;
|
||||
vga_sync_dirty_bitmap(s);
|
||||
if (s->line_compare < height) {
|
||||
/* split screen mode */
|
||||
@@ -1681,7 +1680,7 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
|
||||
if (!multi_run) {
|
||||
mask = (s->cr[VGA_CRTC_MODE] & 3) ^ 3;
|
||||
if ((y1 & mask) == mask)
|
||||
- addr1 += line_offset;
|
||||
+ addr1 += s->line_offset;
|
||||
y1++;
|
||||
multi_run = multi_scan;
|
||||
} else {
|
||||