From ceb1019257bb339f3ef6bfadd056f7d16eaae95c Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Tue, 23 Jul 2019 22:26:05 -0500 Subject: [PATCH] snapshot: Don't leak moment obj list metaroot to callers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit virDomainSnapshotFindByName(list, NULL) should return NULL, rather than the internal-use-only metaroot. Most existing callers pass in a non-NULL name; the few external callers that don't are immediately calling virDomainMomentSetParent (which indeed needs the metaroot rather than NULL if the parent name is NULL); but as the leaky abstraction is ugly, it is worth instead making virDomainMomentSetParent static and adding a new function for resolving the parent link of a brand new moment within its list. The existing external uses of virDomainMomentSetParent always succeed (either the new moment has parent_name of NULL to become a new root, or has parent_name set to a strdup of the previous current moment); hence, our new function does not need a return value (but it still has a VIR_WARN in case future uses break our assumptions about failure being impossible). Missed when commit 02c4e24d refactored things to attempt to remove direct metaroot manipulations out of the qemu and test drivers into internal-only details, and made more obvious when commit dc8d3dc6 factored it out into a separate file. Signed-off-by: Eric Blake Reviewed-by: Daniel P. Berrangé --- src/conf/virdomainmomentobjlist.c | 34 +++++++++++++++++++++++++---- src/conf/virdomainmomentobjlist.h | 4 ++-- src/conf/virdomainsnapshotobjlist.c | 9 ++++++++ src/conf/virdomainsnapshotobjlist.h | 2 ++ src/libvirt_private.syms | 2 +- src/qemu/qemu_driver.c | 5 +---- src/test/test_driver.c | 5 +---- 7 files changed, 46 insertions(+), 15 deletions(-) diff --git a/src/conf/virdomainmomentobjlist.c b/src/conf/virdomainmomentobjlist.c index 7cb1745525..5c147bdbbf 100644 --- a/src/conf/virdomainmomentobjlist.c +++ b/src/conf/virdomainmomentobjlist.c @@ -151,7 +151,7 @@ virDomainMomentDropChildren(virDomainMomentObjPtr moment) /* Add @moment to @parent's list of children. */ -void +static void virDomainMomentSetParent(virDomainMomentObjPtr moment, virDomainMomentObjPtr parent) { @@ -162,6 +162,27 @@ virDomainMomentSetParent(virDomainMomentObjPtr moment, } +/* Add @moment to the appropriate parent's list of children. The + * caller must ensure that moment->def->parent_name is either NULL + * (for a new root) or set to an existing moment already in the + * list. */ +void +virDomainMomentLinkParent(virDomainMomentObjListPtr moments, + virDomainMomentObjPtr moment) +{ + virDomainMomentObjPtr parent; + + parent = virDomainMomentFindByName(moments, moment->def->parent_name); + if (!parent) { + parent = &moments->metaroot; + if (moment->def->parent_name) + VIR_WARN("moment %s lacks parent %s", moment->def->name, + moment->def->parent_name); + } + virDomainMomentSetParent(moment, parent); +} + + /* Take all children of @from and convert them into children of @to. */ void virDomainMomentMoveChildren(virDomainMomentObjPtr from, @@ -390,7 +411,9 @@ virDomainMomentObjPtr virDomainMomentFindByName(virDomainMomentObjListPtr moments, const char *name) { - return name ? virHashLookup(moments->objs, name) : &moments->metaroot; + if (name) + return virHashLookup(moments->objs, name); + return NULL; } @@ -484,9 +507,12 @@ virDomainMomentSetRelations(void *payload, parent = virDomainMomentFindByName(curr->moments, obj->def->parent_name); if (!parent) { - curr->err = -1; parent = &curr->moments->metaroot; - VIR_WARN("moment %s lacks parent", obj->def->name); + if (obj->def->parent_name) { + curr->err = -1; + VIR_WARN("moment %s lacks parent %s", obj->def->name, + obj->def->parent_name); + } } else { tmp = parent; while (tmp && tmp->def) { diff --git a/src/conf/virdomainmomentobjlist.h b/src/conf/virdomainmomentobjlist.h index 4067e928f4..897d8d54d1 100644 --- a/src/conf/virdomainmomentobjlist.h +++ b/src/conf/virdomainmomentobjlist.h @@ -60,8 +60,8 @@ void virDomainMomentDropParent(virDomainMomentObjPtr moment); void virDomainMomentDropChildren(virDomainMomentObjPtr moment); void virDomainMomentMoveChildren(virDomainMomentObjPtr from, virDomainMomentObjPtr to); -void virDomainMomentSetParent(virDomainMomentObjPtr moment, - virDomainMomentObjPtr parent); +void virDomainMomentLinkParent(virDomainMomentObjListPtr moments, + virDomainMomentObjPtr moment); virDomainMomentObjListPtr virDomainMomentObjListNew(void); void virDomainMomentObjListFree(virDomainMomentObjListPtr moments); diff --git a/src/conf/virdomainsnapshotobjlist.c b/src/conf/virdomainsnapshotobjlist.c index 99bc4bb0c5..95622f0ba7 100644 --- a/src/conf/virdomainsnapshotobjlist.c +++ b/src/conf/virdomainsnapshotobjlist.c @@ -223,6 +223,15 @@ virDomainSnapshotForEach(virDomainSnapshotObjListPtr snapshots, } +/* Populate parent link of a given snapshot. */ +void +virDomainSnapshotLinkParent(virDomainSnapshotObjListPtr snapshots, + virDomainMomentObjPtr snap) +{ + return virDomainMomentLinkParent(snapshots->base, snap); +} + + /* Populate parent link and child count of all snapshots, with all * assigned defs having relations starting as 0/NULL. Return 0 on * success, -1 if a parent is missing or if a circular relationship diff --git a/src/conf/virdomainsnapshotobjlist.h b/src/conf/virdomainsnapshotobjlist.h index fed8d22bc8..b8c80b39ed 100644 --- a/src/conf/virdomainsnapshotobjlist.h +++ b/src/conf/virdomainsnapshotobjlist.h @@ -51,6 +51,8 @@ void virDomainSnapshotObjListRemoveAll(virDomainSnapshotObjListPtr snapshots); int virDomainSnapshotForEach(virDomainSnapshotObjListPtr snapshots, virHashIterator iter, void *data); +void virDomainSnapshotLinkParent(virDomainSnapshotObjListPtr snapshots, + virDomainMomentObjPtr moment); int virDomainSnapshotUpdateRelations(virDomainSnapshotObjListPtr snapshots); int virDomainSnapshotCheckCycles(virDomainSnapshotObjListPtr snapshots, virDomainSnapshotDefPtr def, diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index dff97bd82a..ff5a77b0e2 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -978,7 +978,6 @@ virDomainMomentDropParent; virDomainMomentForEachChild; virDomainMomentForEachDescendant; virDomainMomentMoveChildren; -virDomainMomentSetParent; # conf/virdomainobjlist.h @@ -1007,6 +1006,7 @@ virDomainSnapshotFindByName; virDomainSnapshotForEach; virDomainSnapshotGetCurrent; virDomainSnapshotGetCurrentName; +virDomainSnapshotLinkParent; virDomainSnapshotObjListFree; virDomainSnapshotObjListGetNames; virDomainSnapshotObjListNew; diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 482f915b67..065e0a1bd8 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -15540,7 +15540,6 @@ qemuDomainSnapshotCreateXML(virDomainPtr domain, bool update_current = true; bool redefine = flags & VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE; unsigned int parse_flags = VIR_DOMAIN_SNAPSHOT_PARSE_DISKS; - virDomainMomentObjPtr other = NULL; int align_location = VIR_DOMAIN_SNAPSHOT_LOCATION_INTERNAL; bool align_match = true; virQEMUDriverConfigPtr cfg = NULL; @@ -15807,9 +15806,7 @@ qemuDomainSnapshotCreateXML(virDomainPtr domain, snap->def->name); virDomainSnapshotObjListRemove(vm->snapshots, snap); } else { - other = virDomainSnapshotFindByName(vm->snapshots, - snap->def->parent_name); - virDomainMomentSetParent(snap, other); + virDomainSnapshotLinkParent(vm->snapshots, snap); } } else if (snap) { virDomainSnapshotObjListRemove(vm->snapshots, snap); diff --git a/src/test/test_driver.c b/src/test/test_driver.c index 22b96d435b..56f6b78ecc 100755 --- a/src/test/test_driver.c +++ b/src/test/test_driver.c @@ -7663,12 +7663,9 @@ testDomainSnapshotCreateXML(virDomainPtr domain, cleanup: if (vm) { if (snapshot) { - virDomainMomentObjPtr other; if (update_current) virDomainSnapshotSetCurrent(vm->snapshots, snap); - other = virDomainSnapshotFindByName(vm->snapshots, - snap->def->parent_name); - virDomainMomentSetParent(snap, other); + virDomainSnapshotLinkParent(vm->snapshots, snap); } virDomainObjEndAPI(&vm); }