Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
openSUSE:Evergreen:11.2
libvirt
CVE-2010-223x-0003.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File CVE-2010-223x-0003.patch of Package libvirt
>From f8d3e740cee4903bd2eef1a072e8190f5e9e92b9 Mon Sep 17 00:00:00 2001 From: Daniel P. Berrange <berrange@redhat.com> Date: Tue, 15 Jun 2010 14:58:10 +0100 Subject: [PATCH 03/10] Refactor virStorageFileGetMetadataFromFD to separate functionality The virStorageFileGetMetadataFromFD did two jobs in one. First it probed for storage type, then it extracted metadata for the type. It is desirable to be able to separate these jobs, allowing probing without querying metadata, and querying metadata without probing. To prepare for this, split out probing code into a new pair of methods virStorageFileProbeFormatFromFD virStorageFileProbeFormat * src/util/storage_file.c, src/util/storage_file.h, src/libvirt_private.syms: Introduce virStorageFileProbeFormat and virStorageFileProbeFormatFromFD --- src/libvirt_private.syms | 2 + src/util/storage_file.c | 393 ++++++++++++++++++++++++++++++++-------------- src/util/storage_file.h | 4 + 3 files changed, 281 insertions(+), 118 deletions(-) Index: libvirt-0.7.2/src/libvirt_private.syms =================================================================== --- libvirt-0.7.2.orig/src/libvirt_private.syms +++ libvirt-0.7.2/src/libvirt_private.syms @@ -401,6 +401,8 @@ virStorageGenerateQcowPassphrase; # storage_file.h virStorageFileFormatTypeToString; virStorageFileFormatTypeFromString; +virStorageFileProbeFormat; +virStorageFileProbeFormatFromFD; virStorageFileGetMetadata; virStorageFileGetMetadataFromFD; Index: libvirt-0.7.2/src/util/storage_file.c =================================================================== --- libvirt-0.7.2.orig/src/util/storage_file.c +++ libvirt-0.7.2/src/util/storage_file.c @@ -84,8 +84,8 @@ static int vmdk4GetBackingStore(virConne static struct FileTypeInfo const fileTypeInfo[] = { - [VIR_STORAGE_FILE_RAW] = { NULL, NULL, LV_LITTLE_ENDIAN, 0, 0, 0, 0, 0, 0, NULL }, - [VIR_STORAGE_FILE_DIR] = { NULL, NULL, LV_LITTLE_ENDIAN, 0, 0, 0, 0, 0, 0, NULL }, + [VIR_STORAGE_FILE_RAW] = { NULL, NULL, LV_LITTLE_ENDIAN, -1, 0, 0, 0, 0, 0, NULL }, + [VIR_STORAGE_FILE_DIR] = { NULL, NULL, LV_LITTLE_ENDIAN, -1, 0, 0, 0, 0, 0, NULL }, [VIR_STORAGE_FILE_BOCHS] = { /*"Bochs Virtual HD Image", */ /* Untested */ NULL, NULL, @@ -401,147 +401,306 @@ absolutePathFromBaseFile(const char *bas return res; } +static int +virStorageFileMatchesMagic(int format, + unsigned char *buf, + size_t buflen) +{ + int mlen; + + if (fileTypeInfo[format].magic == NULL) + return 0; + + /* Validate magic data */ + mlen = strlen(fileTypeInfo[format].magic); + if (mlen > buflen) + return 0; + + if (memcmp(buf, fileTypeInfo[format].magic, mlen) != 0) + return 0; + + return 1; +} + + +static int +virStorageFileMatchesExtension(int format, + const char *path) +{ + if (fileTypeInfo[format].extension == NULL) + return 0; + + if (virFileHasSuffix(path, fileTypeInfo[format].extension)) + return 1; + + return 0; +} + + +static int +virStorageFileMatchesVersion(int format, + unsigned char *buf, + size_t buflen) +{ + int version; + + /* Validate version number info */ + if (fileTypeInfo[format].versionOffset == -1) + return 0; + + if ((fileTypeInfo[format].versionOffset + 4) > buflen) + return 0; + + if (fileTypeInfo[format].endian == LV_LITTLE_ENDIAN) { + version = + (buf[fileTypeInfo[format].versionOffset+3] << 24) | + (buf[fileTypeInfo[format].versionOffset+2] << 16) | + (buf[fileTypeInfo[format].versionOffset+1] << 8) | + (buf[fileTypeInfo[format].versionOffset]); + } else { + version = + (buf[fileTypeInfo[format].versionOffset] << 24) | + (buf[fileTypeInfo[format].versionOffset+1] << 16) | + (buf[fileTypeInfo[format].versionOffset+2] << 8) | + (buf[fileTypeInfo[format].versionOffset+3]); + } + if (version != fileTypeInfo[format].versionNumber) + return 0; + + return 1; +} + + +static int +virStorageFileGetMetadataFromBuf(virConnectPtr conn, + int format, + const char *path, + unsigned char *buf, + size_t buflen, + virStorageFileMetadata *meta) +{ + /* XXX we should consider moving virStorageBackendUpdateVolInfo + * code into this method, for non-magic files + */ + if (!fileTypeInfo[format].magic) { + return 0; + } + + /* Optionally extract capacity from file */ + if (fileTypeInfo[format].sizeOffset != -1) { + if ((fileTypeInfo[format].sizeOffset + 8) > buflen) + return 1; + + if (fileTypeInfo[format].endian == LV_LITTLE_ENDIAN) { + meta->capacity = + ((unsigned long long)buf[fileTypeInfo[format].sizeOffset+7] << 56) | + ((unsigned long long)buf[fileTypeInfo[format].sizeOffset+6] << 48) | + ((unsigned long long)buf[fileTypeInfo[format].sizeOffset+5] << 40) | + ((unsigned long long)buf[fileTypeInfo[format].sizeOffset+4] << 32) | + ((unsigned long long)buf[fileTypeInfo[format].sizeOffset+3] << 24) | + ((unsigned long long)buf[fileTypeInfo[format].sizeOffset+2] << 16) | + ((unsigned long long)buf[fileTypeInfo[format].sizeOffset+1] << 8) | + ((unsigned long long)buf[fileTypeInfo[format].sizeOffset]); + } else { + meta->capacity = + ((unsigned long long)buf[fileTypeInfo[format].sizeOffset] << 56) | + ((unsigned long long)buf[fileTypeInfo[format].sizeOffset+1] << 48) | + ((unsigned long long)buf[fileTypeInfo[format].sizeOffset+2] << 40) | + ((unsigned long long)buf[fileTypeInfo[format].sizeOffset+3] << 32) | + ((unsigned long long)buf[fileTypeInfo[format].sizeOffset+4] << 24) | + ((unsigned long long)buf[fileTypeInfo[format].sizeOffset+5] << 16) | + ((unsigned long long)buf[fileTypeInfo[format].sizeOffset+6] << 8) | + ((unsigned long long)buf[fileTypeInfo[format].sizeOffset+7]); + } + /* Avoid unlikely, but theoretically possible overflow */ + if (meta->capacity > (ULLONG_MAX / fileTypeInfo[format].sizeMultiplier)) + return 1; + meta->capacity *= fileTypeInfo[format].sizeMultiplier; + } + + if (fileTypeInfo[format].qcowCryptOffset != -1) { + int crypt_format; + + crypt_format = + (buf[fileTypeInfo[format].qcowCryptOffset] << 24) | + (buf[fileTypeInfo[format].qcowCryptOffset+1] << 16) | + (buf[fileTypeInfo[format].qcowCryptOffset+2] << 8) | + (buf[fileTypeInfo[format].qcowCryptOffset+3]); + meta->encrypted = crypt_format != 0; + } + + if (fileTypeInfo[format].getBackingStore != NULL) { + char *backing; + int backingFormat; + int ret = fileTypeInfo[format].getBackingStore(conn, + &backing, + &backingFormat, + buf, buflen); + if (ret == BACKING_STORE_INVALID) + return 1; + + if (ret == BACKING_STORE_ERROR) + return -1; + + if (backing != NULL) { + meta->backingStore = absolutePathFromBaseFile(path, backing); + VIR_FREE(backing); + if (meta->backingStore == NULL) { + virReportOOMError(conn); + return -1; + } + meta->backingStoreFormat = backingFormat; + } else { + meta->backingStore = NULL; + meta->backingStoreFormat = VIR_STORAGE_FILE_AUTO; + } + } + + return 0; +} + + +static int +virStorageFileProbeFormatFromBuf(const char *path, + unsigned char *buf, + size_t buflen) +{ + int format = VIR_STORAGE_FILE_RAW; + int i; + + /* First check file magic */ + for (i = 0 ; i < VIR_STORAGE_FILE_LAST ; i++) { + if (virStorageFileMatchesMagic(i, buf, buflen) && + virStorageFileMatchesVersion(i, buf, buflen)) { + format = i; + goto cleanup; + } + } + + /* No magic, so check file extension */ + for (i = 0 ; i < VIR_STORAGE_FILE_LAST ; i++) { + if (virStorageFileMatchesExtension(i, path)) { + format = i; + goto cleanup; + } + } + +cleanup: + return format; +} /** - * Probe the header of a file to determine what type of disk image - * it is, and info about its capacity if available. + * virStorageFileProbeFormatFromFD: + * + * Probe for the format of 'fd' (which is an open file descriptor + * pointing to 'path'), returning the detected disk format. + * + * Callers are advised never to trust the returned 'format' + * unless it is listed as VIR_STORAGE_FILE_RAW, since a + * malicious guest can turn a file into any other non-raw + * format at will. + * + * Best option: Don't use this function */ int -virStorageFileGetMetadataFromFD(virConnectPtr conn, +virStorageFileProbeFormatFromFD(virConnectPtr conn, const char *path, - int fd, - virStorageFileMetadata *meta) + int fd) { unsigned char head[20*512]; /* vmdk4GetBackingStore needs this much. */ - int len, i; + int len; - /* If all else fails, call it a raw file */ - meta->format = VIR_STORAGE_FILE_RAW; + if (lseek(fd, 0, SEEK_SET) == (off_t)-1) { + virReportSystemError(conn, errno, _("cannot set to start of '%s'"), path); + return -1; + } if ((len = read(fd, head, sizeof(head))) < 0) { virReportSystemError(conn, errno, _("cannot read header '%s'"), path); return -1; } - /* First check file magic */ - for (i = 0 ; i < ARRAY_CARDINALITY(fileTypeInfo) ; i++) { - int mlen; + return virStorageFileProbeFormatFromBuf(path, head, len); +} - if (fileTypeInfo[i].magic == NULL) - continue; +/** + * virStorageFileProbeFormat: + * + * Probe for the format of 'path', returning the detected + * disk format. + * + * Callers are advised never to trust the returned 'format' + * unless it is listed as VIR_STORAGE_FILE_RAW, since a + * malicious guest can turn a file into any other non-raw + * format at will. + * + * Best option: Don't use this function + */ +int +virStorageFileProbeFormat(virConnectPtr conn, const char *path) +{ + int fd, ret; - /* Validate magic data */ - mlen = strlen(fileTypeInfo[i].magic); - if (mlen > len) - continue; - if (memcmp(head, fileTypeInfo[i].magic, mlen) != 0) - continue; - - /* Validate version number info */ - if (fileTypeInfo[i].versionNumber != -1) { - int version; - - if (fileTypeInfo[i].endian == LV_LITTLE_ENDIAN) { - version = (head[fileTypeInfo[i].versionOffset+3] << 24) | - (head[fileTypeInfo[i].versionOffset+2] << 16) | - (head[fileTypeInfo[i].versionOffset+1] << 8) | - head[fileTypeInfo[i].versionOffset]; - } else { - version = (head[fileTypeInfo[i].versionOffset] << 24) | - (head[fileTypeInfo[i].versionOffset+1] << 16) | - (head[fileTypeInfo[i].versionOffset+2] << 8) | - head[fileTypeInfo[i].versionOffset+3]; - } - if (version != fileTypeInfo[i].versionNumber) - continue; - } + if ((fd = open(path, O_RDONLY)) < 0) { + virReportSystemError(conn, errno, _("cannot open file '%s'"), path); + return -1; + } - /* Optionally extract capacity from file */ - if (fileTypeInfo[i].sizeOffset != -1) { - if (fileTypeInfo[i].endian == LV_LITTLE_ENDIAN) { - meta->capacity = - ((unsigned long long)head[fileTypeInfo[i].sizeOffset+7] << 56) | - ((unsigned long long)head[fileTypeInfo[i].sizeOffset+6] << 48) | - ((unsigned long long)head[fileTypeInfo[i].sizeOffset+5] << 40) | - ((unsigned long long)head[fileTypeInfo[i].sizeOffset+4] << 32) | - ((unsigned long long)head[fileTypeInfo[i].sizeOffset+3] << 24) | - ((unsigned long long)head[fileTypeInfo[i].sizeOffset+2] << 16) | - ((unsigned long long)head[fileTypeInfo[i].sizeOffset+1] << 8) | - ((unsigned long long)head[fileTypeInfo[i].sizeOffset]); - } else { - meta->capacity = - ((unsigned long long)head[fileTypeInfo[i].sizeOffset] << 56) | - ((unsigned long long)head[fileTypeInfo[i].sizeOffset+1] << 48) | - ((unsigned long long)head[fileTypeInfo[i].sizeOffset+2] << 40) | - ((unsigned long long)head[fileTypeInfo[i].sizeOffset+3] << 32) | - ((unsigned long long)head[fileTypeInfo[i].sizeOffset+4] << 24) | - ((unsigned long long)head[fileTypeInfo[i].sizeOffset+5] << 16) | - ((unsigned long long)head[fileTypeInfo[i].sizeOffset+6] << 8) | - ((unsigned long long)head[fileTypeInfo[i].sizeOffset+7]); - } - /* Avoid unlikely, but theoretically possible overflow */ - if (meta->capacity > (ULLONG_MAX / fileTypeInfo[i].sizeMultiplier)) - continue; - meta->capacity *= fileTypeInfo[i].sizeMultiplier; - } + ret = virStorageFileProbeFormatFromFD(conn, path, fd); - if (fileTypeInfo[i].qcowCryptOffset != -1) { - int crypt_format; + close(fd); - crypt_format = (head[fileTypeInfo[i].qcowCryptOffset] << 24) | - (head[fileTypeInfo[i].qcowCryptOffset+1] << 16) | - (head[fileTypeInfo[i].qcowCryptOffset+2] << 8) | - head[fileTypeInfo[i].qcowCryptOffset+3]; - meta->encrypted = crypt_format != 0; - } + return ret; +} - /* Validation passed, we know the file format now */ - meta->format = i; - if (fileTypeInfo[i].getBackingStore != NULL) { - char *backing; - int backingFormat; - - switch (fileTypeInfo[i].getBackingStore(conn, &backing, - &backingFormat, - head, len)) { - case BACKING_STORE_OK: - break; +/** + * virStorageFileGetMetadataFromFD: + * + * Probe for the format of 'fd' (which is an open file descriptor + * for the file 'path'), filling 'meta' with the detected + * format and other associated metadata. + * + * Callers are advised never to trust the returned 'meta->format' + * unless it is listed as VIR_STORAGE_FILE_RAW, since a + * malicious guest can turn a file into any other non-raw + * format at will. + */ +int +virStorageFileGetMetadataFromFD(virConnectPtr conn, + const char *path, + int fd, + virStorageFileMetadata *meta) +{ + unsigned char head[20*512]; /* vmdk4GetBackingStore needs this much. */ + int len; - case BACKING_STORE_INVALID: - continue; + memset(meta, 0, sizeof (*meta)); - case BACKING_STORE_ERROR: - return -1; - } - if (backing != NULL) { - meta->backingStore = absolutePathFromBaseFile(path, backing); - VIR_FREE(backing); - if (meta->backingStore == NULL) { - virReportOOMError(conn); - return -1; - } - meta->backingStoreFormat = backingFormat; - } else { - meta->backingStoreFormat = VIR_STORAGE_FILE_AUTO; - } - } - return 0; + if (lseek(fd, 0, SEEK_SET) == (off_t)-1) { + virReportSystemError(conn, errno, _("cannot set to start of '%s'"), path); + return -1; } - /* No magic, so check file extension */ - for (i = 0 ; i < ARRAY_CARDINALITY(fileTypeInfo) ; i++) { - if (fileTypeInfo[i].extension == NULL) - continue; - - if (!virFileHasSuffix(path, fileTypeInfo[i].extension)) - continue; - - meta->format = i; - return 0; + if ((len = read(fd, head, sizeof(head))) < 0) { + virReportSystemError(conn, errno, _("cannot read header '%s'"), path); + return -1; } - return 0; + meta->format = virStorageFileProbeFormatFromBuf(path, head, len); + + return virStorageFileGetMetadataFromBuf(conn, meta->format, path, head, len, meta); } +/** + * virStorageFileGetMetadata: + * + * Probe for the format of 'path', filling 'meta' with the detected + * format and other associated metadata. + * + * Callers are advised never to trust the returned 'meta->format' + * unless it is listed as VIR_STORAGE_FILE_RAW, since a + * malicious guest can turn a file into any other non-raw + * format at will. + */ int virStorageFileGetMetadata(virConnectPtr conn, const char *path, Index: libvirt-0.7.2/src/util/storage_file.h =================================================================== --- libvirt-0.7.2.orig/src/util/storage_file.h +++ libvirt-0.7.2/src/util/storage_file.h @@ -53,6 +53,12 @@ typedef struct _virStorageFileMetadata { bool encrypted; } virStorageFileMetadata; +int virStorageFileProbeFormat(virConnectPtr conn, + const char *path); +int virStorageFileProbeFormatFromFD(virConnectPtr conn, + const char *path, + int fd); + int virStorageFileGetMetadata(virConnectPtr conn, const char *path, virStorageFileMetadata *meta);
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor