diff --git a/SOURCES/kvm-block-add-__com.redhat_change-backing-file-qmp-comma.patch b/SOURCES/kvm-block-add-__com.redhat_change-backing-file-qmp-comma.patch new file mode 100644 index 0000000..06f8023 --- /dev/null +++ b/SOURCES/kvm-block-add-__com.redhat_change-backing-file-qmp-comma.patch @@ -0,0 +1,124 @@ +From ce7b70a0a59a571095a9bec614cce7b260c8c4fd Mon Sep 17 00:00:00 2001 +From: Jeffrey Cody +Date: Fri, 19 Sep 2014 03:18:59 +0200 +Subject: [PATCH 4/4] block: add __com.redhat_change-backing-file qmp command + +Message-id: +Patchwork-id: 61313 +O-Subject: [PATCH qemu-kvm-rhev RHEL7.0.z 4/4] block: add __com.redhat_change-backing-file qmp command +Bugzilla: 1122925 +RH-Acked-by: Kevin Wolf +RH-Acked-by: Eric Blake +RH-Acked-by: Stefan Hajnoczi + +Upstream, the QAPI command 'change-backing-file' was added in a patch, +as part of a series that allowed libvirt to specify backing file +names in block-commit and block-stream. + +This standalone QAPI (change-backing-file) is not currently in use by +libvirt, except as a witness that QEMU has the ability to change backing +files in block-commit and block-stream. + +However, change-backing-file also relies on node-names functionality, +which is not present in RHEL7.0. The backport of node-names would also +be fairly instrusive, especially for a command that is not going to be +used beyond verifying its presence. + +This downstream patch adds __com.redhat_change-backing-file, which +accepts the same arguments as its upstream namesake. However, no action +is performed, and the command always returns QERR_UNSUPPORTED. + +This is not placed inside the RHEL/RHEV differentiation commands, as it +is not a live block operation (upstream or the dummy version), and +returns synchronously. + +Signed-off-by: Jeff Cody +Signed-off-by: Miroslav Rezanina +--- + blockdev.c | 8 ++++++++ + qapi-schema.json | 16 ++++++++++++++++ + qmp-commands.hx | 22 ++++++++++++++++++++++ + 3 files changed, 46 insertions(+), 0 deletions(-) + +diff --git a/blockdev.c b/blockdev.c +index c4fb129..ff0fe9d 100644 +--- a/blockdev.c ++++ b/blockdev.c +@@ -1782,6 +1782,14 @@ void qmp_block_job_complete(const char *device, Error **errp) + block_job_complete(job, errp); + } + ++void qmp___com_redhat_change_backing_file(const char *device, ++ const char *image_node_name, ++ const char *backing_file, ++ Error **errp) ++{ ++ error_set(errp, QERR_UNSUPPORTED); ++} ++ + void qmp_blockdev_add(BlockdevOptions *options, Error **errp) + { + QmpOutputVisitor *ov = qmp_output_visitor_new(); +diff --git a/qapi-schema.json b/qapi-schema.json +index e11b641..3a5a743 100644 +--- a/qapi-schema.json ++++ b/qapi-schema.json +@@ -1826,6 +1826,22 @@ + 'data': {'command-line': 'str', '*cpu-index': 'int'}, + 'returns': 'str' } + ++## ++# @__com.redhat_change-backing-file ++# ++# This is a placeholder function, that exists as a witness for libvirt ++# that the ability to specify backing files in block-commit and block-stream ++# exists in this version of QEMU. ++# ++# It has the same argument requirements as the upstream 'change-backing-file', ++# but performs no action. ++# ++# Returns: NotSupported ++## ++{ 'command': '__com.redhat_change-backing-file', ++ 'data': { 'device': 'str', 'image-node-name': 'str', ++ 'backing-file': 'str' } } ++ + #_rhev-only CONFIG_LIVE_BLOCK_OPS + ## + # @block-commit +diff --git a/qmp-commands.hx b/qmp-commands.hx +index 94f8671..a300d10 100644 +--- a/qmp-commands.hx ++++ b/qmp-commands.hx +@@ -1241,6 +1241,28 @@ EQMP + #endif + + { ++ .name = RFQDN_REDHAT "change-backing-file", ++ .args_type = "device:s,image-node-name:s,backing-file:s", ++ .mhandler.cmd_new = qmp_marshal_input___com_redhat_change_backing_file, ++ }, ++ ++SQMP ++@__com.redhat_change-backing-file ++------------------- ++@__com.redhat_change-backing-file ++ ++This is a placeholder function, that exists as a witness for libvirt ++that the ability to specify backing files block-commit and block-stream ++exists in this version of QEMU. ++ ++It has the same argument requirements as the upstream 'change-backing-file', ++but performs no action. ++ ++Returns: NotSupported ++ ++EQMP ++ ++ { + .name = "balloon", + .args_type = "value:M", + .mhandler.cmd_new = qmp_marshal_input_balloon, +-- +1.7.1 + diff --git a/SOURCES/kvm-block-add-backing-file-option-to-block-stream.patch b/SOURCES/kvm-block-add-backing-file-option-to-block-stream.patch new file mode 100644 index 0000000..c9eeaeb --- /dev/null +++ b/SOURCES/kvm-block-add-backing-file-option-to-block-stream.patch @@ -0,0 +1,234 @@ +From dd7f33dff7cdf1d3481936560a1a1db285856eeb Mon Sep 17 00:00:00 2001 +From: Jeffrey Cody +Date: Fri, 19 Sep 2014 03:18:58 +0200 +Subject: [PATCH 3/4] block: add backing-file option to block-stream + +Message-id: <5b8611fab581db6b4c5eb31c998378090819268d.1411096194.git.jcody@redhat.com> +Patchwork-id: 61312 +O-Subject: [PATCH qemu-kvm-rhev RHEL7.0.z 3/4] block: add backing-file option to block-stream +Bugzilla: 1122925 +RH-Acked-by: Kevin Wolf +RH-Acked-by: Eric Blake +RH-Acked-by: Stefan Hajnoczi + +On some image chains, QEMU may not always be able to resolve the +filenames properly, when updating the backing file of an image +after a block job. + +For instance, certain relative pathnames may fail, or drives may +have been specified originally by file descriptor (e.g. /dev/fd/???), +or a relative protocol pathname may have been used. + +In these instances, QEMU may lack the information to be able to make +the correct choice, but the user or management layer most likely does +have that knowledge. + +With this extension to the block-stream api, the user is able to change +the backing file of the active layer as part of the block-stream +operation. + +This allows the change to be 'safe', in the sense that if the attempt +to write the active image metadata fails, then the block-stream +operation returns failure, without disrupting the guest. + +If a backing file string is not specified in the command, the backing +file string to use is determined in the same manner as it was +previously. + +Reviewed-by: Eric Blake +Signed-off-by: Jeff Cody +Signed-off-by: Stefan Hajnoczi +(cherry picked from commit 13d8cc515dfcf5574077f964332d34890c0101d0) + +Conflicts: + block/stream.c + blockdev.c + qapi/block-core.json + +RHEL7 Notes: Conflicts due to: surrounding context differences, and + and the qapi json not being split into + separate files like upstream. Also + upstream used 1024 for local backing + file string size, and downstream we + already use PATH_MAX instead. + +Signed-off-by: Jeff Cody +Signed-off-by: Miroslav Rezanina +--- + block/stream.c | 11 +++++------ + blockdev.c | 23 +++++++++++++++++++---- + hmp.c | 2 +- + qapi-schema.json | 19 +++++++++++++++++-- + qmp-commands.hx | 2 +- + 5 files changed, 43 insertions(+), 14 deletions(-) + +diff --git a/block/stream.c b/block/stream.c +index 2a6f533..367120d 100644 +--- a/block/stream.c ++++ b/block/stream.c +@@ -32,7 +32,7 @@ typedef struct StreamBlockJob { + RateLimit limit; + BlockDriverState *base; + BlockdevOnError on_error; +- char backing_file_id[PATH_MAX]; ++ char *backing_file_str; + } StreamBlockJob; + + static int coroutine_fn stream_populate(BlockDriverState *bs, +@@ -182,7 +182,7 @@ wait: + if (!block_job_is_cancelled(&s->common) && sector_num == end && ret == 0) { + const char *base_id = NULL, *base_fmt = NULL; + if (base) { +- base_id = s->backing_file_id; ++ base_id = s->backing_file_str; + if (base->drv) { + base_fmt = base->drv->format_name; + } +@@ -192,6 +192,7 @@ wait: + } + + qemu_vfree(buf); ++ g_free(s->backing_file_str); + block_job_completed(&s->common, ret); + } + +@@ -213,7 +214,7 @@ static const BlockJobDriver stream_job_driver = { + }; + + void stream_start(BlockDriverState *bs, BlockDriverState *base, +- const char *base_id, int64_t speed, ++ const char *backing_file_str, int64_t speed, + BlockdevOnError on_error, + BlockDriverCompletionFunc *cb, + void *opaque, Error **errp) +@@ -233,9 +234,7 @@ void stream_start(BlockDriverState *bs, BlockDriverState *base, + } + + s->base = base; +- if (base_id) { +- pstrcpy(s->backing_file_id, sizeof(s->backing_file_id), base_id); +- } ++ s->backing_file_str = g_strdup(backing_file_str); + + s->on_error = on_error; + s->common.co = qemu_coroutine_create(stream_run); +diff --git a/blockdev.c b/blockdev.c +index b22b42e..c4fb129 100644 +--- a/blockdev.c ++++ b/blockdev.c +@@ -1425,14 +1425,17 @@ static void block_job_cb(void *opaque, int ret) + bdrv_put_ref_bh_schedule(bs); + } + +-void qmp_block_stream(const char *device, bool has_base, +- const char *base, bool has_speed, int64_t speed, ++void qmp_block_stream(const char *device, ++ bool has_base, const char *base, ++ bool has_backing_file, const char *backing_file, ++ bool has_speed, int64_t speed, + bool has_on_error, BlockdevOnError on_error, + Error **errp) + { + BlockDriverState *bs; + BlockDriverState *base_bs = NULL; + Error *local_err = NULL; ++ const char *base_name = NULL; + + if (!has_on_error) { + on_error = BLOCKDEV_ON_ERROR_REPORT; +@@ -1444,15 +1447,27 @@ void qmp_block_stream(const char *device, bool has_base, + return; + } + +- if (base) { ++ if (has_base) { + base_bs = bdrv_find_backing_image(bs, base); + if (base_bs == NULL) { + error_set(errp, QERR_BASE_NOT_FOUND, base); + return; + } ++ base_name = base; + } + +- stream_start(bs, base_bs, base, has_speed ? speed : 0, ++ /* if we are streaming the entire chain, the result will have no backing ++ * file, and specifying one is therefore an error */ ++ if (base_bs == NULL && has_backing_file) { ++ error_setg(errp, "backing file specified, but streaming the " ++ "entire chain"); ++ return; ++ } ++ ++ /* backing_file string overrides base bs filename */ ++ base_name = has_backing_file ? backing_file : base_name; ++ ++ stream_start(bs, base_bs, base_name, has_speed ? speed : 0, + on_error, block_job_cb, bs, &local_err); + if (error_is_set(&local_err)) { + error_propagate(errp, local_err); +diff --git a/hmp.c b/hmp.c +index 841929d..b723b26 100644 +--- a/hmp.c ++++ b/hmp.c +@@ -1046,7 +1046,7 @@ void hmp_block_stream(Monitor *mon, const QDict *qdict) + const char *base = qdict_get_try_str(qdict, "base"); + int64_t speed = qdict_get_try_int(qdict, "speed", 0); + +- qmp_block_stream(device, base != NULL, base, ++ qmp_block_stream(device, base != NULL, base, false, NULL, + qdict_haskey(qdict, "speed"), speed, + BLOCKDEV_ON_ERROR_REPORT, true, &error); + +diff --git a/qapi-schema.json b/qapi-schema.json +index 100b059..e11b641 100644 +--- a/qapi-schema.json ++++ b/qapi-schema.json +@@ -2274,6 +2274,21 @@ + # + # @base: #optional the common backing file name + # ++# @backing-file: #optional The backing file string to write into the active ++# layer. This filename is not validated. ++# ++# If a pathname string is such that it cannot be ++# resolved by QEMU, that means that subsequent QMP or ++# HMP commands must use node-names for the image in ++# question, as filename lookup methods will fail. ++# ++# If not specified, QEMU will automatically determine ++# the backing file string to use, or error out if there ++# is no obvious choice. Care should be taken when ++# specifying the string, to specify a valid filename or ++# protocol. ++# (Since 2.1) ++# + # @speed: #optional the maximum speed, in bytes per second + # + # @on-error: #optional the action to take on an error (default report). +@@ -2286,8 +2301,8 @@ + # Since: 1.1 + ## + { 'command': 'block-stream', +- 'data': { 'device': 'str', '*base': 'str', '*speed': 'int', +- '*on-error': 'BlockdevOnError' } } ++ 'data': { 'device': 'str', '*base': 'str', '*backing-file': 'str', ++ '*speed': 'int', '*on-error': 'BlockdevOnError' } } + #_end-rhev-only + + ## +diff --git a/qmp-commands.hx b/qmp-commands.hx +index 79006c5..94f8671 100644 +--- a/qmp-commands.hx ++++ b/qmp-commands.hx +@@ -999,7 +999,7 @@ EQMP + #ifdef CONFIG_LIVE_BLOCK_OPS + { + .name = "block-stream", +- .args_type = "device:B,base:s?,speed:o?,on-error:s?", ++ .args_type = "device:B,base:s?,speed:o?,backing-file:s?,on-error:s?", + .mhandler.cmd_new = qmp_marshal_input_block_stream, + }, + +-- +1.7.1 + diff --git a/SOURCES/kvm-block-add-helper-function-to-determine-if-a-BDS-is-i.patch b/SOURCES/kvm-block-add-helper-function-to-determine-if-a-BDS-is-i.patch new file mode 100644 index 0000000..1747065 --- /dev/null +++ b/SOURCES/kvm-block-add-helper-function-to-determine-if-a-BDS-is-i.patch @@ -0,0 +1,74 @@ +From 77785494f8bb202a99f895a1888ea6246ed81b2f Mon Sep 17 00:00:00 2001 +From: Jeffrey Cody +Date: Fri, 19 Sep 2014 03:18:56 +0200 +Subject: [PATCH 1/4] block: add helper function to determine if a BDS is in a chain + +Message-id: +Patchwork-id: 61310 +O-Subject: [PATCH qemu-kvm-rhev RHEL7.0.z 1/4] block: add helper function to determine if a BDS is in a chain +Bugzilla: 1122925 +RH-Acked-by: Kevin Wolf +RH-Acked-by: Eric Blake +RH-Acked-by: Stefan Hajnoczi + +This is a small helper function, to determine if 'base' is in the +chain of BlockDriverState 'top'. It returns true if it is in the chain, +and false otherwise. + +If either argument is NULL, it will also return false. + +Reviewed-by: Benoit Canet +Reviewed-by: Eric Blake +Signed-off-by: Jeff Cody +Reviewed-by: Kevin Wolf +Signed-off-by: Stefan Hajnoczi +(cherry picked from commit 5a6684d2b957f9ec75d7ed7b14332293abec1d6c) + +Conflicts: + block.c + include/block/block.h + +Signed-off-by: Jeff Cody +Signed-off-by: Miroslav Rezanina +--- + block.c | 11 +++++++++++ + include/block/block.h | 1 + + 2 files changed, 12 insertions(+), 0 deletions(-) + +diff --git a/block.c b/block.c +index 4906f6b..058255d 100644 +--- a/block.c ++++ b/block.c +@@ -3420,6 +3420,17 @@ BlockDriverState *bdrv_find(const char *name) + return NULL; + } + ++/* If 'base' is in the same chain as 'top', return true. Otherwise, ++ * return false. If either argument is NULL, return false. */ ++bool bdrv_chain_contains(BlockDriverState *top, BlockDriverState *base) ++{ ++ while (top && top != base) { ++ top = top->backing_hd; ++ } ++ ++ return top != NULL; ++} ++ + BlockDriverState *bdrv_next(BlockDriverState *bs) + { + if (!bs) { +diff --git a/include/block/block.h b/include/block/block.h +index 13ef173..972c0e7 100644 +--- a/include/block/block.h ++++ b/include/block/block.h +@@ -361,6 +361,7 @@ void bdrv_lock_medium(BlockDriverState *bs, bool locked); + void bdrv_eject(BlockDriverState *bs, bool eject_flag); + const char *bdrv_get_format_name(BlockDriverState *bs); + BlockDriverState *bdrv_find(const char *name); ++bool bdrv_chain_contains(BlockDriverState *top, BlockDriverState *base); + BlockDriverState *bdrv_next(BlockDriverState *bs); + void bdrv_iterate(void (*it)(void *opaque, BlockDriverState *bs), + void *opaque); +-- +1.7.1 + diff --git a/SOURCES/kvm-block-extend-block-commit-to-accept-a-string-for-the.patch b/SOURCES/kvm-block-extend-block-commit-to-accept-a-string-for-the.patch new file mode 100644 index 0000000..ad3a840 --- /dev/null +++ b/SOURCES/kvm-block-extend-block-commit-to-accept-a-string-for-the.patch @@ -0,0 +1,294 @@ +From c8dda202bd3faf6cdc91834586c8a42ff4a6f762 Mon Sep 17 00:00:00 2001 +From: Jeffrey Cody +Date: Fri, 19 Sep 2014 03:18:57 +0200 +Subject: [PATCH 2/4] block: extend block-commit to accept a string for the backing file + +Message-id: +Patchwork-id: 61311 +O-Subject: [PATCH qemu-kvm-rhev RHEL7.0.z 2/4] block: extend block-commit to accept a string for the backing file +Bugzilla: 1122925 +RH-Acked-by: Kevin Wolf +RH-Acked-by: Eric Blake +RH-Acked-by: Stefan Hajnoczi + +On some image chains, QEMU may not always be able to resolve the +filenames properly, when updating the backing file of an image +after a block commit. + +For instance, certain relative pathnames may fail, or drives may +have been specified originally by file descriptor (e.g. /dev/fd/???), +or a relative protocol pathname may have been used. + +In these instances, QEMU may lack the information to be able to make +the correct choice, but the user or management layer most likely does +have that knowledge. + +With this extension to the block-commit api, the user is able to change +the backing file of the overlay image as part of the block-commit +operation. + +This allows the change to be 'safe', in the sense that if the attempt +to write the overlay image metadata fails, then the block-commit +operation returns failure, without disrupting the guest. + +If the commit top is the active layer, then specifying the backing +file string will be treated as an error (there is no overlay image +to modify in that case). + +If a backing file string is not specified in the command, the backing +file string to use is determined in the same manner as it was +previously. + +Reviewed-by: Eric Blake +Signed-off-by: Jeff Cody +Reviewed-by: Kevin Wolf +Signed-off-by: Stefan Hajnoczi +(cherry picked from commit 54e269009099cdc9483be115f1e12d56ad459c5e) + +Conflicts: + qapi/block-core.json + +RHEL7 Notes: Conflict is due to qapi json being divided into separate + files upstream; downstream in RHEL7 it is still in a single + json file. + +Signed-off-by: Jeff Cody +Signed-off-by: Miroslav Rezanina +--- + block.c | 8 ++++++-- + block/commit.c | 9 ++++++--- + blockdev.c | 8 +++++++- + include/block/block.h | 3 ++- + include/block/block_int.h | 3 ++- + qapi-schema.json | 20 ++++++++++++++++++-- + qmp-commands.hx | 19 ++++++++++++++++++- + 7 files changed, 59 insertions(+), 11 deletions(-) + +diff --git a/block.c b/block.c +index 058255d..d26e9aa 100644 +--- a/block.c ++++ b/block.c +@@ -2319,12 +2319,15 @@ typedef struct BlkIntermediateStates { + * + * base <- active + * ++ * If backing_file_str is non-NULL, it will be used when modifying top's ++ * overlay image metadata. ++ * + * Error conditions: + * if active == top, that is considered an error + * + */ + int bdrv_drop_intermediate(BlockDriverState *active, BlockDriverState *top, +- BlockDriverState *base) ++ BlockDriverState *base, const char *backing_file_str) + { + BlockDriverState *intermediate; + BlockDriverState *base_bs = NULL; +@@ -2376,7 +2379,8 @@ int bdrv_drop_intermediate(BlockDriverState *active, BlockDriverState *top, + } + + /* success - we can delete the intermediate states, and link top->base */ +- ret = bdrv_change_backing_file(new_top_bs, base_bs->filename, ++ backing_file_str = backing_file_str ? backing_file_str : base_bs->filename; ++ ret = bdrv_change_backing_file(new_top_bs, backing_file_str, + base_bs->drv ? base_bs->drv->format_name : ""); + if (ret) { + goto exit; +diff --git a/block/commit.c b/block/commit.c +index e3e395d..b6e1770 100644 +--- a/block/commit.c ++++ b/block/commit.c +@@ -37,6 +37,7 @@ typedef struct CommitBlockJob { + BlockdevOnError on_error; + int base_flags; + int orig_overlay_flags; ++ char *backing_file_str; + } CommitBlockJob; + + static int coroutine_fn commit_populate(BlockDriverState *bs, +@@ -141,7 +142,7 @@ wait: + + if (!block_job_is_cancelled(&s->common) && sector_num == end) { + /* success */ +- ret = bdrv_drop_intermediate(active, top, base); ++ ret = bdrv_drop_intermediate(active, top, base, s->backing_file_str); + } + + exit_free_buf: +@@ -158,7 +159,7 @@ exit_restore_reopen: + if (overlay_bs && s->orig_overlay_flags != bdrv_get_flags(overlay_bs)) { + bdrv_reopen(overlay_bs, s->orig_overlay_flags, NULL); + } +- ++ g_free(s->backing_file_str); + block_job_completed(&s->common, ret); + } + +@@ -182,7 +183,7 @@ static const BlockJobDriver commit_job_driver = { + void commit_start(BlockDriverState *bs, BlockDriverState *base, + BlockDriverState *top, int64_t speed, + BlockdevOnError on_error, BlockDriverCompletionFunc *cb, +- void *opaque, Error **errp) ++ void *opaque, const char *backing_file_str, Error **errp) + { + CommitBlockJob *s; + BlockReopenQueue *reopen_queue = NULL; +@@ -244,6 +245,8 @@ void commit_start(BlockDriverState *bs, BlockDriverState *base, + s->base_flags = orig_base_flags; + s->orig_overlay_flags = orig_overlay_flags; + ++ s->backing_file_str = g_strdup(backing_file_str); ++ + s->on_error = on_error; + s->common.co = qemu_coroutine_create(commit_run); + +diff --git a/blockdev.c b/blockdev.c +index a94c9d3..b22b42e 100644 +--- a/blockdev.c ++++ b/blockdev.c +@@ -1465,6 +1465,7 @@ void qmp_block_stream(const char *device, bool has_base, + void qmp_block_commit(const char *device, + bool has_base, const char *base, + bool has_top, const char *top, ++ bool has_backing_file, const char *backing_file, + bool has_speed, int64_t speed, + Error **errp) + { +@@ -1522,11 +1523,16 @@ void qmp_block_commit(const char *device, + } + + if (top_bs == bs) { ++ if (has_backing_file) { ++ error_setg(errp, "'backing-file' specified," ++ " but 'top' is the active layer"); ++ return; ++ } + commit_active_start(bs, base_bs, speed, on_error, block_job_cb, + bs, &local_err); + } else { + commit_start(bs, base_bs, top_bs, speed, on_error, block_job_cb, bs, +- &local_err); ++ has_backing_file ? backing_file : NULL, &local_err); + } + if (local_err != NULL) { + error_propagate(errp, local_err); +diff --git a/include/block/block.h b/include/block/block.h +index 972c0e7..03b7960 100644 +--- a/include/block/block.h ++++ b/include/block/block.h +@@ -256,7 +256,8 @@ int bdrv_change_backing_file(BlockDriverState *bs, + const char *backing_file, const char *backing_fmt); + void bdrv_register(BlockDriver *bdrv); + int bdrv_drop_intermediate(BlockDriverState *active, BlockDriverState *top, +- BlockDriverState *base); ++ BlockDriverState *base, ++ const char *backing_file_str); + BlockDriverState *bdrv_find_overlay(BlockDriverState *active, + BlockDriverState *bs); + BlockDriverState *bdrv_find_base(BlockDriverState *bs); +diff --git a/include/block/block_int.h b/include/block/block_int.h +index 53fc98c..e6874b4 100644 +--- a/include/block/block_int.h ++++ b/include/block/block_int.h +@@ -389,13 +389,14 @@ void stream_start(BlockDriverState *bs, BlockDriverState *base, + * @on_error: The action to take upon error. + * @cb: Completion function for the job. + * @opaque: Opaque pointer value passed to @cb. ++ * @backing_file_str: String to use as the backing file in @top's overlay + * @errp: Error object. + * + */ + void commit_start(BlockDriverState *bs, BlockDriverState *base, + BlockDriverState *top, int64_t speed, + BlockdevOnError on_error, BlockDriverCompletionFunc *cb, +- void *opaque, Error **errp); ++ void *opaque, const char *backing_file_str, Error **errp); + /** + * commit_active_start: + * @bs: Active block device to be committed. +diff --git a/qapi-schema.json b/qapi-schema.json +index 3768872..100b059 100644 +--- a/qapi-schema.json ++++ b/qapi-schema.json +@@ -1842,6 +1842,23 @@ + # which contains the topmost data to be committed down. If + # not specified, this is the active layer. + # ++# @backing-file: #optional The backing file string to write into the overlay ++# image of 'top'. If 'top' is the active layer, ++# specifying a backing file string is an error. This ++# filename is not validated. ++# ++# If a pathname string is such that it cannot be ++# resolved by QEMU, that means that subsequent QMP or ++# HMP commands must use node-names for the image in ++# question, as filename lookup methods will fail. ++# ++# If not specified, QEMU will automatically determine ++# the backing file string to use, or error out if ++# there is no obvious choice. Care should be taken ++# when specifying the string, to specify a valid ++# filename or protocol. ++# (Since 2.1) ++# + # If top == base, that is an error. + # If top == active, the job will not be completed by itself, + # user needs to complete the job with the block-job-complete +@@ -1854,7 +1871,6 @@ + # size of the smaller top, you can safely truncate it + # yourself once the commit operation successfully completes. + # +-# + # @speed: #optional the maximum speed, in bytes per second + # + # Returns: Nothing on success +@@ -1869,7 +1885,7 @@ + ## + { 'command': 'block-commit', + 'data': { 'device': 'str', '*base': 'str', '*top': 'str', +- '*speed': 'int' } } ++ '*backing-file': 'str', '*speed': 'int' } } + + ## + # @drive-mirror +diff --git a/qmp-commands.hx b/qmp-commands.hx +index b6b6246..79006c5 100644 +--- a/qmp-commands.hx ++++ b/qmp-commands.hx +@@ -1005,7 +1005,7 @@ EQMP + + { + .name = "block-commit", +- .args_type = "device:B,base:s?,top:s?,speed:o?", ++ .args_type = "device:B,base:s?,top:s?,backing-file:s?,speed:o?", + .mhandler.cmd_new = qmp_marshal_input_block_commit, + }, + +@@ -1026,6 +1026,23 @@ Arguments: + which contains the topmost data to be committed down. If + not specified, this is the active layer. (json-string, optional) + ++- backing-file: The backing file string to write into the overlay ++ image of 'top'. If 'top' is the active layer, ++ specifying a backing file string is an error. This ++ filename is not validated. ++ ++ If a pathname string is such that it cannot be ++ resolved by QEMU, that means that subsequent QMP or ++ HMP commands must use node-names for the image in ++ question, as filename lookup methods will fail. ++ ++ If not specified, QEMU will automatically determine ++ the backing file string to use, or error out if ++ there is no obvious choice. Care should be taken ++ when specifying the string, to specify a valid ++ filename or protocol. ++ (json-string, optional) (Since 2.1) ++ + If top == base, that is an error. + If top == active, the job will not be completed by itself, + user needs to complete the job with the block-job-complete +-- +1.7.1 + diff --git a/SOURCES/kvm-scsi-disk-fix-bug-in-scsi_block_new_request-introduc.patch b/SOURCES/kvm-scsi-disk-fix-bug-in-scsi_block_new_request-introduc.patch new file mode 100644 index 0000000..430e321 --- /dev/null +++ b/SOURCES/kvm-scsi-disk-fix-bug-in-scsi_block_new_request-introduc.patch @@ -0,0 +1,46 @@ +From 0eae214c2b36ad2dd2b841c2dc97e1f86a8284c0 Mon Sep 17 00:00:00 2001 +From: Paolo Bonzini +Date: Fri, 12 Sep 2014 11:56:30 +0200 +Subject: [PATCH] scsi-disk: fix bug in scsi_block_new_request() introduced by commit 137745c + +Message-id: <1410522991-11612-1-git-send-email-pbonzini@redhat.com> +Patchwork-id: 61021 +O-Subject: [RHEL 7.1/7.0.z qemu-kvm PATCH] scsi-disk: fix bug in scsi_block_new_request() introduced by commit 137745c +Bugzilla: 1141189 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Fam Zheng + +From: Ulrich Obergfell + +This patch fixes a bug in scsi_block_new_request() that was introduced +by commit 137745c5c60f083ec982fe9e861e8c16ebca1ba8. If the host cache +is used - i.e. if BDRV_O_NOCACHE is _not_ set - the 'break' statement +needs to be executed to 'fall back' to SG_IO. + +Cc: qemu-stable@nongnu.org +Signed-off-by: Ulrich Obergfell +Signed-off-by: Paolo Bonzini +(cherry picked from commit 2fe5a9f73b3446690db2cae8a58473b0b4beaa32) + +Signed-off-by: Miroslav Rezanina +--- + hw/scsi/scsi-disk.c | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c +index 6491091..830e3bd 100644 +--- a/hw/scsi/scsi-disk.c ++++ b/hw/scsi/scsi-disk.c +@@ -2496,7 +2496,7 @@ static SCSIRequest *scsi_block_new_request(SCSIDevice *d, uint32_t tag, + * ones (such as WRITE SAME or EXTENDED COPY, etc.). So, without + * O_DIRECT everything must go through SG_IO. + */ +- if (bdrv_get_flags(s->qdev.conf.bs) & BDRV_O_NOCACHE) { ++ if (!(bdrv_get_flags(s->qdev.conf.bs) & BDRV_O_NOCACHE)) { + break; + } + +-- +1.7.1 + diff --git a/SOURCES/kvm-spice-display-add-display-channel-id-to-the-debug-me.patch b/SOURCES/kvm-spice-display-add-display-channel-id-to-the-debug-me.patch new file mode 100644 index 0000000..7d2b037 --- /dev/null +++ b/SOURCES/kvm-spice-display-add-display-channel-id-to-the-debug-me.patch @@ -0,0 +1,144 @@ +From 21a79d9dab61df3942c13df2a2472182abdb8a7f Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Mon, 15 Sep 2014 13:08:22 +0200 +Subject: [PATCH 5/6] spice-display: add display channel id to the debug messages. + +Message-id: <1410786503-19794-4-git-send-email-kraxel@redhat.com> +Patchwork-id: 61138 +O-Subject: [RHEL-7.1 qemu-kvm PATCH 3/4] spice-display: add display channel id to the debug messages. +Bugzilla: 1139117 +RH-Acked-by: Markus Armbruster +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Laszlo Ersek + +And s/__FUNCTION__/__func__/ while being at it. + +Signed-off-by: Gerd Hoffmann +(cherry picked from commit 35b2122db446a03be9b88f540e865930efd01d6a) + +Signed-off-by: Miroslav Rezanina +--- + ui/spice-display.c | 27 ++++++++++++++------------- + 1 files changed, 14 insertions(+), 13 deletions(-) + +diff --git a/ui/spice-display.c b/ui/spice-display.c +index 82d8b9f..da45282 100644 +--- a/ui/spice-display.c ++++ b/ui/spice-display.c +@@ -297,7 +297,7 @@ void qemu_spice_create_host_memslot(SimpleSpiceDisplay *ssd) + { + QXLDevMemSlot memslot; + +- dprint(1, "%s:\n", __FUNCTION__); ++ dprint(1, "%s/%d:\n", __func__, ssd->qxl.id); + + memset(&memslot, 0, sizeof(memslot)); + memslot.slot_group_id = MEMSLOT_GROUP_HOST; +@@ -311,7 +311,7 @@ void qemu_spice_create_host_primary(SimpleSpiceDisplay *ssd) + + memset(&surface, 0, sizeof(surface)); + +- dprint(1, "%s: %dx%d\n", __FUNCTION__, ++ dprint(1, "%s/%d: %dx%d\n", __func__, ssd->qxl.id, + surface_width(ssd->ds), surface_height(ssd->ds)); + + surface.format = SPICE_SURFACE_FMT_32_xRGB; +@@ -329,7 +329,7 @@ void qemu_spice_create_host_primary(SimpleSpiceDisplay *ssd) + + void qemu_spice_destroy_host_primary(SimpleSpiceDisplay *ssd) + { +- dprint(1, "%s:\n", __FUNCTION__); ++ dprint(1, "%s/%d:\n", __func__, ssd->qxl.id); + + qemu_spice_destroy_primary_surface(ssd, 0, QXL_SYNC); + } +@@ -354,7 +354,8 @@ void qemu_spice_display_update(SimpleSpiceDisplay *ssd, + { + QXLRect update_area; + +- dprint(2, "%s: x %d y %d w %d h %d\n", __FUNCTION__, x, y, w, h); ++ dprint(2, "%s/%d: x %d y %d w %d h %d\n", __func__, ++ ssd->qxl.id, x, y, w, h); + update_area.left = x, + update_area.right = x + w; + update_area.top = y; +@@ -371,7 +372,7 @@ void qemu_spice_display_switch(SimpleSpiceDisplay *ssd, + { + SimpleSpiceUpdate *update; + +- dprint(1, "%s:\n", __FUNCTION__); ++ dprint(1, "%s/%d:\n", __func__, ssd->qxl.id); + + memset(&ssd->dirty, 0, sizeof(ssd->dirty)); + if (ssd->surface) { +@@ -413,7 +414,7 @@ void qemu_spice_cursor_refresh_unlocked(SimpleSpiceDisplay *ssd) + + void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd) + { +- dprint(3, "%s:\n", __func__); ++ dprint(3, "%s/%d:\n", __func__, ssd->qxl.id); + graphic_hw_update(ssd->dcl.con); + + qemu_mutex_lock(&ssd->lock); +@@ -427,7 +428,7 @@ void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd) + if (ssd->notify) { + ssd->notify = 0; + qemu_spice_wakeup(ssd); +- dprint(2, "%s: notify\n", __FUNCTION__); ++ dprint(2, "%s/%d: notify\n", __func__, ssd->qxl.id); + } + } + +@@ -437,19 +438,19 @@ static void interface_attach_worker(QXLInstance *sin, QXLWorker *qxl_worker) + { + SimpleSpiceDisplay *ssd = container_of(sin, SimpleSpiceDisplay, qxl); + +- dprint(1, "%s:\n", __FUNCTION__); ++ dprint(1, "%s/%d:\n", __func__, ssd->qxl.id); + ssd->worker = qxl_worker; + } + + static void interface_set_compression_level(QXLInstance *sin, int level) + { +- dprint(1, "%s:\n", __FUNCTION__); ++ dprint(1, "%s/%d:\n", __func__, sin->id); + /* nothing to do */ + } + + static void interface_set_mm_time(QXLInstance *sin, uint32_t mm_time) + { +- dprint(3, "%s:\n", __FUNCTION__); ++ dprint(3, "%s/%d:\n", __func__, sin->id); + /* nothing to do */ + } + +@@ -472,7 +473,7 @@ static int interface_get_command(QXLInstance *sin, struct QXLCommandExt *ext) + SimpleSpiceUpdate *update; + int ret = false; + +- dprint(3, "%s:\n", __FUNCTION__); ++ dprint(3, "%s/%d:\n", __func__, ssd->qxl.id); + + qemu_mutex_lock(&ssd->lock); + update = QTAILQ_FIRST(&ssd->updates); +@@ -488,7 +489,7 @@ static int interface_get_command(QXLInstance *sin, struct QXLCommandExt *ext) + + static int interface_req_cmd_notification(QXLInstance *sin) + { +- dprint(1, "%s:\n", __FUNCTION__); ++ dprint(1, "%s/%d:\n", __func__, sin->id); + return 1; + } + +@@ -498,7 +499,7 @@ static void interface_release_resource(QXLInstance *sin, + SimpleSpiceDisplay *ssd = container_of(sin, SimpleSpiceDisplay, qxl); + uintptr_t id; + +- dprint(2, "%s:\n", __FUNCTION__); ++ dprint(2, "%s/%d:\n", __func__, ssd->qxl.id); + id = ext.info->id; + qemu_spice_destroy_update(ssd, (void*)id); + } +-- +1.7.1 + diff --git a/SOURCES/kvm-spice-make-sure-we-don-t-overflow-ssd-buf.patch b/SOURCES/kvm-spice-make-sure-we-don-t-overflow-ssd-buf.patch new file mode 100644 index 0000000..54c00c6 --- /dev/null +++ b/SOURCES/kvm-spice-make-sure-we-don-t-overflow-ssd-buf.patch @@ -0,0 +1,90 @@ +From 997ea047468b04f18925ba1309068d69c16bdcc4 Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Mon, 15 Sep 2014 13:08:23 +0200 +Subject: [PATCH 6/6] spice: make sure we don't overflow ssd->buf + +Message-id: <1410786503-19794-5-git-send-email-kraxel@redhat.com> +Patchwork-id: 61136 +O-Subject: [RHEL-7.1 qemu-kvm PATCH 4/4] spice: make sure we don't overflow ssd->buf +Bugzilla: 1139117 +RH-Acked-by: Markus Armbruster +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Laszlo Ersek + +Related spice-only bug. We have a fixed 16 MB buffer here, being +presented to the spice-server as qxl video memory in case spice is +used with a non-qxl card. It's also used with qxl in vga mode. + +When using display resolutions requiring more than 16 MB of memory we +are going to overflow that buffer. In theory the guest can write, +indirectly via spice-server. The spice-server clears the memory after +setting a new video mode though, triggering a segfault in the overflow +case, so qemu crashes before the guest has a chance to do something +evil. + +Fix that by switching to dynamic allocation for the buffer. + +CVE-2014-3615 + +Cc: qemu-stable@nongnu.org +Cc: secalert@redhat.com +Signed-off-by: Gerd Hoffmann +Reviewed-by: Laszlo Ersek +(cherry picked from commit ab9509cceabef28071e41bdfa073083859c949a7) + +Signed-off-by: Miroslav Rezanina +--- + ui/spice-display.c | 20 +++++++++++++++----- + 1 files changed, 15 insertions(+), 5 deletions(-) + +diff --git a/ui/spice-display.c b/ui/spice-display.c +index da45282..dce9c1b 100644 +--- a/ui/spice-display.c ++++ b/ui/spice-display.c +@@ -308,11 +308,23 @@ void qemu_spice_create_host_memslot(SimpleSpiceDisplay *ssd) + void qemu_spice_create_host_primary(SimpleSpiceDisplay *ssd) + { + QXLDevSurfaceCreate surface; ++ uint64_t surface_size; + + memset(&surface, 0, sizeof(surface)); + +- dprint(1, "%s/%d: %dx%d\n", __func__, ssd->qxl.id, +- surface_width(ssd->ds), surface_height(ssd->ds)); ++ surface_size = (uint64_t) surface_width(ssd->ds) * ++ surface_height(ssd->ds) * 4; ++ assert(surface_size > 0); ++ assert(surface_size < INT_MAX); ++ if (ssd->bufsize < surface_size) { ++ ssd->bufsize = surface_size; ++ g_free(ssd->buf); ++ ssd->buf = g_malloc(ssd->bufsize); ++ } ++ ++ dprint(1, "%s/%d: %ux%u (size %" PRIu64 "/%d)\n", __func__, ssd->qxl.id, ++ surface_width(ssd->ds), surface_height(ssd->ds), ++ surface_size, ssd->bufsize); + + surface.format = SPICE_SURFACE_FMT_32_xRGB; + surface.width = surface_width(ssd->ds); +@@ -343,8 +355,6 @@ void qemu_spice_display_init_common(SimpleSpiceDisplay *ssd) + if (ssd->num_surfaces == 0) { + ssd->num_surfaces = 1024; + } +- ssd->bufsize = (16 * 1024 * 1024); +- ssd->buf = g_malloc(ssd->bufsize); + } + + /* display listener callbacks */ +@@ -463,7 +473,7 @@ static void interface_get_init_info(QXLInstance *sin, QXLDevInitInfo *info) + info->num_memslots = NUM_MEMSLOTS; + info->num_memslots_groups = NUM_MEMSLOTS_GROUPS; + info->internal_groupslot_id = 0; +- info->qxl_ram_size = ssd->bufsize; ++ info->qxl_ram_size = 16 * 1024 * 1024; + info->n_surfaces = ssd->num_surfaces; + } + +-- +1.7.1 + diff --git a/SOURCES/kvm-vbe-make-bochs-dispi-interface-return-the-correct-me.patch b/SOURCES/kvm-vbe-make-bochs-dispi-interface-return-the-correct-me.patch new file mode 100644 index 0000000..4e22076 --- /dev/null +++ b/SOURCES/kvm-vbe-make-bochs-dispi-interface-return-the-correct-me.patch @@ -0,0 +1,92 @@ +From 110fded1f5457f5c089f865636119140b2ee1f94 Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Mon, 15 Sep 2014 13:08:20 +0200 +Subject: [PATCH 3/6] vbe: make bochs dispi interface return the correct memory size with qxl + +Message-id: <1410786503-19794-2-git-send-email-kraxel@redhat.com> +Patchwork-id: 61135 +O-Subject: [RHEL-7.1 qemu-kvm PATCH 1/4] vbe: make bochs dispi interface return the correct memory size with qxl +Bugzilla: 1139117 +RH-Acked-by: Markus Armbruster +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Laszlo Ersek + +VgaState->vram_size is the size of the pci bar. In case of qxl not the +whole pci bar can be used as vga framebuffer. Add a new variable +vbe_size to handle that case. By default (if unset) it equals +vram_size, but qxl can set vbe_size to something else. + +This makes sure VBE_DISPI_INDEX_VIDEO_MEMORY_64K returns correct results +and sanity checks are done with the correct size too. + +Cc: qemu-stable@nongnu.org +Signed-off-by: Gerd Hoffmann +Reviewed-by: Laszlo Ersek +(cherry picked from commit 54a85d462447c1cb8a1638578a7fd086350b4d2d) + +Signed-off-by: Miroslav Rezanina +--- + hw/display/qxl.c | 1 + + hw/display/vga.c | 7 +++++-- + hw/display/vga_int.h | 1 + + 3 files changed, 7 insertions(+), 2 deletions(-) + +diff --git a/hw/display/qxl.c b/hw/display/qxl.c +index 4fe4f1b..0ecd64e 100644 +--- a/hw/display/qxl.c ++++ b/hw/display/qxl.c +@@ -2046,6 +2046,7 @@ static int qxl_init_primary(PCIDevice *dev) + + qxl->id = 0; + qxl_init_ramsize(qxl); ++ vga->vbe_size = qxl->vgamem_size; + vga->vram_size_mb = qxl->vga.vram_size >> 20; + vga_common_init(vga); + vga_init(vga, pci_address_space(dev), pci_address_space_io(dev), false); +diff --git a/hw/display/vga.c b/hw/display/vga.c +index 21a108d..d703d90 100644 +--- a/hw/display/vga.c ++++ b/hw/display/vga.c +@@ -613,7 +613,7 @@ uint32_t vbe_ioport_read_data(void *opaque, uint32_t addr) + val = s->vbe_regs[s->vbe_index]; + } + } else if (s->vbe_index == VBE_DISPI_INDEX_VIDEO_MEMORY_64K) { +- val = s->vram_size / (64 * 1024); ++ val = s->vbe_size / (64 * 1024); + } else { + val = 0; + } +@@ -752,7 +752,7 @@ void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val) + line_offset = w >> 1; + else + line_offset = w * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3); +- h = s->vram_size / line_offset; ++ h = s->vbe_size / line_offset; + /* XXX: support weird bochs semantics ? */ + if (h < s->vbe_regs[VBE_DISPI_INDEX_YRES]) + return; +@@ -2290,6 +2290,9 @@ void vga_common_init(VGACommonState *s) + s->vram_size <<= 1; + } + s->vram_size_mb = s->vram_size >> 20; ++ if (!s->vbe_size) { ++ s->vbe_size = s->vram_size; ++ } + + s->is_vbe_vmstate = 1; + memory_region_init_ram(&s->vram, "vga.vram", s->vram_size); +diff --git a/hw/display/vga_int.h b/hw/display/vga_int.h +index 66f9f3c..5a2f466 100644 +--- a/hw/display/vga_int.h ++++ b/hw/display/vga_int.h +@@ -93,6 +93,7 @@ typedef struct VGACommonState { + MemoryRegion vram_vbe; + uint32_t vram_size; + uint32_t vram_size_mb; /* property */ ++ uint32_t vbe_size; + uint32_t latch; + MemoryRegion *chain4_alias; + uint8_t sr_index; +-- +1.7.1 + diff --git a/SOURCES/kvm-vbe-rework-sanity-checks.patch b/SOURCES/kvm-vbe-rework-sanity-checks.patch new file mode 100644 index 0000000..363b703 --- /dev/null +++ b/SOURCES/kvm-vbe-rework-sanity-checks.patch @@ -0,0 +1,247 @@ +From df5995a56f706268a23451204eadb1823a1f93b5 Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Mon, 15 Sep 2014 13:08:21 +0200 +Subject: [PATCH 4/6] vbe: rework sanity checks + +Message-id: <1410786503-19794-3-git-send-email-kraxel@redhat.com> +Patchwork-id: 61137 +O-Subject: [RHEL-7.1 qemu-kvm PATCH 2/4] vbe: rework sanity checks +Bugzilla: 1139117 +RH-Acked-by: Markus Armbruster +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Laszlo Ersek + +Plug a bunch of holes in the bochs dispi interface parameter checking. +Add a function doing verification on all registers. Call that +unconditionally on every register write. That way we should catch +everything, even changing one register affecting the valid range of +another register. + +Some of the holes have been added by commit +e9c6149f6ae6873f14a12eea554925b6aa4c4dec. Before that commit the +maximum possible framebuffer (VBE_DISPI_MAX_XRES * VBE_DISPI_MAX_YRES * +32 bpp) has been smaller than the qemu vga memory (8MB) and the checking +for VBE_DISPI_MAX_XRES + VBE_DISPI_MAX_YRES + VBE_DISPI_MAX_BPP was ok. + +Some of the holes have been there forever, such as +VBE_DISPI_INDEX_X_OFFSET and VBE_DISPI_INDEX_Y_OFFSET register writes +lacking any verification. + +Security impact: + +(1) Guest can make the ui (gtk/vnc/...) use memory rages outside the vga +frame buffer as source -> host memory leak. Memory isn't leaked to +the guest but to the vnc client though. + +(2) Qemu will segfault in case the memory range happens to include +unmapped areas -> Guest can DoS itself. + +The guest can not modify host memory, so I don't think this can be used +by the guest to escape. + +CVE-2014-3615 + +Cc: qemu-stable@nongnu.org +Cc: secalert@redhat.com +Signed-off-by: Gerd Hoffmann +Reviewed-by: Laszlo Ersek +(cherry picked from commit c1b886c45dc70f247300f549dce9833f3fa2def5) + +Signed-off-by: Miroslav Rezanina +--- + hw/display/vga.c | 154 +++++++++++++++++++++++++++++++++--------------------- + 1 files changed, 95 insertions(+), 59 deletions(-) + +diff --git a/hw/display/vga.c b/hw/display/vga.c +index d703d90..de5d63d 100644 +--- a/hw/display/vga.c ++++ b/hw/display/vga.c +@@ -579,6 +579,93 @@ void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val) + } + } + ++/* ++ * Sanity check vbe register writes. ++ * ++ * As we don't have a way to signal errors to the guest in the bochs ++ * dispi interface we'll go adjust the registers to the closest valid ++ * value. ++ */ ++static void vbe_fixup_regs(VGACommonState *s) ++{ ++ uint16_t *r = s->vbe_regs; ++ uint32_t bits, linelength, maxy, offset; ++ ++ if (!(r[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) { ++ /* vbe is turned off -- nothing to do */ ++ return; ++ } ++ ++ /* check depth */ ++ switch (r[VBE_DISPI_INDEX_BPP]) { ++ case 4: ++ case 8: ++ case 16: ++ case 24: ++ case 32: ++ bits = r[VBE_DISPI_INDEX_BPP]; ++ break; ++ case 15: ++ bits = 16; ++ break; ++ default: ++ bits = r[VBE_DISPI_INDEX_BPP] = 8; ++ break; ++ } ++ ++ /* check width */ ++ r[VBE_DISPI_INDEX_XRES] &= ~7u; ++ if (r[VBE_DISPI_INDEX_XRES] == 0) { ++ r[VBE_DISPI_INDEX_XRES] = 8; ++ } ++ if (r[VBE_DISPI_INDEX_XRES] > VBE_DISPI_MAX_XRES) { ++ r[VBE_DISPI_INDEX_XRES] = VBE_DISPI_MAX_XRES; ++ } ++ r[VBE_DISPI_INDEX_VIRT_WIDTH] &= ~7u; ++ if (r[VBE_DISPI_INDEX_VIRT_WIDTH] > VBE_DISPI_MAX_XRES) { ++ r[VBE_DISPI_INDEX_VIRT_WIDTH] = VBE_DISPI_MAX_XRES; ++ } ++ if (r[VBE_DISPI_INDEX_VIRT_WIDTH] < r[VBE_DISPI_INDEX_XRES]) { ++ r[VBE_DISPI_INDEX_VIRT_WIDTH] = r[VBE_DISPI_INDEX_XRES]; ++ } ++ ++ /* check height */ ++ linelength = r[VBE_DISPI_INDEX_VIRT_WIDTH] * bits / 8; ++ maxy = s->vbe_size / linelength; ++ if (r[VBE_DISPI_INDEX_YRES] == 0) { ++ r[VBE_DISPI_INDEX_YRES] = 1; ++ } ++ if (r[VBE_DISPI_INDEX_YRES] > VBE_DISPI_MAX_YRES) { ++ r[VBE_DISPI_INDEX_YRES] = VBE_DISPI_MAX_YRES; ++ } ++ if (r[VBE_DISPI_INDEX_YRES] > maxy) { ++ r[VBE_DISPI_INDEX_YRES] = maxy; ++ } ++ ++ /* check offset */ ++ if (r[VBE_DISPI_INDEX_X_OFFSET] > VBE_DISPI_MAX_XRES) { ++ r[VBE_DISPI_INDEX_X_OFFSET] = VBE_DISPI_MAX_XRES; ++ } ++ if (r[VBE_DISPI_INDEX_Y_OFFSET] > VBE_DISPI_MAX_YRES) { ++ r[VBE_DISPI_INDEX_Y_OFFSET] = VBE_DISPI_MAX_YRES; ++ } ++ offset = r[VBE_DISPI_INDEX_X_OFFSET] * bits / 8; ++ offset += r[VBE_DISPI_INDEX_Y_OFFSET] * linelength; ++ if (offset + r[VBE_DISPI_INDEX_YRES] * linelength > s->vbe_size) { ++ r[VBE_DISPI_INDEX_Y_OFFSET] = 0; ++ offset = r[VBE_DISPI_INDEX_X_OFFSET] * bits / 8; ++ if (offset + r[VBE_DISPI_INDEX_YRES] * linelength > s->vbe_size) { ++ r[VBE_DISPI_INDEX_X_OFFSET] = 0; ++ offset = 0; ++ } ++ } ++ ++ /* update vga state */ ++ r[VBE_DISPI_INDEX_VIRT_HEIGHT] = maxy; ++ s->vbe_line_offset = linelength; ++ s->vbe_start_addr = offset / 4; ++} ++ + static uint32_t vbe_ioport_read_index(void *opaque, uint32_t addr) + { + VGACommonState *s = opaque; +@@ -648,22 +735,13 @@ void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val) + } + break; + case VBE_DISPI_INDEX_XRES: +- if ((val <= VBE_DISPI_MAX_XRES) && ((val & 7) == 0)) { +- s->vbe_regs[s->vbe_index] = val; +- } +- break; + case VBE_DISPI_INDEX_YRES: +- if (val <= VBE_DISPI_MAX_YRES) { +- s->vbe_regs[s->vbe_index] = val; +- } +- break; + case VBE_DISPI_INDEX_BPP: +- if (val == 0) +- val = 8; +- if (val == 4 || val == 8 || val == 15 || +- val == 16 || val == 24 || val == 32) { +- s->vbe_regs[s->vbe_index] = val; +- } ++ case VBE_DISPI_INDEX_VIRT_WIDTH: ++ case VBE_DISPI_INDEX_X_OFFSET: ++ case VBE_DISPI_INDEX_Y_OFFSET: ++ s->vbe_regs[s->vbe_index] = val; ++ vbe_fixup_regs(s); + break; + case VBE_DISPI_INDEX_BANK: + if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) { +@@ -680,19 +758,11 @@ void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val) + !(s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) { + int h, shift_control; + +- s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] = +- s->vbe_regs[VBE_DISPI_INDEX_XRES]; +- s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] = +- s->vbe_regs[VBE_DISPI_INDEX_YRES]; ++ s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] = 0; + s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET] = 0; + s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET] = 0; +- +- if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) +- s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 1; +- else +- s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] * +- ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3); +- s->vbe_start_addr = 0; ++ s->vbe_regs[VBE_DISPI_INDEX_ENABLE] |= VBE_DISPI_ENABLED; ++ vbe_fixup_regs(s); + + /* clear the screen (should be done in BIOS) */ + if (!(val & VBE_DISPI_NOCLEARMEM)) { +@@ -741,40 +811,6 @@ void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val) + s->vbe_regs[s->vbe_index] = val; + vga_update_memory_access(s); + break; +- case VBE_DISPI_INDEX_VIRT_WIDTH: +- { +- int w, h, line_offset; +- +- if (val < s->vbe_regs[VBE_DISPI_INDEX_XRES]) +- return; +- w = val; +- if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) +- line_offset = w >> 1; +- else +- line_offset = w * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3); +- h = s->vbe_size / line_offset; +- /* XXX: support weird bochs semantics ? */ +- if (h < s->vbe_regs[VBE_DISPI_INDEX_YRES]) +- return; +- s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] = w; +- s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] = h; +- s->vbe_line_offset = line_offset; +- } +- break; +- case VBE_DISPI_INDEX_X_OFFSET: +- case VBE_DISPI_INDEX_Y_OFFSET: +- { +- int x; +- s->vbe_regs[s->vbe_index] = val; +- s->vbe_start_addr = s->vbe_line_offset * s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET]; +- x = s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET]; +- if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) +- s->vbe_start_addr += x >> 1; +- else +- s->vbe_start_addr += x * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3); +- s->vbe_start_addr >>= 2; +- } +- break; + default: + break; + } +-- +1.7.1 + diff --git a/SOURCES/kvm-vmstate_xhci_event-bug-compat-with-RHEL-7.0-RHEL-onl.patch b/SOURCES/kvm-vmstate_xhci_event-bug-compat-with-RHEL-7.0-RHEL-onl.patch new file mode 100644 index 0000000..8ed9288 --- /dev/null +++ b/SOURCES/kvm-vmstate_xhci_event-bug-compat-with-RHEL-7.0-RHEL-onl.patch @@ -0,0 +1,144 @@ +From a0a7c88ceec2443192ec27242b176b66f82dd74a Mon Sep 17 00:00:00 2001 +From: Laszlo Ersek +Date: Mon, 1 Sep 2014 13:36:53 +0200 +Subject: [PATCH 2/6] vmstate_xhci_event: bug compat with RHEL-7.0 (RHEL only) + +Message-id: <1409578613-11909-3-git-send-email-lersek@redhat.com> +Patchwork-id: 60782 +O-Subject: [PATCH RHEL-7.0.z/RHEL-7.1.0 qemu-kvm 2/2] vmstate_xhci_event: bug compat with RHEL-7.0 (RHEL only) +Bugzilla: 1145055 +RH-Acked-by: Dr. David Alan Gilbert (git) +RH-Acked-by: Amit Shah +RH-Acked-by: Paolo Bonzini + +The "vmstate_xhci_event.fields" member is a pointer to an array of +VMStateField elements. The unnamed array (of static storage duration) +comes from a compound literal. The previous patch fixed the undefined +behavior by adding a terminator element to this array, but in RHEL-7 we +also need to look into the practical details of that undefined behavior. + +In debug builds (./configure --enable-debug), the compiler places the +"vmstate_xhci_intr.fields" member's unnamed initializer array right after +the "vmstate_xhci_event.fields" member's. This leads to infinite recursion +(see the previous patch for details), but in RHEL-7 we don't ship debug +builds. + +In a normal (optimized, official) build, the layout changes. The +"vmstate_xhci_event.fields" member's unterminated initializer array is +followed by the one of the "vmstate_xhci_slot.fields" member: + + (gdb) print (intptr_t)&vmstate_xhci_event.fields[7] - \ + (intptr_t)&vmstate_xhci_slot.fields[0] + $3 = 0 + +where "vmstate_xhci_slot.fields" is initialized from + + .fields = (VMStateField[]) { + VMSTATE_BOOL(enabled, XHCISlot), + VMSTATE_BOOL(addressed, XHCISlot), + VMSTATE_END_OF_LIST() + } + +The elements of this array are (only relevant members quoted): + + (gdb) print vmstate_xhci_slot.fields[0].offset + $16 = 0 + (gdb) print vmstate_xhci_slot.fields[0].size + $17 = 1 + (gdb) print vmstate_xhci_slot.fields[1].offset + $18 = 1 + (gdb) print vmstate_xhci_slot.fields[1].size + $19 = 1 + +This means that the wire format for "vmstate_xhci_event" will include the +byte at offset 0 and the byte at offset 1 from XHCIEvent, corresponding to +part of the "XHCIEvent.type" member: + + (gdb) print vmstate_xhci_event.fields[0].name + $23 = 0x5555558b12e7 "type" + (gdb) print vmstate_xhci_event.fields[0].offset + $24 = 0 + (gdb) print vmstate_xhci_event.fields[0].size + $25 = 4 + +In order to accommodate these bogus bytes, coming from an unpatched source +side, we introduce two dummy XHCIEvent fields; otherwise the patched +destination would reject the migration stream. + +For the reverse direction, we explicitly set the dummy bytes to the values +that they used to take in an unpatched source, so that when the unpatched +destination deserializes them into part of "XHCIEvent.type", said victim +member still receives a correct value. + +The dummy fields have type uint8_t, not bool. The reason is that +assignment to bool (in xhci_event_pre_save()) would entail conversion to +bool, hence result in values 0 or 1. (See _Bool conversion rules and +.) + +RHEL-only because we control the compiler version and the build flags only +in RHEL. + +This is for CVE-2014-5263. + +Suggested-by: Amit Shah +Suggested-by: Dr. David Alan Gilbert +Suggested-by: Markus Armbruster +Signed-off-by: Laszlo Ersek + +Signed-off-by: Miroslav Rezanina +--- + hw/usb/hcd-xhci.c | 27 ++++++++++++++++++++------- + 1 files changed, 20 insertions(+), 7 deletions(-) + +diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c +index dbdf6b1..9f97167 100644 +--- a/hw/usb/hcd-xhci.c ++++ b/hw/usb/hcd-xhci.c +@@ -420,6 +420,8 @@ typedef struct XHCIEvent { + uint32_t flags; + uint8_t slotid; + uint8_t epid; ++ uint8_t cve_2014_5263_a; ++ uint8_t cve_2014_5263_b; + } XHCIEvent; + + typedef struct XHCIInterrupter { +@@ -3515,17 +3517,28 @@ static const VMStateDescription vmstate_xhci_slot = { + } + }; + ++static void xhci_event_pre_save(void *opaque) ++{ ++ XHCIEvent *s = opaque; ++ ++ s->cve_2014_5263_a = ((uint8_t *)&s->type)[0]; ++ s->cve_2014_5263_b = ((uint8_t *)&s->type)[1]; ++} ++ + static const VMStateDescription vmstate_xhci_event = { + .name = "xhci-event", + .version_id = 1, ++ .pre_save = xhci_event_pre_save, + .fields = (VMStateField[]) { +- VMSTATE_UINT32(type, XHCIEvent), +- VMSTATE_UINT32(ccode, XHCIEvent), +- VMSTATE_UINT64(ptr, XHCIEvent), +- VMSTATE_UINT32(length, XHCIEvent), +- VMSTATE_UINT32(flags, XHCIEvent), +- VMSTATE_UINT8(slotid, XHCIEvent), +- VMSTATE_UINT8(epid, XHCIEvent), ++ VMSTATE_UINT32(type, XHCIEvent), ++ VMSTATE_UINT32(ccode, XHCIEvent), ++ VMSTATE_UINT64(ptr, XHCIEvent), ++ VMSTATE_UINT32(length, XHCIEvent), ++ VMSTATE_UINT32(flags, XHCIEvent), ++ VMSTATE_UINT8(slotid, XHCIEvent), ++ VMSTATE_UINT8(epid, XHCIEvent), ++ VMSTATE_UINT8(cve_2014_5263_a, XHCIEvent), ++ VMSTATE_UINT8(cve_2014_5263_b, XHCIEvent), + VMSTATE_END_OF_LIST() + } + }; +-- +1.7.1 + diff --git a/SOURCES/kvm-vmstate_xhci_event-fix-unterminated-field-list.patch b/SOURCES/kvm-vmstate_xhci_event-fix-unterminated-field-list.patch new file mode 100644 index 0000000..92795b5 --- /dev/null +++ b/SOURCES/kvm-vmstate_xhci_event-fix-unterminated-field-list.patch @@ -0,0 +1,64 @@ +From 41d2d56a0fda46b582eab0845f064ba85c9c2456 Mon Sep 17 00:00:00 2001 +From: Laszlo Ersek +Date: Mon, 1 Sep 2014 13:36:52 +0200 +Subject: [PATCH 1/6] vmstate_xhci_event: fix unterminated field list + +Message-id: <1409578613-11909-2-git-send-email-lersek@redhat.com> +Patchwork-id: 60781 +O-Subject: [PATCH RHEL-7.0.z/RHEL-7.1.0 qemu-kvm 1/2] vmstate_xhci_event: fix unterminated field list +Bugzilla: 1145055 +RH-Acked-by: Amit Shah +RH-Acked-by: Juan Quintela +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Gerd Hoffmann + +"vmstate_xhci_event" was introduced in commit 37352df3 ("xhci: add live +migration support"), and first released in v1.6.0. The field list in this +VMSD is not terminated with the VMSTATE_END_OF_LIST() macro. + +During normal use (ie. migration), the issue is practically invisible, +because the "vmstate_xhci_event" object (with the unterminated field list) +is only ever referenced -- via "vmstate_xhci_intr" -- if xhci_er_full() +returns true, for the "ev_buffer" test. Since that field_exists() check +(apparently) almost always returns false, we almost never traverse +"vmstate_xhci_event" during migration, which hides the bug. + +However, Amit's vmstate checker forces recursion into this VMSD as well, +and the lack of VMSTATE_END_OF_LIST() breaks the field list terminator +check (field->name != NULL) in dump_vmstate_vmsd(). The result is +undefined behavior, which in my case translates to infinite recursion +(because the loop happens to overflow into "vmstate_xhci_intr", which then +links back to "vmstate_xhci_event"). + +Add the missing terminator. + +Signed-off-by: Laszlo Ersek +Reviewed-by: Amit Shah +Reviewed-by: Paolo Bonzini +Cc: qemu-stable@nongnu.org +Signed-off-by: Peter Maydell +(cherry picked from commit 3afca1d6d413592c2b78cf28f52fa24a586d8f56) + +RHEL-7 note: this is for CVE-2014-5263. + +Signed-off-by: Laszlo Ersek +Signed-off-by: Miroslav Rezanina +--- + hw/usb/hcd-xhci.c | 1 + + 1 files changed, 1 insertions(+), 0 deletions(-) + +diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c +index 87ba7af..dbdf6b1 100644 +--- a/hw/usb/hcd-xhci.c ++++ b/hw/usb/hcd-xhci.c +@@ -3526,6 +3526,7 @@ static const VMStateDescription vmstate_xhci_event = { + VMSTATE_UINT32(flags, XHCIEvent), + VMSTATE_UINT8(slotid, XHCIEvent), + VMSTATE_UINT8(epid, XHCIEvent), ++ VMSTATE_END_OF_LIST() + } + }; + +-- +1.7.1 + diff --git a/SPECS/qemu-kvm.spec b/SPECS/qemu-kvm.spec index 52b33ce..5ac5dda 100644 --- a/SPECS/qemu-kvm.spec +++ b/SPECS/qemu-kvm.spec @@ -73,7 +73,7 @@ Obsoletes: %1 < %{obsoletes_version} \ Summary: QEMU is a FAST! processor emulator Name: %{pkgname}%{?pkgsuffix} Version: 1.5.3 -Release: 60%{?dist}.7.0.1 +Release: 60%{?dist}.10 # Epoch because we pushed a qemu-1.0 package. AIUI this can't ever be dropped Epoch: 10 License: GPLv2+ and LGPLv2+ and BSD @@ -2334,6 +2334,28 @@ Patch1139: kvm-block-make-top-argument-to-block-commit-optional.patch Patch1140: kvm-qemu-iotests-Test-0-length-image-for-mirror.patch # For bz#1132806 - advertise active commit to libvirt Patch1141: kvm-mirror-Fix-qiov-size-for-short-requests.patch +# For bz#1145055 - vmstate_xhci_event: fix unterminated field list [rhel-7.0.z] +Patch1142: kvm-vmstate_xhci_event-fix-unterminated-field-list.patch +# For bz#1145055 - vmstate_xhci_event: fix unterminated field list [rhel-7.0.z] +Patch1143: kvm-vmstate_xhci_event-bug-compat-with-RHEL-7.0-RHEL-onl.patch +# For bz#1139117 - CVE-2014-3615 qemu-kvm: Qemu: crash when guest sets high resolution [rhel-7.0.z] +Patch1144: kvm-vbe-make-bochs-dispi-interface-return-the-correct-me.patch +# For bz#1139117 - CVE-2014-3615 qemu-kvm: Qemu: crash when guest sets high resolution [rhel-7.0.z] +Patch1145: kvm-vbe-rework-sanity-checks.patch +# For bz#1139117 - CVE-2014-3615 qemu-kvm: Qemu: crash when guest sets high resolution [rhel-7.0.z] +Patch1146: kvm-spice-display-add-display-channel-id-to-the-debug-me.patch +# For bz#1139117 - CVE-2014-3615 qemu-kvm: Qemu: crash when guest sets high resolution [rhel-7.0.z] +Patch1147: kvm-spice-make-sure-we-don-t-overflow-ssd-buf.patch +# For bz#1141189 - bug in scsi_block_new_request() function introduced by upstream commit 137745c5c60f083ec982fe9e861e8c16ebca1ba8 +Patch1148: kvm-scsi-disk-fix-bug-in-scsi_block_new_request-introduc.patch +# For bz#1122925 - Maintain relative path to backing file image during live merge (block-commit) +Patch1149: kvm-block-add-helper-function-to-determine-if-a-BDS-is-i.patch +# For bz#1122925 - Maintain relative path to backing file image during live merge (block-commit) +Patch1150: kvm-block-extend-block-commit-to-accept-a-string-for-the.patch +# For bz#1122925 - Maintain relative path to backing file image during live merge (block-commit) +Patch1151: kvm-block-add-backing-file-option-to-block-stream.patch +# For bz#1122925 - Maintain relative path to backing file image during live merge (block-commit) +Patch1152: kvm-block-add-__com.redhat_change-backing-file-qmp-comma.patch BuildRequires: zlib-devel @@ -3677,6 +3699,17 @@ cp %{SOURCE18} pc-bios # keep "make check" happy %patch1139 -p1 %patch1140 -p1 %patch1141 -p1 +%patch1142 -p1 +%patch1143 -p1 +%patch1144 -p1 +%patch1145 -p1 +%patch1146 -p1 +%patch1147 -p1 +%patch1148 -p1 +%patch1149 -p1 +%patch1150 -p1 +%patch1151 -p1 +%patch1152 -p1 %build buildarch="%{kvm_target}-softmmu" @@ -4093,8 +4126,30 @@ sh %{_sysconfdir}/sysconfig/modules/kvm.modules &> /dev/null || : %{_libdir}/pkgconfig/libcacard.pc %changelog -* Mon Sep 8 2014 Johnny Hughes - 1.5.3-60.el7_0.7.0.1 -- Rebuild with a newer kernel, no code changes +* Mon Sep 29 2014 Miroslav Rezanina - 1.5.3-60.el7_0.10 +- kvm-block-add-helper-function-to-determine-if-a-BDS-is-i.patch [bz#1122925] +- kvm-block-extend-block-commit-to-accept-a-string-for-the.patch [bz#1122925] +- kvm-block-add-backing-file-option-to-block-stream.patch [bz#1122925] +- kvm-block-add-__com.redhat_change-backing-file-qmp-comma.patch [bz#1122925] +- Resolves: bz#1122925 + (Maintain relative path to backing file image during live merge (block-commit)) + +* Tue Sep 23 2014 Miroslav Rezanina - 1.5.3-60.el7_0.9 +- kvm-scsi-disk-fix-bug-in-scsi_block_new_request-introduc.patch [bz#1141189] +- Resolves: bz#1141189 + (bug in scsi_block_new_request() function introduced by upstream commit 137745c5c60f083ec982fe9e861e8c16ebca1ba8) + +* Mon Sep 22 2014 Miroslav Rezanina - 1.5.3-60.el7_0.8 +- kvm-vmstate_xhci_event-fix-unterminated-field-list.patch [bz#1145055] +- kvm-vmstate_xhci_event-bug-compat-with-RHEL-7.0-RHEL-onl.patch [bz#1145055] +- kvm-vbe-make-bochs-dispi-interface-return-the-correct-me.patch [bz#1139117] +- kvm-vbe-rework-sanity-checks.patch [bz#1139117] +- kvm-spice-display-add-display-channel-id-to-the-debug-me.patch [bz#1139117] +- kvm-spice-make-sure-we-don-t-overflow-ssd-buf.patch [bz#1139117] +- Resolves: bz#1139117 + (CVE-2014-3615 qemu-kvm: Qemu: crash when guest sets high resolution [rhel-7.0.z]) +- Resolves: bz#1145055 + (vmstate_xhci_event: fix unterminated field list [rhel-7.0.z]) * Tue Aug 26 2014 Miroslav Rezanina - 1.5.3-60.el7_0.7 - kvm-mirror-Fix-resource-leak-when-bdrv_getlength-fails.patch [bz#1132806]