mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-12-22 05:35:25 +00:00
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. But this requires being careful that we don't invalidate any storage backends that were relying on key being unassigned during virStoragVolCreateXML[From]. I would have split this into two patches (one for escaping, one for avoiding <key>(null)</key>), but since they both end up touching a lot of the same test files, I ended up merging it into one. 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. * src/storage/storage_driver.c (storageVolCreateXML) (storageVolCreateXMLFrom): Ensure parsed key doesn't confuse volume creation. * 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>
This commit is contained in:
parent
6b90d7428d
commit
6cc4d6a3fe
@ -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>
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
18
tests/storagepoolxml2xmlin/pool-dir-naming.xml
Normal file
18
tests/storagepoolxml2xmlin/pool-dir-naming.xml
Normal file
@ -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>
|
18
tests/storagepoolxml2xmlout/pool-dir-naming.xml
Normal file
18
tests/storagepoolxml2xmlout/pool-dir-naming.xml
Normal file
@ -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>
|
@ -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");
|
||||
|
@ -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>
|
||||
|
20
tests/storagevolxml2xmlin/vol-file-naming.xml
Normal file
20
tests/storagevolxml2xmlin/vol-file-naming.xml
Normal file
@ -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>
|
@ -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>
|
||||
|
17
tests/storagevolxml2xmlout/vol-file-naming.xml
Normal file
17
tests/storagevolxml2xmlout/vol-file-naming.xml
Normal file
@ -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>
|
@ -1,6 +1,5 @@
|
||||
<volume>
|
||||
<name>sparse.img</name>
|
||||
<key>(null)</key>
|
||||
<source>
|
||||
</source>
|
||||
<capacity unit='bytes'>1099511627776</capacity>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -1,6 +1,6 @@
|
||||
<volume>
|
||||
<name>sda1</name>
|
||||
<key>(null)</key>
|
||||
<key>/dev/sda1</key>
|
||||
<source>
|
||||
</source>
|
||||
<capacity unit='bytes'>106896384</capacity>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -1,6 +1,5 @@
|
||||
<volume>
|
||||
<name>test2</name>
|
||||
<key>(null)</key>
|
||||
<source>
|
||||
</source>
|
||||
<capacity unit='bytes'>1024</capacity>
|
||||
|
@ -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");
|
||||
|
Loading…
Reference in New Issue
Block a user