summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarkus Armbruster <armbru@redhat.com>2016-04-27 16:29:07 +0200
committerMarkus Armbruster <armbru@redhat.com>2016-04-28 08:18:56 +0200
commit37f32349ea43f41ee8b9a253977ce1e46f576fc7 (patch)
tree4e396a0752ba45512d72a23898c1c3a375b5fa32
parentf419a626c76bcb26697883af702862e8623056f9 (diff)
downloadqemu-37f32349ea43f41ee8b9a253977ce1e46f576fc7.tar.gz
QemuOpts: Fix qemu_opts_foreach() dangling location regression
qemu_opts_foreach() pushes and pops a Location with automatic storage duration. Except it fails to pop when @func() returns non-zero. cur_loc then points to unused stack space, and will most likely get clobbered in short order. Clobbered cur_loc can make loc_pop() and error_print_loc() crash or report bogus locations. Affects several qemu command line options as well as qemu-img, qemu-io, qemu-nbd -object, and blkdebug's configuration file. Broken in commit a4c7367, v2.4.0. Reproducer: $ qemu-system-x86_64 -nodefaults -display none -object secret,id=foo,foo=bar main() reports "Property '.foo' not found" like this: if (qemu_opts_foreach(qemu_find_opts("object"), user_creatable_add_opts_foreach, object_create_delayed, &err)) { error_report_err(err); exit(1); } cur_loc then points to where qemu_opts_foreach()'s Location used to be, i.e. unused stack space. With optimization, this Location doesn't get clobbered for me, and also happens to be the correct location. Without optimization, it does get clobbered in a way that makes error_report_err() report no location. Signed-off-by: Markus Armbruster <armbru@redhat.com> Message-Id: <1461767349-15329-2-git-send-email-armbru@redhat.com> Reviewed-by: Eric Blake <eblake@redhat.com>
-rw-r--r--util/qemu-option.c6
1 files changed, 3 insertions, 3 deletions
diff --git a/util/qemu-option.c b/util/qemu-option.c
index dd9e73df54..3467dc2397 100644
--- a/util/qemu-option.c
+++ b/util/qemu-option.c
@@ -1108,19 +1108,19 @@ int qemu_opts_foreach(QemuOptsList *list, qemu_opts_loopfunc func,
{
Location loc;
QemuOpts *opts;
- int rc;
+ int rc = 0;
loc_push_none(&loc);
QTAILQ_FOREACH(opts, &list->head, next) {
loc_restore(&opts->loc);
rc = func(opaque, opts, errp);
if (rc) {
- return rc;
+ break;
}
assert(!errp || !*errp);
}
loc_pop(&loc);
- return 0;
+ return rc;
}
static size_t count_opts_list(QemuOptsList *list)