mirror of
git://git.proxmox.com/git/pve-qemu.git
synced 2024-12-23 21:35:23 +03:00
merge CVE-2017-17381 fix and backup race condition fix
* CVE-2017-17381: virtio: divide by zero exception while updating rings * race condition when issuing a 'backup-stop' command Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
This commit is contained in:
parent
d2494dd2ef
commit
c25a222062
68
debian/patches/extra/0024-virtio-check-VirtQueue-Vring-object-is-set.patch
vendored
Normal file
68
debian/patches/extra/0024-virtio-check-VirtQueue-Vring-object-is-set.patch
vendored
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
From 537048fe17ab94242908536adcb638ec274a3f53 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Prasad J Pandit <pjp@fedoraproject.org>
|
||||||
|
Date: Wed, 29 Nov 2017 23:14:27 +0530
|
||||||
|
Subject: [PATCH 1/2] virtio: check VirtQueue Vring object is set
|
||||||
|
|
||||||
|
A guest could attempt to use an uninitialised VirtQueue object
|
||||||
|
or unset Vring.align leading to a arithmetic exception. Add check
|
||||||
|
to avoid it.
|
||||||
|
|
||||||
|
Reported-by: Zhangboxian <zhangboxian@huawei.com>
|
||||||
|
Signed-off-by: Prasad J Pandit <pjp@fedoraproject.org>
|
||||||
|
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
|
||||||
|
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
|
||||||
|
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||||
|
Reviewed-by: Cornelia Huck <cohuck@redhat.com>
|
||||||
|
---
|
||||||
|
hw/virtio/virtio.c | 14 +++++++++++---
|
||||||
|
1 file changed, 11 insertions(+), 3 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
|
||||||
|
index 33bb770177..76b9a9907c 100644
|
||||||
|
--- a/hw/virtio/virtio.c
|
||||||
|
+++ b/hw/virtio/virtio.c
|
||||||
|
@@ -183,7 +183,7 @@ void virtio_queue_update_rings(VirtIODevice *vdev, int n)
|
||||||
|
{
|
||||||
|
VRing *vring = &vdev->vq[n].vring;
|
||||||
|
|
||||||
|
- if (!vring->desc) {
|
||||||
|
+ if (!vring->num || !vring->desc || !vring->align) {
|
||||||
|
/* not yet setup -> nothing to do */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
@@ -1416,6 +1416,9 @@ void virtio_config_modern_writel(VirtIODevice *vdev,
|
||||||
|
|
||||||
|
void virtio_queue_set_addr(VirtIODevice *vdev, int n, hwaddr addr)
|
||||||
|
{
|
||||||
|
+ if (!vdev->vq[n].vring.num) {
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
vdev->vq[n].vring.desc = addr;
|
||||||
|
virtio_queue_update_rings(vdev, n);
|
||||||
|
}
|
||||||
|
@@ -1428,6 +1431,9 @@ hwaddr virtio_queue_get_addr(VirtIODevice *vdev, int n)
|
||||||
|
void virtio_queue_set_rings(VirtIODevice *vdev, int n, hwaddr desc,
|
||||||
|
hwaddr avail, hwaddr used)
|
||||||
|
{
|
||||||
|
+ if (!vdev->vq[n].vring.num) {
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
vdev->vq[n].vring.desc = desc;
|
||||||
|
vdev->vq[n].vring.avail = avail;
|
||||||
|
vdev->vq[n].vring.used = used;
|
||||||
|
@@ -1496,8 +1502,10 @@ void virtio_queue_set_align(VirtIODevice *vdev, int n, int align)
|
||||||
|
*/
|
||||||
|
assert(k->has_variable_vring_alignment);
|
||||||
|
|
||||||
|
- vdev->vq[n].vring.align = align;
|
||||||
|
- virtio_queue_update_rings(vdev, n);
|
||||||
|
+ if (align) {
|
||||||
|
+ vdev->vq[n].vring.align = align;
|
||||||
|
+ virtio_queue_update_rings(vdev, n);
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool virtio_queue_notify_aio_vq(VirtQueue *vq)
|
||||||
|
--
|
||||||
|
2.11.0
|
||||||
|
|
253
debian/patches/pve/0029-backup-fix-race-in-backup-stop-command.patch
vendored
Normal file
253
debian/patches/pve/0029-backup-fix-race-in-backup-stop-command.patch
vendored
Normal file
@ -0,0 +1,253 @@
|
|||||||
|
From 3cff3cff0dda09201386dff3c86c5e4fdb0b41b7 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Wolfgang Bumiller <w.bumiller@proxmox.com>
|
||||||
|
Date: Tue, 5 Dec 2017 12:12:15 +0100
|
||||||
|
Subject: [PATCH 2/2] backup: fix race in backup-stop command
|
||||||
|
|
||||||
|
Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
|
||||||
|
---
|
||||||
|
blockdev.c | 90 +++++++++++++++++++++++++++++++++-----------------------------
|
||||||
|
blockjob.c | 8 +++---
|
||||||
|
2 files changed, 52 insertions(+), 46 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/blockdev.c b/blockdev.c
|
||||||
|
index 19a82e8774..d3490936d8 100644
|
||||||
|
--- a/blockdev.c
|
||||||
|
+++ b/blockdev.c
|
||||||
|
@@ -2934,31 +2934,6 @@ out:
|
||||||
|
aio_context_release(aio_context);
|
||||||
|
}
|
||||||
|
|
||||||
|
-void block_job_event_cancelled(BlockJob *job);
|
||||||
|
-void block_job_event_completed(BlockJob *job, const char *msg);
|
||||||
|
-static void block_job_cb(void *opaque, int ret)
|
||||||
|
-{
|
||||||
|
- /* Note that this function may be executed from another AioContext besides
|
||||||
|
- * the QEMU main loop. If you need to access anything that assumes the
|
||||||
|
- * QEMU global mutex, use a BH or introduce a mutex.
|
||||||
|
- */
|
||||||
|
-
|
||||||
|
- BlockDriverState *bs = opaque;
|
||||||
|
- const char *msg = NULL;
|
||||||
|
-
|
||||||
|
- assert(bs->job);
|
||||||
|
-
|
||||||
|
- if (ret < 0) {
|
||||||
|
- msg = strerror(-ret);
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- if (block_job_is_cancelled(bs->job)) {
|
||||||
|
- block_job_event_cancelled(bs->job);
|
||||||
|
- } else {
|
||||||
|
- block_job_event_completed(bs->job, msg);
|
||||||
|
- }
|
||||||
|
-}
|
||||||
|
-
|
||||||
|
/* PVE backup related function */
|
||||||
|
|
||||||
|
static struct PVEBackupState {
|
||||||
|
@@ -2975,6 +2950,8 @@ static struct PVEBackupState {
|
||||||
|
size_t total;
|
||||||
|
size_t transferred;
|
||||||
|
size_t zero_bytes;
|
||||||
|
+ QemuMutex backup_mutex;
|
||||||
|
+ bool backup_mutex_initialized;
|
||||||
|
} backup_state;
|
||||||
|
|
||||||
|
typedef struct PVEBackupDevInfo {
|
||||||
|
@@ -3055,6 +3032,13 @@ static int pvebackup_dump_cb(void *opaque, BlockBackend *target,
|
||||||
|
|
||||||
|
static void pvebackup_cleanup(void)
|
||||||
|
{
|
||||||
|
+ qemu_mutex_lock(&backup_state.backup_mutex);
|
||||||
|
+ // Avoid race between block jobs and backup-cancel command:
|
||||||
|
+ if (!backup_state.vmaw) {
|
||||||
|
+ qemu_mutex_unlock(&backup_state.backup_mutex);
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
backup_state.end_time = time(NULL);
|
||||||
|
|
||||||
|
if (backup_state.vmaw) {
|
||||||
|
@@ -3064,16 +3048,9 @@ static void pvebackup_cleanup(void)
|
||||||
|
backup_state.vmaw = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
- if (backup_state.di_list) {
|
||||||
|
- GList *l = backup_state.di_list;
|
||||||
|
- while (l) {
|
||||||
|
- PVEBackupDevInfo *di = (PVEBackupDevInfo *)l->data;
|
||||||
|
- l = g_list_next(l);
|
||||||
|
- g_free(di);
|
||||||
|
- }
|
||||||
|
- g_list_free(backup_state.di_list);
|
||||||
|
- backup_state.di_list = NULL;
|
||||||
|
- }
|
||||||
|
+ g_list_free(backup_state.di_list);
|
||||||
|
+ backup_state.di_list = NULL;
|
||||||
|
+ qemu_mutex_unlock(&backup_state.backup_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void coroutine_fn backup_close_vma_stream(void *opaque)
|
||||||
|
@@ -3085,6 +3062,8 @@ static void coroutine_fn backup_close_vma_stream(void *opaque)
|
||||||
|
|
||||||
|
static void pvebackup_complete_cb(void *opaque, int ret)
|
||||||
|
{
|
||||||
|
+ // This always runs in the main loop
|
||||||
|
+
|
||||||
|
PVEBackupDevInfo *di = opaque;
|
||||||
|
|
||||||
|
di->completed = true;
|
||||||
|
@@ -3094,8 +3073,6 @@ static void pvebackup_complete_cb(void *opaque, int ret)
|
||||||
|
ret, strerror(-ret));
|
||||||
|
}
|
||||||
|
|
||||||
|
- BlockDriverState *bs = di->bs;
|
||||||
|
-
|
||||||
|
di->bs = NULL;
|
||||||
|
di->target = NULL;
|
||||||
|
|
||||||
|
@@ -3104,7 +3081,11 @@ static void pvebackup_complete_cb(void *opaque, int ret)
|
||||||
|
qemu_coroutine_enter(co);
|
||||||
|
}
|
||||||
|
|
||||||
|
- block_job_cb(bs, ret);
|
||||||
|
+ // remove self from job queue
|
||||||
|
+ qemu_mutex_lock(&backup_state.backup_mutex);
|
||||||
|
+ backup_state.di_list = g_list_remove(backup_state.di_list, di);
|
||||||
|
+ g_free(di);
|
||||||
|
+ qemu_mutex_unlock(&backup_state.backup_mutex);
|
||||||
|
|
||||||
|
if (!backup_state.cancel) {
|
||||||
|
pvebackup_run_next_job();
|
||||||
|
@@ -3114,6 +3095,12 @@ static void pvebackup_complete_cb(void *opaque, int ret)
|
||||||
|
static void pvebackup_cancel(void *opaque)
|
||||||
|
{
|
||||||
|
backup_state.cancel = true;
|
||||||
|
+ qemu_mutex_lock(&backup_state.backup_mutex);
|
||||||
|
+ // Avoid race between block jobs and backup-cancel command:
|
||||||
|
+ if (!backup_state.vmaw) {
|
||||||
|
+ qemu_mutex_unlock(&backup_state.backup_mutex);
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
|
||||||
|
if (!backup_state.error) {
|
||||||
|
error_setg(&backup_state.error, "backup cancelled");
|
||||||
|
@@ -3131,13 +3118,17 @@ static void pvebackup_cancel(void *opaque)
|
||||||
|
if (!di->completed && di->bs) {
|
||||||
|
BlockJob *job = di->bs->job;
|
||||||
|
if (job) {
|
||||||
|
+ AioContext *aio_context = blk_get_aio_context(job->blk);
|
||||||
|
+ aio_context_acquire(aio_context);
|
||||||
|
if (!di->completed) {
|
||||||
|
- block_job_cancel_sync(job);
|
||||||
|
+ block_job_cancel(job);
|
||||||
|
}
|
||||||
|
+ aio_context_release(aio_context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+ qemu_mutex_unlock(&backup_state.backup_mutex);
|
||||||
|
pvebackup_cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -3193,24 +3184,31 @@ static int config_to_vma(const char *file, BackupFormat format,
|
||||||
|
bool block_job_should_pause(BlockJob *job);
|
||||||
|
static void pvebackup_run_next_job(void)
|
||||||
|
{
|
||||||
|
+ qemu_mutex_lock(&backup_state.backup_mutex);
|
||||||
|
+
|
||||||
|
GList *l = backup_state.di_list;
|
||||||
|
while (l) {
|
||||||
|
PVEBackupDevInfo *di = (PVEBackupDevInfo *)l->data;
|
||||||
|
l = g_list_next(l);
|
||||||
|
if (!di->completed && di->bs && di->bs->job) {
|
||||||
|
BlockJob *job = di->bs->job;
|
||||||
|
+ AioContext *aio_context = blk_get_aio_context(job->blk);
|
||||||
|
+ aio_context_acquire(aio_context);
|
||||||
|
+ qemu_mutex_unlock(&backup_state.backup_mutex);
|
||||||
|
if (block_job_should_pause(job)) {
|
||||||
|
- bool cancel = backup_state.error || backup_state.cancel;
|
||||||
|
- if (cancel) {
|
||||||
|
- block_job_cancel(job);
|
||||||
|
+ if (backup_state.error || backup_state.cancel) {
|
||||||
|
+ block_job_cancel_sync(job);
|
||||||
|
} else {
|
||||||
|
block_job_resume(job);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+ aio_context_release(aio_context);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+ qemu_mutex_unlock(&backup_state.backup_mutex);
|
||||||
|
|
||||||
|
+ // no more jobs, run the cleanup
|
||||||
|
pvebackup_cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -3233,6 +3231,11 @@ UuidInfo *qmp_backup(const char *backup_file, bool has_format,
|
||||||
|
UuidInfo *uuid_info;
|
||||||
|
BlockJob *job;
|
||||||
|
|
||||||
|
+ if (!backup_state.backup_mutex_initialized) {
|
||||||
|
+ qemu_mutex_init(&backup_state.backup_mutex);
|
||||||
|
+ backup_state.backup_mutex_initialized = true;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
if (backup_state.di_list) {
|
||||||
|
error_set(errp, ERROR_CLASS_GENERIC_ERROR,
|
||||||
|
"previous backup not finished");
|
||||||
|
@@ -3405,6 +3408,7 @@ UuidInfo *qmp_backup(const char *backup_file, bool has_format,
|
||||||
|
uuid_copy(backup_state.uuid, uuid);
|
||||||
|
uuid_unparse_lower(uuid, backup_state.uuid_str);
|
||||||
|
|
||||||
|
+ qemu_mutex_lock(&backup_state.backup_mutex);
|
||||||
|
backup_state.di_list = di_list;
|
||||||
|
|
||||||
|
backup_state.total = total;
|
||||||
|
@@ -3428,6 +3432,8 @@ UuidInfo *qmp_backup(const char *backup_file, bool has_format,
|
||||||
|
block_job_start(job);
|
||||||
|
}
|
||||||
|
|
||||||
|
+ qemu_mutex_unlock(&backup_state.backup_mutex);
|
||||||
|
+
|
||||||
|
if (!backup_state.error) {
|
||||||
|
pvebackup_run_next_job(); // run one job
|
||||||
|
}
|
||||||
|
diff --git a/blockjob.c b/blockjob.c
|
||||||
|
index cb3741f6dd..199d5852db 100644
|
||||||
|
--- a/blockjob.c
|
||||||
|
+++ b/blockjob.c
|
||||||
|
@@ -37,8 +37,8 @@
|
||||||
|
#include "qemu/timer.h"
|
||||||
|
#include "qapi-event.h"
|
||||||
|
|
||||||
|
-void block_job_event_cancelled(BlockJob *job);
|
||||||
|
-void block_job_event_completed(BlockJob *job, const char *msg);
|
||||||
|
+static void block_job_event_cancelled(BlockJob *job);
|
||||||
|
+static void block_job_event_completed(BlockJob *job, const char *msg);
|
||||||
|
|
||||||
|
/* Transactional group of block jobs */
|
||||||
|
struct BlockJobTxn {
|
||||||
|
@@ -688,7 +688,7 @@ static void block_job_iostatus_set_err(BlockJob *job, int error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
-void block_job_event_cancelled(BlockJob *job)
|
||||||
|
+static void block_job_event_cancelled(BlockJob *job)
|
||||||
|
{
|
||||||
|
if (block_job_is_internal(job)) {
|
||||||
|
return;
|
||||||
|
@@ -702,7 +702,7 @@ void block_job_event_cancelled(BlockJob *job)
|
||||||
|
&error_abort);
|
||||||
|
}
|
||||||
|
|
||||||
|
-void block_job_event_completed(BlockJob *job, const char *msg)
|
||||||
|
+static void block_job_event_completed(BlockJob *job, const char *msg)
|
||||||
|
{
|
||||||
|
if (block_job_is_internal(job)) {
|
||||||
|
return;
|
||||||
|
--
|
||||||
|
2.11.0
|
||||||
|
|
2
debian/patches/series
vendored
2
debian/patches/series
vendored
@ -26,6 +26,7 @@ pve/0025-qemu-img-dd-add-osize-and-read-from-to-stdin-stdout.patch
|
|||||||
pve/0026-backup-modify-job-api.patch
|
pve/0026-backup-modify-job-api.patch
|
||||||
pve/0027-backup-introduce-vma-archive-format.patch
|
pve/0027-backup-introduce-vma-archive-format.patch
|
||||||
pve/0028-adding-old-vma-files.patch
|
pve/0028-adding-old-vma-files.patch
|
||||||
|
pve/0029-backup-fix-race-in-backup-stop-command.patch
|
||||||
extra/0001-Revert-target-i386-disable-LINT0-after-reset.patch
|
extra/0001-Revert-target-i386-disable-LINT0-after-reset.patch
|
||||||
extra/0002-virtio-serial-fix-segfault-on-disconnect.patch
|
extra/0002-virtio-serial-fix-segfault-on-disconnect.patch
|
||||||
extra/0003-megasas-always-store-SCSIRequest-into-MegasasCmd.patch
|
extra/0003-megasas-always-store-SCSIRequest-into-MegasasCmd.patch
|
||||||
@ -49,3 +50,4 @@ extra/0020-vga-fix-region-checks-in-wraparound-case.patch
|
|||||||
extra/0021-io-monitor-encoutput-buffer-size-from-websocket-GSou.patch
|
extra/0021-io-monitor-encoutput-buffer-size-from-websocket-GSou.patch
|
||||||
extra/0022-9pfs-use-g_malloc0-to-allocate-space-for-xattr.patch
|
extra/0022-9pfs-use-g_malloc0-to-allocate-space-for-xattr.patch
|
||||||
extra/0023-cirrus-fix-oob-access-in-mode4and5-write-functions.patch
|
extra/0023-cirrus-fix-oob-access-in-mode4and5-write-functions.patch
|
||||||
|
extra/0024-virtio-check-VirtQueue-Vring-object-is-set.patch
|
||||||
|
Loading…
Reference in New Issue
Block a user