[libvirt] [PATCH] storage: use valid XML for awkward volume names

$ touch /var/lib/libvirt/images/'a<b>c' $ virsh pool-refresh default $ virsh vol-dumpxml 'a<b>c' default | head -n2 <volume> <name>a<b>c</name> Oops. That's not valid XML. And when we fix the XML generation, it fails RelaxNG validation. I'm also tired of seeing <key>(null)</key> in the example output for volume xml; while we used NULLSTR() to avoid a NULL deref rather than relying on glibc's printf extension behavior, it's even better if we avoid the issue in the first place. Note that this patch allows pretty much any volume name that can appear in a directory (excluding . and .. because those are special), but does nothing to change the current (unenforced) RelaxNG claim that pool names will consist only of letters, numbers, _, -, and +. Tightening the C code to match RelaxNG patterns and/or relaxing the grammar to match the C code for pool names is a task for another day (but remember, we DID recently tighten C code for domain names to exclude a leading '.'). * src/conf/storage_conf.c (virStoragePoolSourceFormat) (virStoragePoolDefFormat, virStorageVolTargetDefFormat) (virStorageVolDefFormat): Escape user-controlled strings. (virStorageVolDefParseXML): Parse key, for use in unit tests. * docs/schemas/basictypes.rng (volName): Relax definition. * tests/storagepoolxml2xmltest.c (mymain): Test it. * tests/storagevolxml2xmltest.c (mymain): Likewise. * tests/storagepoolxml2xmlin/pool-dir-naming.xml: New file. * tests/storagepoolxml2xmlout/pool-dir-naming.xml: Likewise. * tests/storagevolxml2xmlin/vol-file-naming.xml: Likewise. * tests/storagevolxml2xmlout/vol-file-naming.xml: Likewise. * tests/storagevolxml2xmlout/vol-*.xml: Fix fallout. Signed-off-by: Eric Blake <eblake@redhat.com> --- docs/schemas/basictypes.rng | 9 ++- src/conf/storage_conf.c | 72 ++++++++++------------ tests/storagepoolxml2xmlin/pool-dir-naming.xml | 18 ++++++ tests/storagepoolxml2xmlout/pool-dir-naming.xml | 18 ++++++ tests/storagepoolxml2xmltest.c | 1 + tests/storagevolxml2xmlin/vol-file-backing.xml | 1 + tests/storagevolxml2xmlin/vol-file-naming.xml | 20 ++++++ tests/storagevolxml2xmlout/vol-file-backing.xml | 2 +- tests/storagevolxml2xmlout/vol-file-naming.xml | 17 +++++ tests/storagevolxml2xmlout/vol-file.xml | 1 - tests/storagevolxml2xmlout/vol-logical-backing.xml | 2 +- tests/storagevolxml2xmlout/vol-logical.xml | 2 +- tests/storagevolxml2xmlout/vol-partition.xml | 2 +- tests/storagevolxml2xmlout/vol-qcow2-0.10-lazy.xml | 2 +- tests/storagevolxml2xmlout/vol-qcow2-1.1.xml | 2 +- tests/storagevolxml2xmlout/vol-qcow2-lazy.xml | 2 +- tests/storagevolxml2xmlout/vol-qcow2-nobacking.xml | 2 +- tests/storagevolxml2xmlout/vol-qcow2.xml | 2 +- tests/storagevolxml2xmlout/vol-sheepdog.xml | 1 - tests/storagevolxml2xmltest.c | 1 + 20 files changed, 125 insertions(+), 52 deletions(-) create mode 100644 tests/storagepoolxml2xmlin/pool-dir-naming.xml create mode 100644 tests/storagepoolxml2xmlout/pool-dir-naming.xml create mode 100644 tests/storagevolxml2xmlin/vol-file-naming.xml create mode 100644 tests/storagevolxml2xmlout/vol-file-naming.xml diff --git a/docs/schemas/basictypes.rng b/docs/schemas/basictypes.rng index 7fbfa53..268bc5a 100644 --- a/docs/schemas/basictypes.rng +++ b/docs/schemas/basictypes.rng @@ -291,8 +291,15 @@ </define> <define name='volName'> + <!-- directory pools allow almost any file name as a volume name --> <data type='string'> - <param name="pattern">[a-zA-Z0-9_\+\-\.]+</param> + <param name="pattern">[^/]+</param> + <except> + <choice> + <value>.</value> + <value>..</value> + </choice> + </except> </data> </define> diff --git a/src/conf/storage_conf.c b/src/conf/storage_conf.c index 33e4caf..8b378c2 100644 --- a/src/conf/storage_conf.c +++ b/src/conf/storage_conf.c @@ -1056,7 +1056,8 @@ virStoragePoolSourceFormat(virBufferPtr buf, virBufferAddLit(buf, " <source>\n"); if ((options->flags & VIR_STORAGE_POOL_SOURCE_HOST) && src->nhost) { for (i = 0; i < src->nhost; i++) { - virBufferAsprintf(buf, " <host name='%s'", src->hosts[i].name); + virBufferEscapeString(buf, " <host name='%s'", + src->hosts[i].name); if (src->hosts[i].port) virBufferAsprintf(buf, " port='%d'", src->hosts[i].port); virBufferAddLit(buf, "/>\n"); @@ -1067,8 +1068,8 @@ virStoragePoolSourceFormat(virBufferPtr buf, src->ndevice) { for (i = 0; i < src->ndevice; i++) { if (src->devices[i].nfreeExtent) { - virBufferAsprintf(buf, " <device path='%s'>\n", - src->devices[i].path); + virBufferEscapeString(buf, " <device path='%s'>\n", + src->devices[i].path); for (j = 0; j < src->devices[i].nfreeExtent; j++) { virBufferAsprintf(buf, " <freeExtent start='%llu' end='%llu'/>\n", src->devices[i].freeExtents[j].start, @@ -1076,15 +1077,14 @@ virStoragePoolSourceFormat(virBufferPtr buf, } virBufferAddLit(buf, " </device>\n"); } else { - virBufferAsprintf(buf, " <device path='%s'/>\n", - src->devices[i].path); + virBufferEscapeString(buf, " <device path='%s'/>\n", + src->devices[i].path); } } } - if ((options->flags & VIR_STORAGE_POOL_SOURCE_DIR) && - src->dir) - virBufferAsprintf(buf, " <dir path='%s'/>\n", src->dir); + if (options->flags & VIR_STORAGE_POOL_SOURCE_DIR) + virBufferEscapeString(buf, " <dir path='%s'/>\n", src->dir); if ((options->flags & VIR_STORAGE_POOL_SOURCE_ADAPTER)) { if (src->adapter.type == VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_FC_HOST || @@ -1104,9 +1104,8 @@ virStoragePoolSourceFormat(virBufferPtr buf, } } - if ((options->flags & VIR_STORAGE_POOL_SOURCE_NAME) && - src->name) - virBufferAsprintf(buf, " <name>%s</name>\n", src->name); + if (options->flags & VIR_STORAGE_POOL_SOURCE_NAME) + virBufferEscapeString(buf, " <name>%s</name>\n", src->name); if ((options->flags & VIR_STORAGE_POOL_SOURCE_INITIATOR_IQN) && src->initiator.iqn) { @@ -1129,11 +1128,12 @@ virStoragePoolSourceFormat(virBufferPtr buf, if (src->authType == VIR_STORAGE_POOL_AUTH_CHAP || src->authType == VIR_STORAGE_POOL_AUTH_CEPHX) { - virBufferAsprintf(buf, " <auth type='%s' username='%s'>\n", - virStoragePoolAuthTypeTypeToString(src->authType), - (src->authType == VIR_STORAGE_POOL_AUTH_CHAP ? - src->auth.chap.username : - src->auth.cephx.username)); + virBufferAsprintf(buf, " <auth type='%s' ", + virStoragePoolAuthTypeTypeToString(src->authType)); + virBufferEscapeString(buf, "username='%s'>\n", + (src->authType == VIR_STORAGE_POOL_AUTH_CHAP ? + src->auth.chap.username : + src->auth.cephx.username)); virBufferAddLit(buf, " <secret"); if (src->auth.cephx.secret.uuidUsable) { @@ -1149,13 +1149,8 @@ virStoragePoolSourceFormat(virBufferPtr buf, virBufferAddLit(buf, " </auth>\n"); } - if (src->vendor != NULL) { - virBufferEscapeString(buf, " <vendor name='%s'/>\n", src->vendor); - } - - if (src->product != NULL) { - virBufferEscapeString(buf, " <product name='%s'/>\n", src->product); - } + virBufferEscapeString(buf, " <vendor name='%s'/>\n", src->vendor); + virBufferEscapeString(buf, " <product name='%s'/>\n", src->product); virBufferAddLit(buf, " </source>\n"); @@ -1182,7 +1177,7 @@ virStoragePoolDefFormat(virStoragePoolDefPtr def) goto cleanup; } virBufferAsprintf(&buf, "<pool type='%s'>\n", type); - virBufferAsprintf(&buf, " <name>%s</name>\n", def->name); + virBufferEscapeString(&buf, " <name>%s</name>\n", def->name); virUUIDFormat(def->uuid, uuid); virBufferAsprintf(&buf, " <uuid>%s</uuid>\n", uuid); @@ -1203,8 +1198,7 @@ virStoragePoolDefFormat(virStoragePoolDefPtr def) def->type != VIR_STORAGE_POOL_SHEEPDOG) { virBufferAddLit(&buf, " <target>\n"); - if (def->target.path) - virBufferAsprintf(&buf, " <path>%s</path>\n", def->target.path); + virBufferEscapeString(&buf, " <path>%s</path>\n", def->target.path); virBufferAddLit(&buf, " <permissions>\n"); virBufferAsprintf(&buf, " <mode>0%o</mode>\n", @@ -1214,9 +1208,8 @@ virStoragePoolDefFormat(virStoragePoolDefPtr def) virBufferAsprintf(&buf, " <group>%d</group>\n", (int) def->target.perms.gid); - if (def->target.perms.label) - virBufferAsprintf(&buf, " <label>%s</label>\n", - def->target.perms.label); + virBufferEscapeString(&buf, " <label>%s</label>\n", + def->target.perms.label); virBufferAddLit(&buf, " </permissions>\n"); virBufferAddLit(&buf, " </target>\n"); @@ -1282,8 +1275,8 @@ virStorageVolDefParseXML(virStoragePoolDefPtr pool, goto error; } - /* Auto-generated so deliberately ignore */ - /* ret->key = virXPathString("string(./key)", ctxt); */ + /* Normally generated by pool refresh, but useful for unit tests */ + ret->key = virXPathString("string(./key)", ctxt); capacity = virXPathString("string(./capacity)", ctxt); unit = virXPathString("string(./capacity/@unit)", ctxt); @@ -1485,11 +1478,11 @@ static int virStorageVolTargetDefFormat(virStorageVolOptionsPtr options, virBufferPtr buf, virStorageVolTargetPtr def, - const char *type) { + const char *type) +{ virBufferAsprintf(buf, " <%s>\n", type); - if (def->path) - virBufferAsprintf(buf, " <path>%s</path>\n", def->path); + virBufferEscapeString(buf, " <path>%s</path>\n", def->path); if (options->formatToString) { const char *format = (options->formatToString)(def->format); @@ -1511,8 +1504,7 @@ virStorageVolTargetDefFormat(virStorageVolOptionsPtr options, (unsigned int) def->perms.gid); - if (def->perms.label) - virBufferAsprintf(buf, " <label>%s</label>\n", + virBufferEscapeString(buf, " <label>%s</label>\n", def->perms.label); virBufferAddLit(buf, " </permissions>\n"); @@ -1572,8 +1564,8 @@ virStorageVolDefFormat(virStoragePoolDefPtr pool, return NULL; virBufferAddLit(&buf, "<volume>\n"); - virBufferAsprintf(&buf, " <name>%s</name>\n", def->name); - virBufferAsprintf(&buf, " <key>%s</key>\n", NULLSTR(def->key)); + virBufferEscapeString(&buf, " <name>%s</name>\n", def->name); + virBufferEscapeString(&buf, " <key>%s</key>\n", def->key); virBufferAddLit(&buf, " <source>\n"); if (def->source.nextent) { @@ -1585,8 +1577,8 @@ virStorageVolDefFormat(virStoragePoolDefPtr pool, if (thispath != NULL) virBufferAddLit(&buf, " </device>\n"); - virBufferAsprintf(&buf, " <device path='%s'>\n", - def->source.extents[i].path); + virBufferEscapeString(&buf, " <device path='%s'>\n", + def->source.extents[i].path); } virBufferAsprintf(&buf, diff --git a/tests/storagepoolxml2xmlin/pool-dir-naming.xml b/tests/storagepoolxml2xmlin/pool-dir-naming.xml new file mode 100644 index 0000000..aa043be --- /dev/null +++ b/tests/storagepoolxml2xmlin/pool-dir-naming.xml @@ -0,0 +1,18 @@ +<pool type='dir'> + <name>virtimages</name> + <uuid>70a7eb15-6c34-ee9c-bf57-69e8e5ff3fb2</uuid> + <capacity>0</capacity> + <allocation>0</allocation> + <available>0</available> + <source> + </source> + <target> + <path>///var/////lib/libvirt/<images>//</path> + <permissions> + <mode>0700</mode> + <owner>-1</owner> + <group>-1</group> + <label>some_label_t</label> + </permissions> + </target> +</pool> diff --git a/tests/storagepoolxml2xmlout/pool-dir-naming.xml b/tests/storagepoolxml2xmlout/pool-dir-naming.xml new file mode 100644 index 0000000..536f58c --- /dev/null +++ b/tests/storagepoolxml2xmlout/pool-dir-naming.xml @@ -0,0 +1,18 @@ +<pool type='dir'> + <name>virtimages</name> + <uuid>70a7eb15-6c34-ee9c-bf57-69e8e5ff3fb2</uuid> + <capacity unit='bytes'>0</capacity> + <allocation unit='bytes'>0</allocation> + <available unit='bytes'>0</available> + <source> + </source> + <target> + <path>/var/lib/libvirt/<images></path> + <permissions> + <mode>0700</mode> + <owner>-1</owner> + <group>-1</group> + <label>some_label_t</label> + </permissions> + </target> +</pool> diff --git a/tests/storagepoolxml2xmltest.c b/tests/storagepoolxml2xmltest.c index 743e1cb..a81cf99 100644 --- a/tests/storagepoolxml2xmltest.c +++ b/tests/storagepoolxml2xmltest.c @@ -85,6 +85,7 @@ mymain(void) ret = -1 DO_TEST("pool-dir"); + DO_TEST("pool-dir-naming"); DO_TEST("pool-fs"); DO_TEST("pool-logical"); DO_TEST("pool-logical-nopath"); diff --git a/tests/storagevolxml2xmlin/vol-file-backing.xml b/tests/storagevolxml2xmlin/vol-file-backing.xml index d23349e..73e7f28 100644 --- a/tests/storagevolxml2xmlin/vol-file-backing.xml +++ b/tests/storagevolxml2xmlin/vol-file-backing.xml @@ -1,5 +1,6 @@ <volume> <name>sparse.img</name> + <key>/var/lib/libvirt/images/sparse.img</key> <source/> <capacity unit='GB'>10</capacity> <allocation unit='MiB'>0</allocation> diff --git a/tests/storagevolxml2xmlin/vol-file-naming.xml b/tests/storagevolxml2xmlin/vol-file-naming.xml new file mode 100644 index 0000000..9a33e2b --- /dev/null +++ b/tests/storagevolxml2xmlin/vol-file-naming.xml @@ -0,0 +1,20 @@ +<volume> + <name><sparse>.img</name> + <source/> + <capacity unit="TiB">1</capacity> + <allocation unit="bytes">0</allocation> + <target> + <path>/var/lib/libvirt/images/<sparse>.img</path> + <permissions> + <mode>0</mode> + <owner>0744</owner> + <group>0</group> + <label>virt_image_t</label> + </permissions> + <timestamps> + <atime>1341933637.273190990</atime> + <mtime>1341930622.047245868</mtime> + <ctime>1341930622.047245868</ctime> + </timestamps> + </target> +</volume> diff --git a/tests/storagevolxml2xmlout/vol-file-backing.xml b/tests/storagevolxml2xmlout/vol-file-backing.xml index c0f152e..8d2fb57 100644 --- a/tests/storagevolxml2xmlout/vol-file-backing.xml +++ b/tests/storagevolxml2xmlout/vol-file-backing.xml @@ -1,6 +1,6 @@ <volume> <name>sparse.img</name> - <key>(null)</key> + <key>/var/lib/libvirt/images/sparse.img</key> <source> </source> <capacity unit='bytes'>10000000000</capacity> diff --git a/tests/storagevolxml2xmlout/vol-file-naming.xml b/tests/storagevolxml2xmlout/vol-file-naming.xml new file mode 100644 index 0000000..7022b02 --- /dev/null +++ b/tests/storagevolxml2xmlout/vol-file-naming.xml @@ -0,0 +1,17 @@ +<volume> + <name><sparse>.img</name> + <source> + </source> + <capacity unit='bytes'>1099511627776</capacity> + <allocation unit='bytes'>0</allocation> + <target> + <path>/var/lib/libvirt/images/<sparse>.img</path> + <format type='raw'/> + <permissions> + <mode>00</mode> + <owner>744</owner> + <group>0</group> + <label>virt_image_t</label> + </permissions> + </target> +</volume> diff --git a/tests/storagevolxml2xmlout/vol-file.xml b/tests/storagevolxml2xmlout/vol-file.xml index a3d6473..b97dd50 100644 --- a/tests/storagevolxml2xmlout/vol-file.xml +++ b/tests/storagevolxml2xmlout/vol-file.xml @@ -1,6 +1,5 @@ <volume> <name>sparse.img</name> - <key>(null)</key> <source> </source> <capacity unit='bytes'>1099511627776</capacity> diff --git a/tests/storagevolxml2xmlout/vol-logical-backing.xml b/tests/storagevolxml2xmlout/vol-logical-backing.xml index 6b010e3..bf34b08 100644 --- a/tests/storagevolxml2xmlout/vol-logical-backing.xml +++ b/tests/storagevolxml2xmlout/vol-logical-backing.xml @@ -1,6 +1,6 @@ <volume> <name>Swap</name> - <key>(null)</key> + <key>r4xkCv-MQhr-WKIT-R66x-Epn2-e8hG-1Z5gY0</key> <source> </source> <capacity unit='bytes'>2080374784</capacity> diff --git a/tests/storagevolxml2xmlout/vol-logical.xml b/tests/storagevolxml2xmlout/vol-logical.xml index 7bf309e..e9b4e4b 100644 --- a/tests/storagevolxml2xmlout/vol-logical.xml +++ b/tests/storagevolxml2xmlout/vol-logical.xml @@ -1,6 +1,6 @@ <volume> <name>Swap</name> - <key>(null)</key> + <key>r4xkCv-MQhr-WKIT-R66x-Epn2-e8hG-1Z5gY0</key> <source> </source> <capacity unit='bytes'>2080374784</capacity> diff --git a/tests/storagevolxml2xmlout/vol-partition.xml b/tests/storagevolxml2xmlout/vol-partition.xml index 271964f..9be1cf1 100644 --- a/tests/storagevolxml2xmlout/vol-partition.xml +++ b/tests/storagevolxml2xmlout/vol-partition.xml @@ -1,6 +1,6 @@ <volume> <name>sda1</name> - <key>(null)</key> + <key>/dev/sda1</key> <source> </source> <capacity unit='bytes'>106896384</capacity> diff --git a/tests/storagevolxml2xmlout/vol-qcow2-0.10-lazy.xml b/tests/storagevolxml2xmlout/vol-qcow2-0.10-lazy.xml index a7b5fed..fd3d606 100644 --- a/tests/storagevolxml2xmlout/vol-qcow2-0.10-lazy.xml +++ b/tests/storagevolxml2xmlout/vol-qcow2-0.10-lazy.xml @@ -1,6 +1,6 @@ <volume> <name>OtherDemo.img</name> - <key>(null)</key> + <key>/var/lib/libvirt/images/OtherDemo.img</key> <source> </source> <capacity unit='bytes'>5368709120</capacity> diff --git a/tests/storagevolxml2xmlout/vol-qcow2-1.1.xml b/tests/storagevolxml2xmlout/vol-qcow2-1.1.xml index b7df8a6..99fb5ac 100644 --- a/tests/storagevolxml2xmlout/vol-qcow2-1.1.xml +++ b/tests/storagevolxml2xmlout/vol-qcow2-1.1.xml @@ -1,6 +1,6 @@ <volume> <name>OtherDemo.img</name> - <key>(null)</key> + <key>/var/lib/libvirt/images/OtherDemo.img</key> <source> </source> <capacity unit='bytes'>5368709120</capacity> diff --git a/tests/storagevolxml2xmlout/vol-qcow2-lazy.xml b/tests/storagevolxml2xmlout/vol-qcow2-lazy.xml index 92b7875..3708ea7 100644 --- a/tests/storagevolxml2xmlout/vol-qcow2-lazy.xml +++ b/tests/storagevolxml2xmlout/vol-qcow2-lazy.xml @@ -1,6 +1,6 @@ <volume> <name>OtherDemo.img</name> - <key>(null)</key> + <key>/var/lib/libvirt/images/OtherDemo.img</key> <source> </source> <capacity unit='bytes'>5368709120</capacity> diff --git a/tests/storagevolxml2xmlout/vol-qcow2-nobacking.xml b/tests/storagevolxml2xmlout/vol-qcow2-nobacking.xml index e2da702..f6a2e21 100644 --- a/tests/storagevolxml2xmlout/vol-qcow2-nobacking.xml +++ b/tests/storagevolxml2xmlout/vol-qcow2-nobacking.xml @@ -1,6 +1,6 @@ <volume> <name>OtherDemo.img</name> - <key>(null)</key> + <key>/var/lib/libvirt/images/OtherDemo.img</key> <source> </source> <capacity unit='bytes'>5368709120</capacity> diff --git a/tests/storagevolxml2xmlout/vol-qcow2.xml b/tests/storagevolxml2xmlout/vol-qcow2.xml index f931a62..b9adcb4 100644 --- a/tests/storagevolxml2xmlout/vol-qcow2.xml +++ b/tests/storagevolxml2xmlout/vol-qcow2.xml @@ -1,6 +1,6 @@ <volume> <name>OtherDemo.img</name> - <key>(null)</key> + <key>/var/lib/libvirt/images/OtherDemo.img</key> <source> </source> <capacity unit='bytes'>5368709120</capacity> diff --git a/tests/storagevolxml2xmlout/vol-sheepdog.xml b/tests/storagevolxml2xmlout/vol-sheepdog.xml index 2f19af8..bd5d6d8 100644 --- a/tests/storagevolxml2xmlout/vol-sheepdog.xml +++ b/tests/storagevolxml2xmlout/vol-sheepdog.xml @@ -1,6 +1,5 @@ <volume> <name>test2</name> - <key>(null)</key> <source> </source> <capacity unit='bytes'>1024</capacity> diff --git a/tests/storagevolxml2xmltest.c b/tests/storagevolxml2xmltest.c index 1fd01f1..e1db465 100644 --- a/tests/storagevolxml2xmltest.c +++ b/tests/storagevolxml2xmltest.c @@ -110,6 +110,7 @@ mymain(void) while (0); DO_TEST("pool-dir", "vol-file"); + DO_TEST("pool-dir", "vol-file-naming"); DO_TEST("pool-dir", "vol-file-backing"); DO_TEST("pool-dir", "vol-qcow2"); DO_TEST("pool-dir", "vol-qcow2-1.1"); -- 1.8.3.1

On 11/21/2013 03:00 PM, Eric Blake wrote:
$ touch /var/lib/libvirt/images/'a<b>c' $ virsh pool-refresh default $ virsh vol-dumpxml 'a<b>c' default | head -n2 <volume> <name>a<b>c</name>
Oops. That's not valid XML. And when we fix the XML generation, it fails RelaxNG validation.
I'm also tired of seeing <key>(null)</key> in the example output for volume xml; while we used NULLSTR() to avoid a NULL deref rather than relying on glibc's printf extension behavior, it's even better if we avoid the issue in the first place.
Note that this patch allows pretty much any volume name that can appear in a directory (excluding . and .. because those are special), but does nothing to change the current (unenforced) RelaxNG claim that pool names will consist only of letters, numbers, _, -, and +. Tightening the C code to match RelaxNG patterns and/or relaxing the grammar to match the C code for pool names is a task for another day (but remember, we DID recently tighten C code for domain names to exclude a leading '.').
* src/conf/storage_conf.c (virStoragePoolSourceFormat) (virStoragePoolDefFormat, virStorageVolTargetDefFormat) (virStorageVolDefFormat): Escape user-controlled strings. (virStorageVolDefParseXML): Parse key, for use in unit tests. * docs/schemas/basictypes.rng (volName): Relax definition. * tests/storagepoolxml2xmltest.c (mymain): Test it. * tests/storagevolxml2xmltest.c (mymain): Likewise. * tests/storagepoolxml2xmlin/pool-dir-naming.xml: New file. * tests/storagepoolxml2xmlout/pool-dir-naming.xml: Likewise. * tests/storagevolxml2xmlin/vol-file-naming.xml: Likewise. * tests/storagevolxml2xmlout/vol-file-naming.xml: Likewise. * tests/storagevolxml2xmlout/vol-*.xml: Fix fallout.
@@ -1282,8 +1275,8 @@ virStorageVolDefParseXML(virStoragePoolDefPtr pool, goto error; }
- /* Auto-generated so deliberately ignore */ - /* ret->key = virXPathString("string(./key)", ctxt); */ + /* Normally generated by pool refresh, but useful for unit tests */ + ret->key = virXPathString("string(./key)", ctxt);
capacity = virXPathString("string(./capacity)", ctxt); unit = virXPathString("string(./capacity/@unit)", ctxt);
This seems unrelated to the rest of the patch and might affect virStorageBackendDiskCreateVol which doesn't ignore the key. ACK if you drop this hunk or fix virStorageBackendDiskCreateVol. Jan

On 11/21/2013 07:55 AM, Ján Tomko wrote:
On 11/21/2013 03:00 PM, Eric Blake wrote:
$ touch /var/lib/libvirt/images/'a<b>c' $ virsh pool-refresh default $ virsh vol-dumpxml 'a<b>c' default | head -n2 <volume> <name>a<b>c</name>
Oops. That's not valid XML. And when we fix the XML generation, it fails RelaxNG validation.
@@ -1282,8 +1275,8 @@ virStorageVolDefParseXML(virStoragePoolDefPtr pool, goto error; }
- /* Auto-generated so deliberately ignore */ - /* ret->key = virXPathString("string(./key)", ctxt); */ + /* Normally generated by pool refresh, but useful for unit tests */ + ret->key = virXPathString("string(./key)", ctxt);
capacity = virXPathString("string(./capacity)", ctxt); unit = virXPathString("string(./capacity/@unit)", ctxt);
This seems unrelated to the rest of the patch and might affect virStorageBackendDiskCreateVol which doesn't ignore the key.
It's related, in that several of the tests/*out/*.xml files now have a <key> that was parsed from then counterpart *in/*.xml file (whereas they previously had a <key>(null)</key>). Most of the time, we generate volume defs during pool refresh and not from xml reparsing; but you do have a point that on CreateVol, we need to be careful to ignore any input key and use the one that the storage volume would have generated normally; likewise, we must ensure we don't leak memory. I'm still checking...
ACK if you drop this hunk or fix virStorageBackendDiskCreateVol.
I'll reply again with what I squash in after auditing all paths where the user passes in volume XML to make sure we aren't leaking or using the wrong key. -- Eric Blake eblake redhat com +1-919-301-3266 Libvirt virtualization library http://libvirt.org

On 11/21/2013 04:57 PM, Eric Blake wrote:
volume defs during pool refresh and not from xml reparsing; but you do have a point that on CreateVol, we need to be careful to ignore any input key and use the one that the storage volume would have generated normally; likewise, we must ensure we don't leak memory.
I'm still checking...
I verified that the only user XML paths are virStorageVolCreateXML and virStorageVolCreateXMLFrom; and that both paths filter through the storage backend->createVol() before ever attempting to use the key in other locations. So all that remains is auditing each backend's createVol: backend_fs.c always reset key before setting it during createVol; nothing to change. backend_disk.c, on the other hand, enters some code that behaves differently if key is NULL (if so, image is newly created, populate the key) compared to non-NULL (look for matching key - even if user's key was wrong!) so I didn't even bother checking backend_logical, backend_rbd, or backend_sheepdog. Instead:
ACK if you drop this hunk or fix virStorageBackendDiskCreateVol.
I'll reply again with what I squash in after auditing all paths where the user passes in volume XML to make sure we aren't leaking or using the wrong key.
I squashed in this, which avoids the problem for all storage backends. diff --git i/src/storage/storage_driver.c w/src/storage/storage_driver.c index b3f0871..3b4715a 100644 --- i/src/storage/storage_driver.c +++ w/src/storage/storage_driver.c @@ -1554,6 +1554,9 @@ storageVolCreateXML(virStoragePoolPtr obj, goto cleanup; } + /* Wipe any key the user may have suggested, as volume creation + * will generate the canonical key. */ + VIR_FREE(voldef->key); if (backend->createVol(obj->conn, pool, voldef) < 0) { goto cleanup; } @@ -1729,7 +1732,10 @@ storageVolCreateXMLFrom(virStoragePoolPtr obj, pool->volumes.count+1) < 0) goto cleanup; - /* 'Define' the new volume so we get async progress reporting */ + /* 'Define' the new volume so we get async progress reporting. + * Wipe any key the user may have suggested, as volume creation + * will generate the canonical key. */ + VIR_FREE(newvol->key); if (backend->createVol(obj->conn, pool, newvol) < 0) { goto cleanup; } -- Eric Blake eblake redhat com +1-919-301-3266 Libvirt virtualization library http://libvirt.org
participants (2)
-
Eric Blake
-
Ján Tomko