storage: Sanitize pool target paths

Spurious / in a pool target path makes life difficult for apps using the
GetVolByPath, and doing other path based comparisons with pools. This
has caused a few issues for virt-manager users:

https://bugzilla.redhat.com/show_bug.cgi?id=494005
https://bugzilla.redhat.com/show_bug.cgi?id=593565

Add a new util API which removes spurious /, virFileSanitizePath. Sanitize
target paths when parsing pool XML, and for paths passed to GetVolByPath.

v2: Leading // must be preserved, properly sanitize path=/, sanitize
    away /./ -> /

v3: Properly handle starting ./ and ending /.

v4: Drop all '.' handling, just sanitize / for now.
This commit is contained in:
Cole Robinson 2010-05-20 11:41:31 -04:00
parent 60881161ea
commit a7fb2258ca
6 changed files with 67 additions and 3 deletions

View File

@ -602,6 +602,7 @@ virStoragePoolDefParseXML(xmlXPathContextPtr ctxt) {
xmlNodePtr source_node;
char *type = NULL;
char *uuid = NULL;
char *tmppath;
if (VIR_ALLOC(ret) < 0) {
virReportOOMError();
@ -699,11 +700,16 @@ virStoragePoolDefParseXML(xmlXPathContextPtr ctxt) {
}
}
if ((ret->target.path = virXPathString("string(./target/path)", ctxt)) == NULL) {
if ((tmppath = virXPathString("string(./target/path)", ctxt)) == NULL) {
virStorageReportError(VIR_ERR_XML_ERROR,
"%s", _("missing storage pool target path"));
goto cleanup;
}
ret->target.path = virFileSanitizePath(tmppath);
VIR_FREE(tmppath);
if (!ret->target.path)
goto cleanup;
if (virStorageDefParsePerms(ctxt, &ret->target.perms,
"./target/permissions", 0700) < 0)

View File

@ -675,6 +675,7 @@ virFileReadLimFD;
virFilePid;
virFileReadPid;
virFileLinkPointsTo;
virFileSanitizePath;
virParseNumber;
virParseVersionString;
virPipeReadUntilEOF;

View File

@ -1204,6 +1204,11 @@ storageVolumeLookupByPath(virConnectPtr conn,
virStorageDriverStatePtr driver = conn->storagePrivateData;
unsigned int i;
virStorageVolPtr ret = NULL;
char *cleanpath;
cleanpath = virFileSanitizePath(path);
if (!cleanpath)
return NULL;
storageDriverLock(driver);
for (i = 0 ; i < driver->pools.count && !ret ; i++) {
@ -1213,7 +1218,7 @@ storageVolumeLookupByPath(virConnectPtr conn,
const char *stable_path;
stable_path = virStorageBackendStablePath(driver->pools.objs[i],
path);
cleanpath);
/*
* virStorageBackendStablePath already does
* virStorageReportError if it fails; we just need to keep
@ -1242,6 +1247,7 @@ storageVolumeLookupByPath(virConnectPtr conn,
"%s", _("no storage vol with matching path"));
cleanup:
VIR_FREE(cleanpath);
storageDriverUnlock(driver);
return ret;
}

View File

@ -1921,6 +1921,55 @@ int virFileAbsPath(const char *path, char **abspath)
return 0;
}
/* Remove spurious / characters from a path. The result must be freed */
char *
virFileSanitizePath(const char *path)
{
const char *cur = path;
char *cleanpath;
int idx = 0;
cleanpath = strdup(path);
if (!cleanpath) {
virReportOOMError();
return NULL;
}
/* Need to sanitize:
* // -> //
* /// -> /
* /../foo -> /../foo
* /foo///bar/ -> /foo/bar
*/
/* Starting with // is valid posix, but ///foo == /foo */
if (cur[0] == '/' && cur[1] == '/' && cur[2] != '/') {
idx = 2;
cur += 2;
}
/* Sanitize path in place */
while (*cur != '\0') {
if (*cur != '/') {
cleanpath[idx++] = *cur++;
continue;
}
/* Skip all extra / */
while (*++cur == '/')
continue;
/* Don't add a trailing / */
if (idx != 0 && *cur == '\0')
break;
cleanpath[idx++] = '/';
}
cleanpath[idx] = '\0';
return cleanpath;
}
/* Like strtol, but produce an "int" result, and check more carefully.
Return 0 upon success; return -1 to indicate failure.
When END_PTR is NULL, the byte after the final valid digit must be NUL.

View File

@ -118,6 +118,8 @@ char *virFindFileInPath(const char *file);
int virFileExists(const char *path);
char *virFileSanitizePath(const char *path);
enum {
VIR_FILE_OP_NONE = 0,
VIR_FILE_OP_AS_UID = (1 << 0),

View File

@ -7,7 +7,7 @@
<source>
</source>
<target>
<path>/var/lib/libvirt/images</path>
<path>///var/////lib/libvirt/images//</path>
<permissions>
<mode>0700</mode>
<owner>0</owner>