[libvirt] [PATCH 00/11] CVE: Multiple flaws in disk handling

This patch series attempts to fix 3 security flaws in the handling of virtual disk formats. This is just another occurrance of the problem previously identified in Xen https://www.redhat.com/security/data/cve/CVE-2008-2004.html In essence, if a guest is configured with a disk, hda, backed in the host by a plain file, then admin in the guest OS can run 'qemu-img -f qcow2 /dev/hda' to write a qcow2 header into the disk. If the host OS ever probes the backing file to identify its format, then it will see it as a qcow2 file now, instead of the expected raw. In QEMU this problem is addressed in two ways - When configuring a guest with -drive, always set format=raw|qcow2|etc Libvirt will always set this when <driver type='raw|qcow2|etc'> is set for a disk. - When creating a qcow2 guest, always set an explicit backing store format with -o backing_store_format=raw|qcow2|etc or -F raw|qcow2|etc. Libvirt will always set this when a <format type='raw|qcow2'/> is set for a volume backing store Despite having support for these QEMU features to prevent probing, there are flaws in the way libvirt handles disks in various places. - In the security drivers (SELinux, CGroups, DAC) when labelling files on the host, instead of looking at the <driver type='raw|qcow2'/> in the XML to identify the disk format, libvirt probes the file for magic data. Thus even if the app has taken the care to set an explicit format, for all disks, libvirt can be tricked into setting security labels on files that it shouldn't. If the guest OS somehow manages to break out and compromise QEMU it can take advantage of this labelling flaw to access files it shouldn't. - In the security drivers (SELinux, CGroups, DAC) when labelling the backing store for files on the host, instead of looking at embedded backing store format in the master disk image, libvirt probes magic data. Thus even if the app has taken the care to set an explicit format, for all disk backing stores, libvirt can be tricked into setting security labels on files that it shouldn't. If the guest OS somehow manages to break out and compromise QEMU it can take advantage of this labelling flaw to access files it shouldn't. - In the storage driver that creates qcow2 files, the backing store format is only set explicitly if the kvm-img binary is found. Any users with just a qemu-img binary will not have the backing store format set, even if qemu-img supports this capability. As a general matter of policy, libvirt does not mandate use of the <driver type='raw|qcow2'/> tag in the XML for disks, and if omitted will allow QEMU to probe disk formats. This is a weak default policy. If no explicit driver is set, libvirt should presume raw, since that is the only safe option. It should require a host level configuration option for the QEMU driver, to allow probing to be used. This patch series addresses all three of the security flaws, and also changes the default QEMU driver policy to disable all disk format probing out of the box. This latter change will break some existing deployments, so it is possible to turn it off in qemu.conf. The changes required significant re-factoring of the util/storage_file.c code and centralizes all processing of disk backing stores to minimise the risk of mistakes. There are also 5 additional test cases to the TCK, 3 to verify the security flaws, and 2 to verify that libvirtd is configured to disallow disk format probing. The file based storage pool needs to report the format of every volume in the pool. There is no way todo this other than to probe the volume metadata. Unfortunately if an application like virt-manager directly copies the <format> from the storage volume XML, straight into the <driver type=> of the guest disk, all our work to avoid the security problems is potentially null & void. NB, this is only a problem if re-using a pre-existing storage volume. If creating a new storage vol when provisioning a guest / hotplugging a disk, virt-manager can trust the storage volume format. I think we need to advise applications that when picking a pre-existing storage volume from a pool, they must not trust the volume format, and must confirm with the user whether to use the probed format, or force to raw The CVEs are https://bugzilla.redhat.com/show_bug.cgi?id=CVE-2010-2237 https://bugzilla.redhat.com/show_bug.cgi?id=CVE-2010-2238 https://bugzilla.redhat.com/show_bug.cgi?id=CVE-2010-2239 In addition, this patch series fixes the problem of mutually recursive backing stores which would cause an infinite loop in libvirtd. Regards, Daniel

When QEMU opens a backing store for a QCow2 file, it will normally auto-probe for the format of the backing store, rather than assuming it has the same format as the referencing file. There is a QCow2 extension that allows an explicit format for the backing store to be embedded in the referencing file. This closes the auto-probing security hole in QEMU. This backing store format can be useful for libvirt users of virStorageFileGetMetadata, so extract this data and report it. QEMU does not require disk image backing store files to be in the same format the file linkee. It will auto-probe the disk format for the backing store when opening it. If the backing store was intended to be a raw file this could be a security hole, because a guest may have written data into its disk that then makes the backing store look like a qcow2 file. If it can trick QEMU into thinking the raw file is a qcow2 file, it can access arbitrary files on the host by adding further backing store links. To address this, callers of virStorageFileGetMeta need to be told of the backing store format. If no format is declared, they can make a decision whether to allow format probing or not. --- src/util/storage_file.c | 206 +++++++++++++++++++++++++++++++++++++++++------ src/util/storage_file.h | 2 + 2 files changed, 183 insertions(+), 25 deletions(-) diff --git a/src/util/storage_file.c b/src/util/storage_file.c index 0adea40..80f743e 100644 --- a/src/util/storage_file.c +++ b/src/util/storage_file.c @@ -78,12 +78,33 @@ struct FileTypeInfo { int qcowCryptOffset; /* Byte offset from start of file * where to find encryption mode, * -1 if encryption is not used */ - int (*getBackingStore)(char **res, const unsigned char *buf, size_t buf_size); + int (*getBackingStore)(char **res, int *format, + const unsigned char *buf, size_t buf_size); }; -static int cowGetBackingStore(char **, const unsigned char *, size_t); -static int qcowXGetBackingStore(char **, const unsigned char *, size_t); -static int vmdk4GetBackingStore(char **, const unsigned char *, size_t); +static int cowGetBackingStore(char **, int *, + const unsigned char *, size_t); +static int qcow1GetBackingStore(char **, int *, + const unsigned char *, size_t); +static int qcow2GetBackingStore(char **, int *, + const unsigned char *, size_t); +static int vmdk4GetBackingStore(char **, int *, + const unsigned char *, size_t); + +#define QCOWX_HDR_VERSION (4) +#define QCOWX_HDR_BACKING_FILE_OFFSET (QCOWX_HDR_VERSION+4) +#define QCOWX_HDR_BACKING_FILE_SIZE (QCOWX_HDR_BACKING_FILE_OFFSET+8) +#define QCOWX_HDR_IMAGE_SIZE (QCOWX_HDR_BACKING_FILE_SIZE+4+4) + +#define QCOW1_HDR_CRYPT (QCOWX_HDR_IMAGE_SIZE+8+1+1) +#define QCOW2_HDR_CRYPT (QCOWX_HDR_IMAGE_SIZE+8) + +#define QCOW1_HDR_TOTAL_SIZE (QCOW1_HDR_CRYPT+4+8) +#define QCOW2_HDR_TOTAL_SIZE (QCOW2_HDR_CRYPT+4+4+8+8+4+4+8) + +#define QCOW2_HDR_EXTENSION_END 0 +#define QCOW2_HDR_EXTENSION_BACKING_FORMAT 0xE2792ACA + static struct FileTypeInfo const fileTypeInfo[] = { @@ -119,11 +140,11 @@ static struct FileTypeInfo const fileTypeInfo[] = { /* QCow */ { VIR_STORAGE_FILE_QCOW, "QFI", NULL, LV_BIG_ENDIAN, 4, 1, - 4+4+8+4+4, 8, 1, 4+4+8+4+4+8+1+1+2, qcowXGetBackingStore }, + QCOWX_HDR_IMAGE_SIZE, 8, 1, QCOW1_HDR_CRYPT, qcow1GetBackingStore }, /* QCow 2 */ { VIR_STORAGE_FILE_QCOW2, "QFI", NULL, LV_BIG_ENDIAN, 4, 2, - 4+4+8+4+4, 8, 1, 4+4+8+4+4+8, qcowXGetBackingStore }, + QCOWX_HDR_IMAGE_SIZE, 8, 1, QCOW2_HDR_CRYPT, qcow2GetBackingStore }, /* VMDK 3 */ /* XXX Untested { VIR_STORAGE_FILE_VMDK, "COWD", NULL, @@ -142,11 +163,14 @@ static struct FileTypeInfo const fileTypeInfo[] = { static int cowGetBackingStore(char **res, + int *format, const unsigned char *buf, size_t buf_size) { #define COW_FILENAME_MAXLEN 1024 *res = NULL; + *format = VIR_STORAGE_FILE_AUTO; + if (buf_size < 4+4+ COW_FILENAME_MAXLEN) return BACKING_STORE_INVALID; if (buf[4+4] == '\0') /* cow_header_v2.backing_file[0] */ @@ -160,31 +184,98 @@ cowGetBackingStore(char **res, return BACKING_STORE_OK; } + +static int +qcow2GetBackingStoreFormat(int *format, + const unsigned char *buf, + size_t buf_size, + size_t extension_start, + size_t extension_end) +{ + size_t offset = extension_start; + + /* + * The extensions take format of + * + * int32: magic + * int32: length + * byte[length]: payload + * + * Unknown extensions can be ignored by skipping + * over "length" bytes in the data stream. + */ + while (offset < (buf_size-8) && + offset < (extension_end-8)) { + unsigned int magic = + (buf[offset] << 24) + + (buf[offset+1] << 16) + + (buf[offset+2] << 8) + + (buf[offset+3]); + unsigned int len = + (buf[offset+4] << 24) + + (buf[offset+5] << 16) + + (buf[offset+6] << 8) + + (buf[offset+7]); + + offset += 8; + + if ((offset + len) < offset) + break; + + if ((offset + len) > buf_size) + break; + + switch (magic) { + case QCOW2_HDR_EXTENSION_END: + goto done; + + case QCOW2_HDR_EXTENSION_BACKING_FORMAT: + if (buf[offset+len] != '\0') + break; + *format = virStorageFileFormatTypeFromString( + ((const char *)buf)+offset); + break; + } + + offset += len; + } + +done: + + return 0; +} + + static int qcowXGetBackingStore(char **res, + int *format, const unsigned char *buf, - size_t buf_size) + size_t buf_size, + bool isQCow2) { unsigned long long offset; unsigned long size; *res = NULL; - if (buf_size < 4+4+8+4) + if (format) + *format = VIR_STORAGE_FILE_AUTO; + + if (buf_size < QCOWX_HDR_BACKING_FILE_OFFSET+8+4) return BACKING_STORE_INVALID; - offset = (((unsigned long long)buf[4+4] << 56) - | ((unsigned long long)buf[4+4+1] << 48) - | ((unsigned long long)buf[4+4+2] << 40) - | ((unsigned long long)buf[4+4+3] << 32) - | ((unsigned long long)buf[4+4+4] << 24) - | ((unsigned long long)buf[4+4+5] << 16) - | ((unsigned long long)buf[4+4+6] << 8) - | buf[4+4+7]); /* QCowHeader.backing_file_offset */ + offset = (((unsigned long long)buf[QCOWX_HDR_BACKING_FILE_OFFSET] << 56) + | ((unsigned long long)buf[QCOWX_HDR_BACKING_FILE_OFFSET+1] << 48) + | ((unsigned long long)buf[QCOWX_HDR_BACKING_FILE_OFFSET+2] << 40) + | ((unsigned long long)buf[QCOWX_HDR_BACKING_FILE_OFFSET+3] << 32) + | ((unsigned long long)buf[QCOWX_HDR_BACKING_FILE_OFFSET+4] << 24) + | ((unsigned long long)buf[QCOWX_HDR_BACKING_FILE_OFFSET+5] << 16) + | ((unsigned long long)buf[QCOWX_HDR_BACKING_FILE_OFFSET+6] << 8) + | buf[QCOWX_HDR_BACKING_FILE_OFFSET+7]); /* QCowHeader.backing_file_offset */ if (offset > buf_size) return BACKING_STORE_INVALID; - size = ((buf[4+4+8] << 24) - | (buf[4+4+8+1] << 16) - | (buf[4+4+8+2] << 8) - | buf[4+4+8+3]); /* QCowHeader.backing_file_size */ + size = ((buf[QCOWX_HDR_BACKING_FILE_SIZE] << 24) + | (buf[QCOWX_HDR_BACKING_FILE_SIZE+1] << 16) + | (buf[QCOWX_HDR_BACKING_FILE_SIZE+2] << 8) + | buf[QCOWX_HDR_BACKING_FILE_SIZE+3]); /* QCowHeader.backing_file_size */ if (size == 0) return BACKING_STORE_OK; if (offset + size > buf_size || offset + size < offset) @@ -197,12 +288,63 @@ qcowXGetBackingStore(char **res, } memcpy(*res, buf + offset, size); (*res)[size] = '\0'; + + /* + * Traditionally QCow2 files had a layout of + * + * [header] + * [backingStoreName] + * + * Although the backingStoreName typically followed + * the header immediately, this was not required by + * the format. By specifying a higher byte offset for + * the backing file offset in the header, it was + * possible to leave space between the header and + * start of backingStore. + * + * This hack is now used to store extensions to the + * qcow2 format: + * + * [header] + * [extensions] + * [backingStoreName] + * + * Thus the file region to search for extensions is + * between the end of the header (QCOW2_HDR_TOTAL_SIZE) + * and the start of the backingStoreName (offset) + */ + if (isQCow2) + qcow2GetBackingStoreFormat(format, buf, buf_size, QCOW2_HDR_TOTAL_SIZE, offset); + return BACKING_STORE_OK; } static int +qcow1GetBackingStore(char **res, + int *format, + const unsigned char *buf, + size_t buf_size) +{ + /* QCow1 doesn't have the extensions capability + * used to store backing format */ + *format = VIR_STORAGE_FILE_AUTO; + return qcowXGetBackingStore(res, NULL, buf, buf_size, false); +} + +static int +qcow2GetBackingStore(char **res, + int *format, + const unsigned char *buf, + size_t buf_size) +{ + return qcowXGetBackingStore(res, format, buf, buf_size, true); +} + + +static int vmdk4GetBackingStore(char **res, + int *format, const unsigned char *buf, size_t buf_size) { @@ -212,6 +354,14 @@ vmdk4GetBackingStore(char **res, size_t len; *res = NULL; + /* + * Technically this should have been VMDK, since + * VMDK spec / VMWare impl only support VMDK backed + * by VMDK. QEMU isn't following this though and + * does probing on VMDK backing files, hence we set + * AUTO + */ + *format = VIR_STORAGE_FILE_AUTO; if (buf_size <= 0x200) return BACKING_STORE_INVALID; @@ -358,9 +508,12 @@ virStorageFileGetMetadataFromFD(const char *path, /* Validation passed, we know the file format now */ meta->format = fileTypeInfo[i].type; if (fileTypeInfo[i].getBackingStore != NULL) { - char *base; + char *backing; + int backingFormat; - switch (fileTypeInfo[i].getBackingStore(&base, head, len)) { + switch (fileTypeInfo[i].getBackingStore(&backing, + &backingFormat, + head, len)) { case BACKING_STORE_OK: break; @@ -370,13 +523,16 @@ virStorageFileGetMetadataFromFD(const char *path, case BACKING_STORE_ERROR: return -1; } - if (base != NULL) { - meta->backingStore = absolutePathFromBaseFile(path, base); - VIR_FREE(base); + if (backing != NULL) { + meta->backingStore = absolutePathFromBaseFile(path, backing); + VIR_FREE(backing); if (meta->backingStore == NULL) { virReportOOMError(); return -1; } + meta->backingStoreFormat = backingFormat; + } else { + meta->backingStoreFormat = VIR_STORAGE_FILE_AUTO; } } return 0; diff --git a/src/util/storage_file.h b/src/util/storage_file.h index 58533ee..6328ba7 100644 --- a/src/util/storage_file.h +++ b/src/util/storage_file.h @@ -28,6 +28,7 @@ # include <stdbool.h> enum virStorageFileFormat { + VIR_STORAGE_FILE_AUTO = -1, VIR_STORAGE_FILE_RAW = 0, VIR_STORAGE_FILE_DIR, VIR_STORAGE_FILE_BOCHS, @@ -47,6 +48,7 @@ VIR_ENUM_DECL(virStorageFileFormat); typedef struct _virStorageFileMetadata { int format; char *backingStore; + int backingStoreFormat; unsigned long long capacity; bool encrypted; } virStorageFileMetadata; -- 1.7.1.1

On Mon, Jul 12, 2010 at 02:30:38PM +0100, Daniel P. Berrange wrote:
When QEMU opens a backing store for a QCow2 file, it will normally auto-probe for the format of the backing store, rather than assuming it has the same format as the referencing file. There is a QCow2 extension that allows an explicit format for the backing store to be embedded in the referencing file. This closes the auto-probing security hole in QEMU.
This backing store format can be useful for libvirt users of virStorageFileGetMetadata, so extract this data and report it.
QEMU does not require disk image backing store files to be in the same format the file linkee. It will auto-probe the disk format for the backing store when opening it. If the backing store was intended to be a raw file this could be a security hole, because a guest may have written data into its disk that then makes the backing store look like a qcow2 file. If it can trick QEMU into thinking the raw file is a qcow2 file, it can access arbitrary files on the host by adding further backing store links.
To address this, callers of virStorageFileGetMeta need to be told of the backing store format. If no format is declared, they can make a decision whether to allow format probing or not. --- src/util/storage_file.c | 206 +++++++++++++++++++++++++++++++++++++++++------ src/util/storage_file.h | 2 + 2 files changed, 183 insertions(+), 25 deletions(-)
diff --git a/src/util/storage_file.c b/src/util/storage_file.c index 0adea40..80f743e 100644 --- a/src/util/storage_file.c +++ b/src/util/storage_file.c @@ -78,12 +78,33 @@ struct FileTypeInfo { int qcowCryptOffset; /* Byte offset from start of file * where to find encryption mode, * -1 if encryption is not used */ - int (*getBackingStore)(char **res, const unsigned char *buf, size_t buf_size); + int (*getBackingStore)(char **res, int *format, + const unsigned char *buf, size_t buf_size); };
-static int cowGetBackingStore(char **, const unsigned char *, size_t); -static int qcowXGetBackingStore(char **, const unsigned char *, size_t); -static int vmdk4GetBackingStore(char **, const unsigned char *, size_t); +static int cowGetBackingStore(char **, int *, + const unsigned char *, size_t); +static int qcow1GetBackingStore(char **, int *, + const unsigned char *, size_t); +static int qcow2GetBackingStore(char **, int *, + const unsigned char *, size_t); +static int vmdk4GetBackingStore(char **, int *, + const unsigned char *, size_t); + +#define QCOWX_HDR_VERSION (4) +#define QCOWX_HDR_BACKING_FILE_OFFSET (QCOWX_HDR_VERSION+4) +#define QCOWX_HDR_BACKING_FILE_SIZE (QCOWX_HDR_BACKING_FILE_OFFSET+8) +#define QCOWX_HDR_IMAGE_SIZE (QCOWX_HDR_BACKING_FILE_SIZE+4+4) + +#define QCOW1_HDR_CRYPT (QCOWX_HDR_IMAGE_SIZE+8+1+1) +#define QCOW2_HDR_CRYPT (QCOWX_HDR_IMAGE_SIZE+8) + +#define QCOW1_HDR_TOTAL_SIZE (QCOW1_HDR_CRYPT+4+8) +#define QCOW2_HDR_TOTAL_SIZE (QCOW2_HDR_CRYPT+4+4+8+8+4+4+8) + +#define QCOW2_HDR_EXTENSION_END 0 +#define QCOW2_HDR_EXTENSION_BACKING_FORMAT 0xE2792ACA +
static struct FileTypeInfo const fileTypeInfo[] = { @@ -119,11 +140,11 @@ static struct FileTypeInfo const fileTypeInfo[] = { /* QCow */ { VIR_STORAGE_FILE_QCOW, "QFI", NULL, LV_BIG_ENDIAN, 4, 1, - 4+4+8+4+4, 8, 1, 4+4+8+4+4+8+1+1+2, qcowXGetBackingStore }, + QCOWX_HDR_IMAGE_SIZE, 8, 1, QCOW1_HDR_CRYPT, qcow1GetBackingStore }, /* QCow 2 */ { VIR_STORAGE_FILE_QCOW2, "QFI", NULL, LV_BIG_ENDIAN, 4, 2, - 4+4+8+4+4, 8, 1, 4+4+8+4+4+8, qcowXGetBackingStore }, + QCOWX_HDR_IMAGE_SIZE, 8, 1, QCOW2_HDR_CRYPT, qcow2GetBackingStore }, /* VMDK 3 */ /* XXX Untested { VIR_STORAGE_FILE_VMDK, "COWD", NULL, @@ -142,11 +163,14 @@ static struct FileTypeInfo const fileTypeInfo[] = {
static int cowGetBackingStore(char **res, + int *format, const unsigned char *buf, size_t buf_size) { #define COW_FILENAME_MAXLEN 1024 *res = NULL; + *format = VIR_STORAGE_FILE_AUTO; + if (buf_size < 4+4+ COW_FILENAME_MAXLEN) return BACKING_STORE_INVALID; if (buf[4+4] == '\0') /* cow_header_v2.backing_file[0] */ @@ -160,31 +184,98 @@ cowGetBackingStore(char **res, return BACKING_STORE_OK; }
+ +static int +qcow2GetBackingStoreFormat(int *format, + const unsigned char *buf, + size_t buf_size, + size_t extension_start, + size_t extension_end) +{ + size_t offset = extension_start; + + /* + * The extensions take format of + * + * int32: magic + * int32: length + * byte[length]: payload + * + * Unknown extensions can be ignored by skipping + * over "length" bytes in the data stream. + */ + while (offset < (buf_size-8) && + offset < (extension_end-8)) { + unsigned int magic = + (buf[offset] << 24) + + (buf[offset+1] << 16) + + (buf[offset+2] << 8) + + (buf[offset+3]); + unsigned int len = + (buf[offset+4] << 24) + + (buf[offset+5] << 16) + + (buf[offset+6] << 8) + + (buf[offset+7]); + + offset += 8; + + if ((offset + len) < offset) + break; + + if ((offset + len) > buf_size) + break; + + switch (magic) { + case QCOW2_HDR_EXTENSION_END: + goto done; + + case QCOW2_HDR_EXTENSION_BACKING_FORMAT: + if (buf[offset+len] != '\0') + break; + *format = virStorageFileFormatTypeFromString( + ((const char *)buf)+offset); + break; + } + + offset += len; + } + +done: + + return 0; +} + + static int qcowXGetBackingStore(char **res, + int *format, const unsigned char *buf, - size_t buf_size) + size_t buf_size, + bool isQCow2) { unsigned long long offset; unsigned long size;
*res = NULL; - if (buf_size < 4+4+8+4) + if (format) + *format = VIR_STORAGE_FILE_AUTO; + + if (buf_size < QCOWX_HDR_BACKING_FILE_OFFSET+8+4) return BACKING_STORE_INVALID; - offset = (((unsigned long long)buf[4+4] << 56) - | ((unsigned long long)buf[4+4+1] << 48) - | ((unsigned long long)buf[4+4+2] << 40) - | ((unsigned long long)buf[4+4+3] << 32) - | ((unsigned long long)buf[4+4+4] << 24) - | ((unsigned long long)buf[4+4+5] << 16) - | ((unsigned long long)buf[4+4+6] << 8) - | buf[4+4+7]); /* QCowHeader.backing_file_offset */ + offset = (((unsigned long long)buf[QCOWX_HDR_BACKING_FILE_OFFSET] << 56) + | ((unsigned long long)buf[QCOWX_HDR_BACKING_FILE_OFFSET+1] << 48) + | ((unsigned long long)buf[QCOWX_HDR_BACKING_FILE_OFFSET+2] << 40) + | ((unsigned long long)buf[QCOWX_HDR_BACKING_FILE_OFFSET+3] << 32) + | ((unsigned long long)buf[QCOWX_HDR_BACKING_FILE_OFFSET+4] << 24) + | ((unsigned long long)buf[QCOWX_HDR_BACKING_FILE_OFFSET+5] << 16) + | ((unsigned long long)buf[QCOWX_HDR_BACKING_FILE_OFFSET+6] << 8) + | buf[QCOWX_HDR_BACKING_FILE_OFFSET+7]); /* QCowHeader.backing_file_offset */ if (offset > buf_size) return BACKING_STORE_INVALID; - size = ((buf[4+4+8] << 24) - | (buf[4+4+8+1] << 16) - | (buf[4+4+8+2] << 8) - | buf[4+4+8+3]); /* QCowHeader.backing_file_size */ + size = ((buf[QCOWX_HDR_BACKING_FILE_SIZE] << 24) + | (buf[QCOWX_HDR_BACKING_FILE_SIZE+1] << 16) + | (buf[QCOWX_HDR_BACKING_FILE_SIZE+2] << 8) + | buf[QCOWX_HDR_BACKING_FILE_SIZE+3]); /* QCowHeader.backing_file_size */ if (size == 0) return BACKING_STORE_OK; if (offset + size > buf_size || offset + size < offset) @@ -197,12 +288,63 @@ qcowXGetBackingStore(char **res, } memcpy(*res, buf + offset, size); (*res)[size] = '\0'; + + /* + * Traditionally QCow2 files had a layout of + * + * [header] + * [backingStoreName] + * + * Although the backingStoreName typically followed + * the header immediately, this was not required by + * the format. By specifying a higher byte offset for + * the backing file offset in the header, it was + * possible to leave space between the header and + * start of backingStore. + * + * This hack is now used to store extensions to the + * qcow2 format: + * + * [header] + * [extensions] + * [backingStoreName] + * + * Thus the file region to search for extensions is + * between the end of the header (QCOW2_HDR_TOTAL_SIZE) + * and the start of the backingStoreName (offset) + */ + if (isQCow2) + qcow2GetBackingStoreFormat(format, buf, buf_size, QCOW2_HDR_TOTAL_SIZE, offset); + return BACKING_STORE_OK; }
static int +qcow1GetBackingStore(char **res, + int *format, + const unsigned char *buf, + size_t buf_size) +{ + /* QCow1 doesn't have the extensions capability + * used to store backing format */ + *format = VIR_STORAGE_FILE_AUTO; + return qcowXGetBackingStore(res, NULL, buf, buf_size, false); +} + +static int +qcow2GetBackingStore(char **res, + int *format, + const unsigned char *buf, + size_t buf_size) +{ + return qcowXGetBackingStore(res, format, buf, buf_size, true); +} + + +static int vmdk4GetBackingStore(char **res, + int *format, const unsigned char *buf, size_t buf_size) { @@ -212,6 +354,14 @@ vmdk4GetBackingStore(char **res, size_t len;
*res = NULL; + /* + * Technically this should have been VMDK, since + * VMDK spec / VMWare impl only support VMDK backed + * by VMDK. QEMU isn't following this though and + * does probing on VMDK backing files, hence we set + * AUTO + */ + *format = VIR_STORAGE_FILE_AUTO;
if (buf_size <= 0x200) return BACKING_STORE_INVALID; @@ -358,9 +508,12 @@ virStorageFileGetMetadataFromFD(const char *path, /* Validation passed, we know the file format now */ meta->format = fileTypeInfo[i].type; if (fileTypeInfo[i].getBackingStore != NULL) { - char *base; + char *backing; + int backingFormat;
- switch (fileTypeInfo[i].getBackingStore(&base, head, len)) { + switch (fileTypeInfo[i].getBackingStore(&backing, + &backingFormat, + head, len)) { case BACKING_STORE_OK: break;
@@ -370,13 +523,16 @@ virStorageFileGetMetadataFromFD(const char *path, case BACKING_STORE_ERROR: return -1; } - if (base != NULL) { - meta->backingStore = absolutePathFromBaseFile(path, base); - VIR_FREE(base); + if (backing != NULL) { + meta->backingStore = absolutePathFromBaseFile(path, backing); + VIR_FREE(backing); if (meta->backingStore == NULL) { virReportOOMError(); return -1; } + meta->backingStoreFormat = backingFormat; + } else { + meta->backingStoreFormat = VIR_STORAGE_FILE_AUTO; } } return 0; diff --git a/src/util/storage_file.h b/src/util/storage_file.h index 58533ee..6328ba7 100644 --- a/src/util/storage_file.h +++ b/src/util/storage_file.h @@ -28,6 +28,7 @@ # include <stdbool.h>
enum virStorageFileFormat { + VIR_STORAGE_FILE_AUTO = -1, VIR_STORAGE_FILE_RAW = 0, VIR_STORAGE_FILE_DIR, VIR_STORAGE_FILE_BOCHS, @@ -47,6 +48,7 @@ VIR_ENUM_DECL(virStorageFileFormat); typedef struct _virStorageFileMetadata { int format; char *backingStore; + int backingStoreFormat; unsigned long long capacity; bool encrypted; } virStorageFileMetadata;
ACK, also includes some cleanup about the indexes in the qcow formats Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

Instead of including a field in FileTypeInfo struct for the disk format, rely on the array index matching the format. Use verify() to assert the correct number of elements in the array. * src/util/storage_file.c: remove type field from FileTypeInfo --- src/util/storage_file.c | 108 +++++++++++++++++++++++----------------------- 1 files changed, 54 insertions(+), 54 deletions(-) diff --git a/src/util/storage_file.c b/src/util/storage_file.c index 80f743e..df0e3a1 100644 --- a/src/util/storage_file.c +++ b/src/util/storage_file.c @@ -58,7 +58,6 @@ enum { /* Either 'magic' or 'extension' *must* be provided */ struct FileTypeInfo { - int type; /* One of the constants above */ const char *magic; /* Optional string of file magic * to check at head of file */ const char *extension; /* Optional file extension to check */ @@ -108,58 +107,59 @@ static int vmdk4GetBackingStore(char **, int *, static struct FileTypeInfo const fileTypeInfo[] = { - /* Bochs */ - /* XXX Untested - { VIR_STORAGE_FILE_BOCHS, "Bochs Virtual HD Image", NULL, - LV_LITTLE_ENDIAN, 64, 0x20000, - 32+16+16+4+4+4+4+4, 8, 1, -1, NULL },*/ - /* CLoop */ - /* XXX Untested - { VIR_STORAGE_VOL_CLOOP, "#!/bin/sh\n#V2.0 Format\nmodprobe cloop file=$0 && mount -r -t iso9660 /dev/cloop $1\n", NULL, - LV_LITTLE_ENDIAN, -1, 0, - -1, 0, 0, -1, NULL }, */ - /* Cow */ - { VIR_STORAGE_FILE_COW, "OOOM", NULL, - LV_BIG_ENDIAN, 4, 2, - 4+4+1024+4, 8, 1, -1, cowGetBackingStore }, - /* DMG */ - /* XXX QEMU says there's no magic for dmg, but we should check... */ - { VIR_STORAGE_FILE_DMG, NULL, ".dmg", - 0, -1, 0, - -1, 0, 0, -1, NULL }, - /* XXX there's probably some magic for iso we can validate too... */ - { VIR_STORAGE_FILE_ISO, NULL, ".iso", - 0, -1, 0, - -1, 0, 0, -1, NULL }, - /* Parallels */ - /* XXX Untested - { VIR_STORAGE_FILE_PARALLELS, "WithoutFreeSpace", NULL, - LV_LITTLE_ENDIAN, 16, 2, - 16+4+4+4+4, 4, 512, -1, NULL }, - */ - /* QCow */ - { VIR_STORAGE_FILE_QCOW, "QFI", NULL, - LV_BIG_ENDIAN, 4, 1, - QCOWX_HDR_IMAGE_SIZE, 8, 1, QCOW1_HDR_CRYPT, qcow1GetBackingStore }, - /* QCow 2 */ - { VIR_STORAGE_FILE_QCOW2, "QFI", NULL, - LV_BIG_ENDIAN, 4, 2, - QCOWX_HDR_IMAGE_SIZE, 8, 1, QCOW2_HDR_CRYPT, qcow2GetBackingStore }, - /* VMDK 3 */ - /* XXX Untested - { VIR_STORAGE_FILE_VMDK, "COWD", NULL, - LV_LITTLE_ENDIAN, 4, 1, - 4+4+4, 4, 512, -1, NULL }, - */ - /* VMDK 4 */ - { VIR_STORAGE_FILE_VMDK, "KDMV", NULL, - LV_LITTLE_ENDIAN, 4, 1, - 4+4+4, 8, 512, -1, vmdk4GetBackingStore }, - /* Connectix / VirtualPC */ - { VIR_STORAGE_FILE_VPC, "conectix", NULL, - LV_BIG_ENDIAN, 12, 0x10000, - 8 + 4 + 4 + 8 + 4 + 4 + 2 + 2 + 4, 8, 1, -1, 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, + LV_LITTLE_ENDIAN, 64, 0x20000, + 32+16+16+4+4+4+4+4, 8, 1, -1, NULL + }, + [VIR_STORAGE_FILE_CLOOP] = { + /*"#!/bin/sh\n#V2.0 Format\nmodprobe cloop file=$0 && mount -r -t iso9660 /dev/cloop $1\n", */ /* Untested */ NULL, + NULL, + LV_LITTLE_ENDIAN, -1, 0, + -1, 0, 0, -1, NULL + }, + [VIR_STORAGE_FILE_COW] = { + "OOOM", NULL, + LV_BIG_ENDIAN, 4, 2, + 4+4+1024+4, 8, 1, -1, cowGetBackingStore + }, + [VIR_STORAGE_FILE_DMG] = { + NULL, /* XXX QEMU says there's no magic for dmg, but we should check... */ + ".dmg", + 0, -1, 0, + -1, 0, 0, -1, NULL + }, + [VIR_STORAGE_FILE_ISO] = { + NULL, /* XXX there's probably some magic for iso we can validate too... */ + ".iso", + 0, -1, 0, + -1, 0, 0, -1, NULL + }, + [VIR_STORAGE_FILE_QCOW] = { + "QFI", NULL, + LV_BIG_ENDIAN, 4, 1, + QCOWX_HDR_IMAGE_SIZE, 8, 1, QCOW1_HDR_CRYPT, qcow1GetBackingStore, + }, + [VIR_STORAGE_FILE_QCOW2] = { + "QFI", NULL, + LV_BIG_ENDIAN, 4, 2, + QCOWX_HDR_IMAGE_SIZE, 8, 1, QCOW2_HDR_CRYPT, qcow2GetBackingStore, + }, + [VIR_STORAGE_FILE_VMDK] = { + "KDMV", NULL, + LV_LITTLE_ENDIAN, 4, 1, + 4+4+4, 8, 512, -1, vmdk4GetBackingStore + }, + [VIR_STORAGE_FILE_VPC] = { + "conectix", NULL, + LV_BIG_ENDIAN, 12, 0x10000, + 8 + 4 + 4 + 8 + 4 + 4 + 2 + 2 + 4, 8, 1, -1, NULL + }, }; +verify(ARRAY_CARDINALITY(fileTypeInfo) == VIR_STORAGE_FILE_LAST); static int cowGetBackingStore(char **res, @@ -506,7 +506,7 @@ virStorageFileGetMetadataFromFD(const char *path, } /* Validation passed, we know the file format now */ - meta->format = fileTypeInfo[i].type; + meta->format = i; if (fileTypeInfo[i].getBackingStore != NULL) { char *backing; int backingFormat; @@ -546,7 +546,7 @@ virStorageFileGetMetadataFromFD(const char *path, if (!virFileHasSuffix(path, fileTypeInfo[i].extension)) continue; - meta->format = fileTypeInfo[i].type; + meta->format = i; return 0; } -- 1.7.1.1

On Mon, Jul 12, 2010 at 02:30:39PM +0100, Daniel P. Berrange wrote:
Instead of including a field in FileTypeInfo struct for the disk format, rely on the array index matching the format. Use verify() to assert the correct number of elements in the array.
* src/util/storage_file.c: remove type field from FileTypeInfo
ACK, small simplification and more comoile time checking. Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

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 | 460 +++++++++++++++++++++++++++++++++------------- src/util/storage_file.h | 4 + 3 files changed, 335 insertions(+), 131 deletions(-) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 778ceb1..4607f49 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -628,6 +628,8 @@ virStorageGenerateQcowPassphrase; # storage_file.h virStorageFileFormatTypeToString; virStorageFileFormatTypeFromString; +virStorageFileProbeFormat; +virStorageFileProbeFormatFromFD; virStorageFileGetMetadata; virStorageFileGetMetadataFromFD; virStorageFileIsSharedFS; diff --git a/src/util/storage_file.c b/src/util/storage_file.c index df0e3a1..221268b 100644 --- a/src/util/storage_file.c +++ b/src/util/storage_file.c @@ -104,6 +104,9 @@ static int vmdk4GetBackingStore(char **, int *, #define QCOW2_HDR_EXTENSION_END 0 #define QCOW2_HDR_EXTENSION_BACKING_FORMAT 0xE2792ACA +/* VMDK needs at least this to find backing store, + * other formats are less */ +#define STORAGE_MAX_HEAD (20*512) static struct FileTypeInfo const fileTypeInfo[] = { @@ -349,9 +352,14 @@ vmdk4GetBackingStore(char **res, size_t buf_size) { static const char prefix[] = "parentFileNameHint=\""; - - char desc[20*512 + 1], *start, *end; + char *desc, *start, *end; size_t len; + int ret = BACKING_STORE_ERROR; + + if (VIR_ALLOC_N(desc, STORAGE_MAX_HEAD + 1) < 0) { + virReportOOMError(); + goto cleanup; + } *res = NULL; /* @@ -363,29 +371,42 @@ vmdk4GetBackingStore(char **res, */ *format = VIR_STORAGE_FILE_AUTO; - if (buf_size <= 0x200) - return BACKING_STORE_INVALID; + if (buf_size <= 0x200) { + ret = BACKING_STORE_INVALID; + goto cleanup; + } len = buf_size - 0x200; - if (len > sizeof(desc) - 1) - len = sizeof(desc) - 1; + if (len > STORAGE_MAX_HEAD) + len = STORAGE_MAX_HEAD; memcpy(desc, buf + 0x200, len); desc[len] = '\0'; start = strstr(desc, prefix); - if (start == NULL) - return BACKING_STORE_OK; + if (start == NULL) { + ret = BACKING_STORE_OK; + goto cleanup; + } start += strlen(prefix); end = strchr(start, '"'); - if (end == NULL) - return BACKING_STORE_INVALID; - if (end == start) - return BACKING_STORE_OK; + if (end == NULL) { + ret = BACKING_STORE_INVALID; + goto cleanup; + } + if (end == start) { + ret = BACKING_STORE_OK; + goto cleanup; + } *end = '\0'; *res = strdup(start); if (*res == NULL) { virReportOOMError(); - return BACKING_STORE_ERROR; + goto cleanup; } - return BACKING_STORE_OK; + + ret = BACKING_STORE_OK; + +cleanup: + VIR_FREE(desc); + return ret; } /** @@ -411,148 +432,325 @@ absolutePathFromBaseFile(const char *base_file, const char *path) return res; } -/** - * Probe the header of a file to determine what type of disk image - * it is, and info about its capacity if available. - */ -int -virStorageFileGetMetadataFromFD(const char *path, - int fd, - virStorageFileMetadata *meta) + +static bool +virStorageFileMatchesMagic(int format, + unsigned char *buf, + size_t buflen) { - unsigned char head[20*512]; /* vmdk4GetBackingStore needs this much. */ - int len, i; + int mlen; - memset(meta, 0, sizeof (*meta)); + if (fileTypeInfo[format].magic == NULL) + return false; - /* If all else fails, call it a raw file */ - meta->format = VIR_STORAGE_FILE_RAW; + /* Validate magic data */ + mlen = strlen(fileTypeInfo[format].magic); + if (mlen > buflen) + return false; - if ((len = read(fd, head, sizeof(head))) < 0) { - virReportSystemError(errno, _("cannot read header '%s'"), path); - return -1; + if (memcmp(buf, fileTypeInfo[format].magic, mlen) != 0) + return false; + + return true; +} + + +static bool +virStorageFileMatchesExtension(int format, + const char *path) +{ + if (fileTypeInfo[format].extension == NULL) + return false; + + if (virFileHasSuffix(path, fileTypeInfo[format].extension)) + return true; + + return false; +} + + +static bool +virStorageFileMatchesVersion(int format, + unsigned char *buf, + size_t buflen) +{ + int version; + + /* Validate version number info */ + if (fileTypeInfo[format].versionOffset == -1) + return false; + + if ((fileTypeInfo[format].versionOffset + 4) > buflen) + return false; + + 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 false; - /* First check file magic */ - for (i = 0 ; i < ARRAY_CARDINALITY(fileTypeInfo) ; i++) { - int mlen; - - if (fileTypeInfo[i].magic == NULL) - continue; - - /* 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; - } + return true; +} - /* 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; - } - if (fileTypeInfo[i].qcowCryptOffset != -1) { - int crypt_format; +static int +virStorageFileGetMetadataFromBuf(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; + } - 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; + /* 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; + } - /* Validation passed, we know the file format now */ - meta->format = i; - if (fileTypeInfo[i].getBackingStore != NULL) { - char *backing; - int backingFormat; + if (fileTypeInfo[format].qcowCryptOffset != -1) { + int crypt_format; - switch (fileTypeInfo[i].getBackingStore(&backing, - &backingFormat, - head, len)) { - case BACKING_STORE_OK: - break; + 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; + } - case BACKING_STORE_INVALID: - continue; + if (fileTypeInfo[format].getBackingStore != NULL) { + char *backing; + int backingFormat; + int ret = fileTypeInfo[format].getBackingStore(&backing, + &backingFormat, + buf, buflen); + if (ret == BACKING_STORE_INVALID) + return 1; + + if (ret == BACKING_STORE_ERROR) + return -1; - case BACKING_STORE_ERROR: + if (backing != NULL) { + meta->backingStore = absolutePathFromBaseFile(path, backing); + VIR_FREE(backing); + if (meta->backingStore == NULL) { + virReportOOMError(); return -1; } - if (backing != NULL) { - meta->backingStore = absolutePathFromBaseFile(path, backing); - VIR_FREE(backing); - if (meta->backingStore == NULL) { - virReportOOMError(); - return -1; - } - meta->backingStoreFormat = backingFormat; - } else { - meta->backingStoreFormat = VIR_STORAGE_FILE_AUTO; - } + 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; } - return 0; } /* No magic, so check file extension */ - for (i = 0 ; i < ARRAY_CARDINALITY(fileTypeInfo) ; i++) { - if (fileTypeInfo[i].extension == NULL) - continue; + for (i = 0 ; i < VIR_STORAGE_FILE_LAST ; i++) { + if (virStorageFileMatchesExtension(i, path)) { + format = i; + goto cleanup; + } + } - if (!virFileHasSuffix(path, fileTypeInfo[i].extension)) - continue; +cleanup: + return format; +} - meta->format = i; - return 0; + +/** + * 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 +virStorageFileProbeFormatFromFD(const char *path, int fd) +{ + unsigned char *head; + ssize_t len = STORAGE_MAX_HEAD; + int ret = -1; + + if (VIR_ALLOC_N(head, len) < 0) { + virReportOOMError(); + return -1; } - return 0; + if (lseek(fd, 0, SEEK_SET) == (off_t)-1) { + virReportSystemError(errno, _("cannot set to start of '%s'"), path); + goto cleanup; + } + + if ((len = read(fd, head, len)) < 0) { + virReportSystemError(errno, _("cannot read header '%s'"), path); + goto cleanup; + } + + ret = virStorageFileProbeFormatFromBuf(path, head, len); + +cleanup: + VIR_FREE(head); + return ret; +} + + +/** + * 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 raw file into any other non-raw + * format at will. + * + * Best option: Don't use this function + */ +int +virStorageFileProbeFormat(const char *path) +{ + int fd, ret; + + if ((fd = open(path, O_RDONLY)) < 0) { + virReportSystemError(errno, _("cannot open file '%s'"), path); + return -1; + } + + ret = virStorageFileProbeFormatFromFD(path, fd); + + close(fd); + + return ret; } +/** + * 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 raw file into any other non-raw + * format at will. + */ +int +virStorageFileGetMetadataFromFD(const char *path, + int fd, + virStorageFileMetadata *meta) +{ + unsigned char *head; + ssize_t len = STORAGE_MAX_HEAD; + int ret = -1; + + if (VIR_ALLOC_N(head, len) < 0) { + virReportOOMError(); + return -1; + } + + memset(meta, 0, sizeof (*meta)); + + if (lseek(fd, 0, SEEK_SET) == (off_t)-1) { + virReportSystemError(errno, _("cannot set to start of '%s'"), path); + goto cleanup; + } + + if ((len = read(fd, head, len)) < 0) { + virReportSystemError(errno, _("cannot read header '%s'"), path); + goto cleanup; + } + + meta->format = virStorageFileProbeFormatFromBuf(path, head, len); + + ret = virStorageFileGetMetadataFromBuf(meta->format, path, head, len, meta); + +cleanup: + VIR_FREE(head); + return ret; +} + +/** + * 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 raw file into any other non-raw + * format at will. + */ int virStorageFileGetMetadata(const char *path, virStorageFileMetadata *meta) diff --git a/src/util/storage_file.h b/src/util/storage_file.h index 6328ba7..3420d44 100644 --- a/src/util/storage_file.h +++ b/src/util/storage_file.h @@ -57,6 +57,10 @@ typedef struct _virStorageFileMetadata { # define DEV_BSIZE 512 # endif +int virStorageFileProbeFormat(const char *path); +int virStorageFileProbeFormatFromFD(const char *path, + int fd); + int virStorageFileGetMetadata(const char *path, virStorageFileMetadata *meta); int virStorageFileGetMetadataFromFD(const char *path, -- 1.7.1.1

On Mon, Jul 12, 2010 at 02:30:40PM +0100, Daniel P. Berrange wrote:
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 [...] +++ b/src/util/storage_file.c @@ -104,6 +104,9 @@ static int vmdk4GetBackingStore(char **, int *, #define QCOW2_HDR_EXTENSION_END 0 #define QCOW2_HDR_EXTENSION_BACKING_FORMAT 0xE2792ACA
+/* VMDK needs at least this to find backing store, + * other formats are less */ +#define STORAGE_MAX_HEAD (20*512)
What about finishing the comment, less what ??? "need less" ? [...]
- unsigned char head[20*512]; /* vmdk4GetBackingStore needs this much. */
okay "need less" [...]
+/** + * 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
Could this be a setting ? Not always nice to set security left as a setting, but if we don't trust that code ...
+/** + * 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 raw file into any other non-raw + * format at will. + * + * Best option: Don't use this function + */
idem.
+ * 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 raw file into any other non-raw + * format at will.
idem ACK to the approach but since we are left to chose between heuristics potentially dangerous or disabling guessing, ca we defr that back to some kind of user option ? Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

Require the disk image to be passed into virStorageFileGetMetadata. If this is set to VIR_STORAGE_FILE_AUTO, then the format will be resolved using probing. This makes it easier to control when probing will be used * src/qemu/qemu_driver.c, src/qemu/qemu_security_dac.c, src/security/security_selinux.c, src/security/virt-aa-helper.c: Set VIR_STORAGE_FILE_AUTO when calling virStorageFileGetMetadata. * src/storage/storage_backend_fs.c: Probe for disk format before calling virStorageFileGetMetadata. * src/util/storage_file.h, src/util/storage_file.c: Remove format from virStorageFileMeta struct & require it to be passed into method. --- src/qemu/qemu_driver.c | 27 +++++++++++++++++--- src/qemu/qemu_security_dac.c | 4 ++- src/security/security_selinux.c | 4 ++- src/security/virt-aa-helper.c | 4 ++- src/storage/storage_backend_fs.c | 11 ++++++-- src/util/storage_file.c | 50 +++++++++++++++++++++++++------------ src/util/storage_file.h | 3 +- 7 files changed, 76 insertions(+), 27 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 487bfa3..97f2990 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -3069,7 +3069,9 @@ static int qemuSetupDiskCgroup(virCgroupPtr cgroup, } } - rc = virStorageFileGetMetadata(path, &meta); + rc = virStorageFileGetMetadata(path, + VIR_STORAGE_FILE_AUTO, + &meta); if (rc < 0) VIR_WARN("Unable to lookup parent image for %s", path); @@ -3119,7 +3121,9 @@ static int qemuTeardownDiskCgroup(virCgroupPtr cgroup, } } - rc = virStorageFileGetMetadata(path, &meta); + rc = virStorageFileGetMetadata(path, + VIR_STORAGE_FILE_AUTO, + &meta); if (rc < 0) VIR_WARN("Unable to lookup parent image for %s", path); @@ -9614,6 +9618,7 @@ static int qemuDomainGetBlockInfo(virDomainPtr dom, virDomainDiskDefPtr disk = NULL; struct stat sb; int i; + int format; virCheckFlags(0, -1); @@ -9658,7 +9663,21 @@ static int qemuDomainGetBlockInfo(virDomainPtr dom, } /* Probe for magic formats */ - if (virStorageFileGetMetadataFromFD(path, fd, &meta) < 0) + if (disk->driverType) { + if ((format = virStorageFileFormatTypeFromString(disk->driverType)) < 0) { + qemuReportError(VIR_ERR_INTERNAL_ERROR, + _("unknown disk format %s for %s"), + disk->driverType, disk->src); + goto cleanup; + } + } else { + if ((format = virStorageFileProbeFormat(disk->src)) < 0) + goto cleanup; + } + + if (virStorageFileGetMetadataFromFD(path, fd, + format, + &meta) < 0) goto cleanup; /* Get info for normal formats */ @@ -9706,7 +9725,7 @@ static int qemuDomainGetBlockInfo(virDomainPtr dom, highest allocated extent from QEMU */ if (virDomainObjIsActive(vm) && disk->type == VIR_DOMAIN_DISK_TYPE_BLOCK && - meta.format != VIR_STORAGE_FILE_RAW && + format != VIR_STORAGE_FILE_RAW && S_ISBLK(sb.st_mode)) { qemuDomainObjPrivatePtr priv = vm->privateData; if (qemuDomainObjBeginJob(vm) < 0) diff --git a/src/qemu/qemu_security_dac.c b/src/qemu/qemu_security_dac.c index 95015b0..acfe48e 100644 --- a/src/qemu/qemu_security_dac.c +++ b/src/qemu/qemu_security_dac.c @@ -115,7 +115,9 @@ qemuSecurityDACSetSecurityImageLabel(virDomainObjPtr vm ATTRIBUTE_UNUSED, virStorageFileMetadata meta; int ret; - ret = virStorageFileGetMetadata(path, &meta); + ret = virStorageFileGetMetadata(path, + VIR_STORAGE_FILE_AUTO, + &meta); if (path != disk->src) VIR_FREE(path); diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c index e5eef19..5c0f002 100644 --- a/src/security/security_selinux.c +++ b/src/security/security_selinux.c @@ -457,7 +457,9 @@ SELinuxSetSecurityImageLabel(virDomainObjPtr vm, virStorageFileMetadata meta; int ret; - ret = virStorageFileGetMetadata(path, &meta); + ret = virStorageFileGetMetadata(path, + VIR_STORAGE_FILE_AUTO, + &meta); if (path != disk->src) VIR_FREE(path); diff --git a/src/security/virt-aa-helper.c b/src/security/virt-aa-helper.c index c66f107..2c045e6 100644 --- a/src/security/virt-aa-helper.c +++ b/src/security/virt-aa-helper.c @@ -830,7 +830,9 @@ get_files(vahControl * ctl) do { virStorageFileMetadata meta; - ret = virStorageFileGetMetadata(path, &meta); + ret = virStorageFileGetMetadata(path, + VIR_STORAGE_FILE_AUTO, + &meta); if (path != ctl->def->disks[i]->src) VIR_FREE(path); diff --git a/src/storage/storage_backend_fs.c b/src/storage/storage_backend_fs.c index f0cd770..d3ac0fe 100644 --- a/src/storage/storage_backend_fs.c +++ b/src/storage/storage_backend_fs.c @@ -75,14 +75,19 @@ virStorageBackendProbeTarget(virStorageVolTargetPtr target, memset(&meta, 0, sizeof(meta)); - if (virStorageFileGetMetadataFromFD(target->path, fd, &meta) < 0) { + if ((target->format = virStorageFileProbeFormatFromFD(target->path, fd)) < 0) { close(fd); return -1; } - close(fd); + if (virStorageFileGetMetadataFromFD(target->path, fd, + target->format, + &meta) < 0) { + close(fd); + return -1; + } - target->format = meta.format; + close(fd); if (backingStore) { *backingStore = meta.backingStore; diff --git a/src/util/storage_file.c b/src/util/storage_file.c index 221268b..9712d92 100644 --- a/src/util/storage_file.c +++ b/src/util/storage_file.c @@ -696,18 +696,23 @@ virStorageFileProbeFormat(const char *path) /** * 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. + * Extract metadata about the storage volume with the specified + * image format. If image format is VIR_STORAGE_FILE_AUTO, it + * will probe to automatically identify the format. * - * 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 raw file into any other non-raw - * format at will. + * Callers are advised never to use VIR_STORAGE_FILE_AUTO as a + * format, since a malicious guest can turn a raw file into any + * other non-raw format at will. + * + * If the returned meta.backingStoreFormat is VIR_STORAGE_FILE_AUTO + * it indicates the image didn't specify an explicit format for its + * backing store. Callers are advised against probing for the + * backing store format in this case. */ int virStorageFileGetMetadataFromFD(const char *path, int fd, + int format, virStorageFileMetadata *meta) { unsigned char *head; @@ -731,9 +736,16 @@ virStorageFileGetMetadataFromFD(const char *path, goto cleanup; } - meta->format = virStorageFileProbeFormatFromBuf(path, head, len); + if (format == VIR_STORAGE_FILE_AUTO) + format = virStorageFileProbeFormatFromBuf(path, head, len); + + if (format < 0 || + format >= VIR_STORAGE_FILE_LAST) { + virReportSystemError(EINVAL, _("unknown storage file format %d"), format); + return -1; + } - ret = virStorageFileGetMetadataFromBuf(meta->format, path, head, len, meta); + ret = virStorageFileGetMetadataFromBuf(format, path, head, len, meta); cleanup: VIR_FREE(head); @@ -743,16 +755,22 @@ cleanup: /** * virStorageFileGetMetadata: * - * Probe for the format of 'path', filling 'meta' with the detected - * format and other associated metadata. + * Extract metadata about the storage volume with the specified + * image format. If image format is VIR_STORAGE_FILE_AUTO, it + * will probe to automatically identify the format. * - * 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 raw file into any other non-raw - * format at will. + * Callers are advised never to use VIR_STORAGE_FILE_AUTO as a + * format, since a malicious guest can turn a raw file into any + * other non-raw format at will. + * + * If the returned meta.backingStoreFormat is VIR_STORAGE_FILE_AUTO + * it indicates the image didn't specify an explicit format for its + * backing store. Callers are advised against probing for the + * backing store format in this case. */ int virStorageFileGetMetadata(const char *path, + int format, virStorageFileMetadata *meta) { int fd, ret; @@ -762,7 +780,7 @@ virStorageFileGetMetadata(const char *path, return -1; } - ret = virStorageFileGetMetadataFromFD(path, fd, meta); + ret = virStorageFileGetMetadataFromFD(path, fd, format, meta); close(fd); diff --git a/src/util/storage_file.h b/src/util/storage_file.h index 3420d44..6853182 100644 --- a/src/util/storage_file.h +++ b/src/util/storage_file.h @@ -46,7 +46,6 @@ enum virStorageFileFormat { VIR_ENUM_DECL(virStorageFileFormat); typedef struct _virStorageFileMetadata { - int format; char *backingStore; int backingStoreFormat; unsigned long long capacity; @@ -62,9 +61,11 @@ int virStorageFileProbeFormatFromFD(const char *path, int fd); int virStorageFileGetMetadata(const char *path, + int format, virStorageFileMetadata *meta); int virStorageFileGetMetadataFromFD(const char *path, int fd, + int format, virStorageFileMetadata *meta); int virStorageFileIsSharedFS(const char *path); -- 1.7.1.1

On Mon, Jul 12, 2010 at 02:30:41PM +0100, Daniel P. Berrange wrote:
Require the disk image to be passed into virStorageFileGetMetadata. If this is set to VIR_STORAGE_FILE_AUTO, then the format will be resolved using probing. This makes it easier to control when probing will be used
* src/qemu/qemu_driver.c, src/qemu/qemu_security_dac.c, src/security/security_selinux.c, src/security/virt-aa-helper.c: Set VIR_STORAGE_FILE_AUTO when calling virStorageFileGetMetadata. * src/storage/storage_backend_fs.c: Probe for disk format before calling virStorageFileGetMetadata. * src/util/storage_file.h, src/util/storage_file.c: Remove format from virStorageFileMeta struct & require it to be passed into method.
Okay sort of work around for my question on previous patch for most cases, ACK Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

There is duplicated code which iterates over disk backing stores performing some action. Provide a convenient helper for doing this to eliminate duplication & risk of mistakes with disk format probing * src/conf/domain_conf.c, src/conf/domain_conf.h, src/libvirt_private.syms: Add virDomainDiskDefForeachPath() --- src/conf/domain_conf.c | 99 ++++++++++++++++++++++++++++++++++++++++++++++ src/conf/domain_conf.h | 11 +++++ src/libvirt_private.syms | 1 + 3 files changed, 111 insertions(+), 0 deletions(-) diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 378c06e..b20ca97 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -45,6 +45,7 @@ #include "macvtap.h" #include "nwfilter_conf.h" #include "ignore-value.h" +#include "storage_file.h" #define VIR_FROM_THIS VIR_FROM_DOMAIN @@ -7273,4 +7274,102 @@ done: } +int virDomainDiskDefForeachPath(virDomainDiskDefPtr disk, + bool allowProbing, + bool ignoreOpenFailure, + virDomainDiskDefPathIterator iter, + void *opaque) +{ + virHashTablePtr paths; + int format; + int ret = -1; + size_t depth = 0; + char *nextpath = NULL; + + if (!disk->src) + return 0; + + if (disk->driverType) { + const char *formatStr = disk->driverType; + if (STREQ(formatStr, "aio")) + formatStr = "raw"; /* Xen compat */ + + if ((format = virStorageFileFormatTypeFromString(formatStr)) < 0) { + virDomainReportError(VIR_ERR_INTERNAL_ERROR, + _("unknown disk format '%s' for %s"), + disk->driverType, disk->src); + return -1; + } + } else { + if (allowProbing) { + format = VIR_STORAGE_FILE_AUTO; + } else { + virDomainReportError(VIR_ERR_INTERNAL_ERROR, + _("no disk format for %s and probing is disabled"), + disk->src); + return -1; + } + } + + paths = virHashCreate(5); + + do { + virStorageFileMetadata meta; + const char *path = nextpath ? nextpath : disk->src; + int fd; + + if (iter(disk, path, depth, opaque) < 0) + goto cleanup; + + if (virHashLookup(paths, path)) { + virDomainReportError(VIR_ERR_INTERNAL_ERROR, + _("backing store for %s is self-referential"), + disk->src); + goto cleanup; + } + + if ((fd = open(path, O_RDONLY)) < 0) { + if (ignoreOpenFailure) { + char ebuf[1024]; + VIR_WARN("Ignoring open failure on %s: %s", path, + virStrerror(errno, ebuf, sizeof(ebuf))); + break; + } else { + virReportSystemError(errno, + _("unable to open disk path %s"), + path); + goto cleanup; + } + } + + if (virStorageFileGetMetadataFromFD(path, fd, format, &meta) < 0) { + close(fd); + goto cleanup; + } + close(fd); + + if (virHashAddEntry(paths, path, (void*)0x1) < 0) { + virReportOOMError(); + goto cleanup; + } + + depth++; + nextpath = meta.backingStore; + + format = meta.backingStoreFormat; + + if (format == VIR_STORAGE_FILE_AUTO && + !allowProbing) + format = VIR_STORAGE_FILE_RAW; /* Stops further recursion */ + } while (nextpath); + + ret = 0; + +cleanup: + virHashFree(paths, NULL); + VIR_FREE(nextpath); + + return ret; +} + #endif /* ! PROXY */ diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 01da17e..d46869e 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -1079,6 +1079,17 @@ int virDomainChrDefForeach(virDomainDefPtr def, void *opaque); +typedef int (*virDomainDiskDefPathIterator)(virDomainDiskDefPtr disk, + const char *path, + size_t depth, + void *opaque); + +int virDomainDiskDefForeachPath(virDomainDiskDefPtr disk, + bool allowProbing, + bool ignoreOpenFailure, + virDomainDiskDefPathIterator iter, + void *opaque); + VIR_ENUM_DECL(virDomainVirt) VIR_ENUM_DECL(virDomainBoot) VIR_ENUM_DECL(virDomainFeature) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 4607f49..b5f3695 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -225,6 +225,7 @@ virDomainSnapshotDefFormat; virDomainSnapshotAssignDef; virDomainObjAssignDef; virDomainChrDefForeach; +virDomainDiskDefForeachPath; # domain_event.h -- 1.7.1.1

On Mon, Jul 12, 2010 at 02:30:42PM +0100, Daniel P. Berrange wrote:
There is duplicated code which iterates over disk backing stores performing some action. Provide a convenient helper for doing this to eliminate duplication & risk of mistakes with disk format probing
* src/conf/domain_conf.c, src/conf/domain_conf.h, src/libvirt_private.syms: Add virDomainDiskDefForeachPath() [...] + if ((fd = open(path, O_RDONLY)) < 0) {
+ if (virStorageFileGetMetadataFromFD(path, fd, format, &meta) < 0) { + close(fd); + goto cleanup; + } + close(fd);
stylistic ret = f(... fd, ) close(fd); if (ret < 0) goto cleanup; looks simpler to me, but it's a matter of taste :-) ACK, Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

Update the QEMU cgroups code, QEMU DAC security driver, SELinux and AppArmour security drivers over to use the shared helper API virDomainDiskDefForeachPath(). * src/qemu/qemu_driver.c, src/qemu/qemu_security_dac.c, src/security/security_selinux.c, src/security/virt-aa-helper.c: Convert over to use virDomainDiskDefForeachPath() --- src/qemu/qemu_driver.c | 161 ++++++++++++++++---------------------- src/qemu/qemu_security_dac.c | 47 ++++-------- src/security/security_selinux.c | 67 +++++++---------- src/security/virt-aa-helper.c | 71 ++++++++---------- 4 files changed, 142 insertions(+), 204 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 97f2990..99aeffa 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -3040,107 +3040,82 @@ static const char *const defaultDeviceACL[] = { #define DEVICE_PTY_MAJOR 136 #define DEVICE_SND_MAJOR 116 -static int qemuSetupDiskCgroup(virCgroupPtr cgroup, - virDomainObjPtr vm, - virDomainDiskDefPtr disk) -{ - char *path = disk->src; - int ret = -1; - while (path != NULL) { - virStorageFileMetadata meta; - int rc; +static int qemuSetupDiskPathAllow(virDomainDiskDefPtr disk ATTRIBUTE_UNUSED, + const char *path, + size_t depth ATTRIBUTE_UNUSED, + void *opaque) +{ + virCgroupPtr cgroup = opaque; + int rc; - VIR_DEBUG("Process path '%s' for disk", path); - rc = virCgroupAllowDevicePath(cgroup, path); - if (rc != 0) { - /* Get this for non-block devices */ - if (rc == -EINVAL) { - VIR_DEBUG("Ignoring EINVAL for %s", path); - } else if (rc == -EACCES) { /* Get this for root squash NFS */ - VIR_DEBUG("Ignoring EACCES for %s", path); - } else { - virReportSystemError(-rc, - _("Unable to allow device %s for %s"), - path, vm->def->name); - if (path != disk->src) - VIR_FREE(path); - goto cleanup; - } + VIR_DEBUG("Process path %s for disk", path); + /* XXX RO vs RW */ + rc = virCgroupAllowDevicePath(cgroup, path); + if (rc != 0) { + /* Get this for non-block devices */ + if (rc == -EINVAL) { + VIR_DEBUG("Ignoring EINVAL for %s", path); + } else if (rc == -EACCES) { /* Get this for root squash NFS */ + VIR_DEBUG("Ignoring EACCES for %s", path); + } else { + virReportSystemError(-rc, + _("Unable to allow access for disk path %s"), + path); + return -1; } - - rc = virStorageFileGetMetadata(path, - VIR_STORAGE_FILE_AUTO, - &meta); - if (rc < 0) - VIR_WARN("Unable to lookup parent image for %s", path); - - if (path != disk->src) - VIR_FREE(path); - path = NULL; - - if (rc < 0) - break; /* Treating as non fatal */ - - path = meta.backingStore; } + return 0; +} - ret = 0; -cleanup: - return ret; +static int qemuSetupDiskCgroup(virCgroupPtr cgroup, + virDomainDiskDefPtr disk) +{ + return virDomainDiskDefForeachPath(disk, + true, + true, + qemuSetupDiskPathAllow, + cgroup); } -static int qemuTeardownDiskCgroup(virCgroupPtr cgroup, - virDomainObjPtr vm, - virDomainDiskDefPtr disk) +static int qemuTeardownDiskPathDeny(virDomainDiskDefPtr disk ATTRIBUTE_UNUSED, + const char *path, + size_t depth ATTRIBUTE_UNUSED, + void *opaque) { - char *path = disk->src; - int ret = -1; - - while (path != NULL) { - virStorageFileMetadata meta; - int rc; + virCgroupPtr cgroup = opaque; + int rc; - VIR_DEBUG("Process path '%s' for disk", path); - rc = virCgroupDenyDevicePath(cgroup, path); - if (rc != 0) { - /* Get this for non-block devices */ - if (rc == -EINVAL) { - VIR_DEBUG("Ignoring EINVAL for %s", path); - } else if (rc == -EACCES) { /* Get this for root squash NFS */ - VIR_DEBUG("Ignoring EACCES for %s", path); - } else { - virReportSystemError(-rc, - _("Unable to deny device %s for %s"), - path, vm->def->name); - if (path != disk->src) - VIR_FREE(path); - goto cleanup; - } + VIR_DEBUG("Process path %s for disk", path); + /* XXX RO vs RW */ + rc = virCgroupDenyDevicePath(cgroup, path); + if (rc != 0) { + /* Get this for non-block devices */ + if (rc == -EINVAL) { + VIR_DEBUG("Ignoring EINVAL for %s", path); + } else if (rc == -EACCES) { /* Get this for root squash NFS */ + VIR_DEBUG("Ignoring EACCES for %s", path); + } else { + virReportSystemError(-rc, + _("Unable to allow access for disk path %s"), + path); + return -1; } - - rc = virStorageFileGetMetadata(path, - VIR_STORAGE_FILE_AUTO, - &meta); - if (rc < 0) - VIR_WARN("Unable to lookup parent image for %s", path); - - if (path != disk->src) - VIR_FREE(path); - path = NULL; - - if (rc < 0) - break; /* Treating as non fatal */ - - path = meta.backingStore; } + return 0; +} - ret = 0; -cleanup: - return ret; +static int qemuTeardownDiskCgroup(virCgroupPtr cgroup, + virDomainDiskDefPtr disk) +{ + return virDomainDiskDefForeachPath(disk, + true, + true, + qemuTeardownDiskPathDeny, + cgroup); } @@ -3204,7 +3179,7 @@ static int qemuSetupCgroup(struct qemud_driver *driver, } for (i = 0; i < vm->def->ndisks ; i++) { - if (qemuSetupDiskCgroup(cgroup, vm, vm->def->disks[i]) < 0) + if (qemuSetupDiskCgroup(cgroup, vm->def->disks[i]) < 0) goto cleanup; } @@ -8035,7 +8010,7 @@ static int qemudDomainAttachDevice(virDomainPtr dom, vm->def->name); goto endjob; } - if (qemuSetupDiskCgroup(cgroup, vm, dev->data.disk) < 0) + if (qemuSetupDiskCgroup(cgroup, dev->data.disk) < 0) goto endjob; } @@ -8080,7 +8055,7 @@ static int qemudDomainAttachDevice(virDomainPtr dom, /* Fallthrough */ } if (ret != 0 && cgroup) { - if (qemuTeardownDiskCgroup(cgroup, vm, dev->data.disk) < 0) + if (qemuTeardownDiskCgroup(cgroup, dev->data.disk) < 0) VIR_WARN("Failed to teardown cgroup for disk path %s", NULLSTR(dev->data.disk->src)); } @@ -8280,7 +8255,7 @@ static int qemuDomainUpdateDeviceFlags(virDomainPtr dom, vm->def->name); goto endjob; } - if (qemuSetupDiskCgroup(cgroup, vm, dev->data.disk) < 0) + if (qemuSetupDiskCgroup(cgroup, dev->data.disk) < 0) goto endjob; } @@ -8303,7 +8278,7 @@ static int qemuDomainUpdateDeviceFlags(virDomainPtr dom, } if (ret != 0 && cgroup) { - if (qemuTeardownDiskCgroup(cgroup, vm, dev->data.disk) < 0) + if (qemuTeardownDiskCgroup(cgroup, dev->data.disk) < 0) VIR_WARN("Failed to teardown cgroup for disk path %s", NULLSTR(dev->data.disk->src)); } @@ -8430,7 +8405,7 @@ static int qemudDomainDetachPciDiskDevice(struct qemud_driver *driver, VIR_WARN("Unable to restore security label on %s", dev->data.disk->src); if (cgroup != NULL) { - if (qemuTeardownDiskCgroup(cgroup, vm, dev->data.disk) < 0) + if (qemuTeardownDiskCgroup(cgroup, dev->data.disk) < 0) VIR_WARN("Failed to teardown cgroup for disk path %s", NULLSTR(dev->data.disk->src)); } @@ -8493,7 +8468,7 @@ static int qemudDomainDetachSCSIDiskDevice(struct qemud_driver *driver, VIR_WARN("Unable to restore security label on %s", dev->data.disk->src); if (cgroup != NULL) { - if (qemuTeardownDiskCgroup(cgroup, vm, dev->data.disk) < 0) + if (qemuTeardownDiskCgroup(cgroup, dev->data.disk) < 0) VIR_WARN("Failed to teardown cgroup for disk path %s", NULLSTR(dev->data.disk->src)); } diff --git a/src/qemu/qemu_security_dac.c b/src/qemu/qemu_security_dac.c index acfe48e..770010d 100644 --- a/src/qemu/qemu_security_dac.c +++ b/src/qemu/qemu_security_dac.c @@ -98,45 +98,28 @@ err: static int +qemuSecurityDACSetSecurityFileLabel(virDomainDiskDefPtr disk ATTRIBUTE_UNUSED, + const char *path, + size_t depth ATTRIBUTE_UNUSED, + void *opaque ATTRIBUTE_UNUSED) +{ + return qemuSecurityDACSetOwnership(path, driver->user, driver->group); +} + + +static int qemuSecurityDACSetSecurityImageLabel(virDomainObjPtr vm ATTRIBUTE_UNUSED, virDomainDiskDefPtr disk) { - const char *path; - if (!driver->privileged || !driver->dynamicOwnership) return 0; - if (!disk->src) - return 0; - - path = disk->src; - do { - virStorageFileMetadata meta; - int ret; - - ret = virStorageFileGetMetadata(path, - VIR_STORAGE_FILE_AUTO, - &meta); - - if (path != disk->src) - VIR_FREE(path); - path = NULL; - - if (ret < 0) - return -1; - - if (meta.backingStore != NULL && - qemuSecurityDACSetOwnership(meta.backingStore, - driver->user, driver->group) < 0) { - VIR_FREE(meta.backingStore); - return -1; - } - - path = meta.backingStore; - } while (path != NULL); - - return qemuSecurityDACSetOwnership(disk->src, driver->user, driver->group); + return virDomainDiskDefForeachPath(disk, + true, + false, + qemuSecurityDACSetSecurityFileLabel, + NULL); } diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c index 5c0f002..d191118 100644 --- a/src/security/security_selinux.c +++ b/src/security/security_selinux.c @@ -439,54 +439,43 @@ SELinuxRestoreSecurityImageLabel(virDomainObjPtr vm, static int +SELinuxSetSecurityFileLabel(virDomainDiskDefPtr disk, + const char *path, + size_t depth, + void *opaque) +{ + const virSecurityLabelDefPtr secdef = opaque; + + if (depth == 0) { + if (disk->shared) { + return SELinuxSetFilecon(path, default_image_context); + } else if (disk->readonly) { + return SELinuxSetFilecon(path, default_content_context); + } else if (secdef->imagelabel) { + return SELinuxSetFilecon(path, secdef->imagelabel); + } else { + return 0; + } + } else { + return SELinuxSetFilecon(path, default_content_context); + } +} + +static int SELinuxSetSecurityImageLabel(virDomainObjPtr vm, virDomainDiskDefPtr disk) { const virSecurityLabelDefPtr secdef = &vm->def->seclabel; - const char *path; if (secdef->type == VIR_DOMAIN_SECLABEL_STATIC) return 0; - if (!disk->src) - return 0; - - path = disk->src; - do { - virStorageFileMetadata meta; - int ret; - - ret = virStorageFileGetMetadata(path, - VIR_STORAGE_FILE_AUTO, - &meta); - - if (path != disk->src) - VIR_FREE(path); - path = NULL; - - if (ret < 0) - break; - - if (meta.backingStore != NULL && - SELinuxSetFilecon(meta.backingStore, - default_content_context) < 0) { - VIR_FREE(meta.backingStore); - return -1; - } - - path = meta.backingStore; - } while (path != NULL); - - if (disk->shared) { - return SELinuxSetFilecon(disk->src, default_image_context); - } else if (disk->readonly) { - return SELinuxSetFilecon(disk->src, default_content_context); - } else if (secdef->imagelabel) { - return SELinuxSetFilecon(disk->src, secdef->imagelabel); - } - - return 0; + return virDomainDiskDefForeachPath(disk, + true, + false, + SELinuxSetSecurityFileLabel, + secdef); } diff --git a/src/security/virt-aa-helper.c b/src/security/virt-aa-helper.c index 2c045e6..9ed0cd3 100644 --- a/src/security/virt-aa-helper.c +++ b/src/security/virt-aa-helper.c @@ -36,7 +36,6 @@ #include "uuid.h" #include "hostusb.h" #include "pci.h" -#include "storage_file.h" static char *progname; @@ -801,6 +800,28 @@ file_iterate_pci_cb(pciDevice *dev ATTRIBUTE_UNUSED, } static int +add_file_path(virDomainDiskDefPtr disk, + const char *path, + size_t depth, + void *opaque) +{ + virBufferPtr buf = opaque; + int ret; + + if (depth == 0) { + if (disk->readonly) + ret = vah_add_file(buf, path, "r"); + else + ret = vah_add_file(buf, path, "rw"); + } else { + ret = vah_add_file(buf, path, "r"); + } + + return ret; +} + + +static int get_files(vahControl * ctl) { virBuffer buf = VIR_BUFFER_INITIALIZER; @@ -821,45 +842,15 @@ get_files(vahControl * ctl) goto clean; } - for (i = 0; i < ctl->def->ndisks; i++) - if (ctl->def->disks[i] && ctl->def->disks[i]->src) { - int ret; - const char *path; - - path = ctl->def->disks[i]->src; - do { - virStorageFileMetadata meta; - - ret = virStorageFileGetMetadata(path, - VIR_STORAGE_FILE_AUTO, - &meta); - - if (path != ctl->def->disks[i]->src) - VIR_FREE(path); - path = NULL; - - if (ret < 0) { - vah_warning("could not open path, skipping"); - continue; - } - - if (meta.backingStore != NULL && - (ret = vah_add_file(&buf, meta.backingStore, "rw")) != 0) { - VIR_FREE(meta.backingStore); - goto clean; - } - - path = meta.backingStore; - } while (path != NULL); - - if (ctl->def->disks[i]->readonly) - ret = vah_add_file(&buf, ctl->def->disks[i]->src, "r"); - else - ret = vah_add_file(&buf, ctl->def->disks[i]->src, "rw"); - - if (ret != 0) - goto clean; - } + for (i = 0; i < ctl->def->ndisks; i++) { + int ret = virDomainDiskDefForeachPath(ctl->def->disks[i], + true, + false, + add_file_path, + &buf); + if (ret != 0) + goto clean; + } for (i = 0; i < ctl->def->nserials; i++) if (ctl->def->serials[i] && ctl->def->serials[i]->data.file.path) -- 1.7.1.1

On Mon, Jul 12, 2010 at 02:30:43PM +0100, Daniel P. Berrange wrote:
Update the QEMU cgroups code, QEMU DAC security driver, SELinux and AppArmour security drivers over to use the shared helper API virDomainDiskDefForeachPath().
* src/qemu/qemu_driver.c, src/qemu/qemu_security_dac.c, src/security/security_selinux.c, src/security/virt-aa-helper.c: Convert over to use virDomainDiskDefForeachPath() --- src/qemu/qemu_driver.c | 161 ++++++++++++++++---------------------- src/qemu/qemu_security_dac.c | 47 ++++-------- src/security/security_selinux.c | 67 +++++++---------- src/security/virt-aa-helper.c | 71 ++++++++---------- 4 files changed, 142 insertions(+), 204 deletions(-)
ACK, but that patch gave me headache ... or it's the accumulation :-) Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

The implementation of security driver callbacks often needs to access the security driver object. Currently only a handful of callbacks include the driver object as a parameter. Later patches require this is many more places. * src/qemu/qemu_driver.c: Pass in the security driver object to all callbacks * src/qemu/qemu_security_dac.c, src/qemu/qemu_security_stacked.c, src/security/security_apparmor.c, src/security/security_driver.h, src/security/security_selinux.c: Add a virSecurityDriverPtr param to all security callbacks --- src/qemu/qemu_driver.c | 88 ++++++++++++++++++++----------- src/qemu/qemu_security_dac.c | 44 +++++++++++----- src/qemu/qemu_security_stacked.c | 107 +++++++++++++++++++++++++------------- src/security/security_apparmor.c | 57 +++++++++++++------- src/security/security_driver.h | 40 ++++++++++---- src/security/security_selinux.c | 56 +++++++++++++------ 6 files changed, 260 insertions(+), 132 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 99aeffa..616547c 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -1278,7 +1278,8 @@ qemuReconnectDomain(void *payload, const char *name ATTRIBUTE_UNUSED, void *opaq if (driver->securityDriver && driver->securityDriver->domainReserveSecurityLabel && - driver->securityDriver->domainReserveSecurityLabel(obj) < 0) + driver->securityDriver->domainReserveSecurityLabel(driver->securityDriver, + obj) < 0) goto error; if (obj->def->id >= driver->nextvmid) @@ -3401,13 +3402,15 @@ static int qemudStartVMDaemon(virConnectPtr conn, DEBUG0("Generating domain security label (if required)"); if (driver->securityDriver && driver->securityDriver->domainGenSecurityLabel && - driver->securityDriver->domainGenSecurityLabel(vm) < 0) + driver->securityDriver->domainGenSecurityLabel(driver->securityDriver, + vm) < 0) goto cleanup; DEBUG0("Generating setting domain security labels (if required)"); if (driver->securityDriver && driver->securityDriver->domainSetSecurityAllLabel && - driver->securityDriver->domainSetSecurityAllLabel(vm, stdin_path) < 0) { + driver->securityDriver->domainSetSecurityAllLabel(driver->securityDriver, + vm, stdin_path) < 0) { if (stdin_path && virStorageFileIsSharedFS(stdin_path) != 1) goto cleanup; } @@ -3766,10 +3769,12 @@ static void qemudShutdownVMDaemon(struct qemud_driver *driver, /* Reset Security Labels */ if (driver->securityDriver && driver->securityDriver->domainRestoreSecurityAllLabel) - driver->securityDriver->domainRestoreSecurityAllLabel(vm, migrated); + driver->securityDriver->domainRestoreSecurityAllLabel(driver->securityDriver, + vm, migrated); if (driver->securityDriver && driver->securityDriver->domainReleaseSecurityLabel) - driver->securityDriver->domainReleaseSecurityLabel(vm); + driver->securityDriver->domainReleaseSecurityLabel(driver->securityDriver, + vm); /* Clear out dynamically assigned labels */ if (vm->def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC) { @@ -5171,7 +5176,8 @@ static int qemudDomainSaveFlag(virDomainPtr dom, const char *path, if ((!bypassSecurityDriver) && driver->securityDriver && driver->securityDriver->domainSetSavedStateLabel && - driver->securityDriver->domainSetSavedStateLabel(vm, path) == -1) + driver->securityDriver->domainSetSavedStateLabel(driver->securityDriver, + vm, path) == -1) goto endjob; if (header.compressed == QEMUD_SAVE_FORMAT_RAW) { @@ -5206,7 +5212,8 @@ static int qemudDomainSaveFlag(virDomainPtr dom, const char *path, if ((!bypassSecurityDriver) && driver->securityDriver && driver->securityDriver->domainRestoreSavedStateLabel && - driver->securityDriver->domainRestoreSavedStateLabel(vm, path) == -1) + driver->securityDriver->domainRestoreSavedStateLabel(driver->securityDriver, + vm, path) == -1) VIR_WARN("failed to restore save state label on %s", path); if (cgroup != NULL) { @@ -5253,7 +5260,8 @@ endjob: if ((!bypassSecurityDriver) && driver->securityDriver && driver->securityDriver->domainRestoreSavedStateLabel && - driver->securityDriver->domainRestoreSavedStateLabel(vm, path) == -1) + driver->securityDriver->domainRestoreSavedStateLabel(driver->securityDriver, + vm, path) == -1) VIR_WARN("failed to restore save state label on %s", path); } @@ -5488,7 +5496,8 @@ static int qemudDomainCoreDump(virDomainPtr dom, if (driver->securityDriver && driver->securityDriver->domainSetSavedStateLabel && - driver->securityDriver->domainSetSavedStateLabel(vm, path) == -1) + driver->securityDriver->domainSetSavedStateLabel(driver->securityDriver, + vm, path) == -1) goto endjob; /* Migrate will always stop the VM, so the resume condition is @@ -5531,7 +5540,8 @@ static int qemudDomainCoreDump(virDomainPtr dom, if (driver->securityDriver && driver->securityDriver->domainRestoreSavedStateLabel && - driver->securityDriver->domainRestoreSavedStateLabel(vm, path) == -1) + driver->securityDriver->domainRestoreSavedStateLabel(driver->securityDriver, + vm, path) == -1) goto endjob; endjob: @@ -5914,12 +5924,13 @@ static int qemudDomainGetSecurityLabel(virDomainPtr dom, virSecurityLabelPtr sec * QEMU monitor hasn't seen SIGHUP/ERR on poll(). */ if (virDomainObjIsActive(vm)) { - if (driver->securityDriver && driver->securityDriver->domainGetSecurityProcessLabel) { - if (driver->securityDriver->domainGetSecurityProcessLabel(vm, seclabel) == -1) { - qemuReportError(VIR_ERR_INTERNAL_ERROR, - "%s", _("Failed to get security label")); - goto cleanup; - } + if (driver->securityDriver && + driver->securityDriver->domainGetSecurityProcessLabel && + driver->securityDriver->domainGetSecurityProcessLabel(driver->securityDriver, + vm, seclabel) < 0) { + qemuReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("Failed to get security label")); + goto cleanup; } } @@ -6325,7 +6336,8 @@ qemudDomainSaveImageStartVM(virConnectPtr conn, out: if (driver->securityDriver && driver->securityDriver->domainRestoreSavedStateLabel && - driver->securityDriver->domainRestoreSavedStateLabel(vm, path) == -1) + driver->securityDriver->domainRestoreSavedStateLabel(driver->securityDriver, + vm, path) == -1) VIR_WARN("failed to restore save state label on %s", path); return ret; @@ -7039,7 +7051,8 @@ static int qemudDomainChangeEjectableMedia(struct qemud_driver *driver, if (driver->securityDriver && driver->securityDriver->domainSetSecurityImageLabel && - driver->securityDriver->domainSetSecurityImageLabel(vm, disk) < 0) + driver->securityDriver->domainSetSecurityImageLabel(driver->securityDriver, + vm, disk) < 0) return -1; if (!(driveAlias = qemuDeviceDriveHostAlias(origdisk, qemuCmdFlags))) @@ -7068,7 +7081,8 @@ static int qemudDomainChangeEjectableMedia(struct qemud_driver *driver, if (driver->securityDriver && driver->securityDriver->domainRestoreSecurityImageLabel && - driver->securityDriver->domainRestoreSecurityImageLabel(vm, origdisk) < 0) + driver->securityDriver->domainRestoreSecurityImageLabel(driver->securityDriver, + vm, origdisk) < 0) VIR_WARN("Unable to restore security label on ejected image %s", origdisk->src); VIR_FREE(origdisk->src); @@ -7086,7 +7100,8 @@ error: VIR_FREE(driveAlias); if (driver->securityDriver && driver->securityDriver->domainRestoreSecurityImageLabel && - driver->securityDriver->domainRestoreSecurityImageLabel(vm, disk) < 0) + driver->securityDriver->domainRestoreSecurityImageLabel(driver->securityDriver, + vm, disk) < 0) VIR_WARN("Unable to restore security label on new media %s", disk->src); return -1; } @@ -7113,7 +7128,8 @@ static int qemudDomainAttachPciDiskDevice(struct qemud_driver *driver, if (driver->securityDriver && driver->securityDriver->domainSetSecurityImageLabel && - driver->securityDriver->domainSetSecurityImageLabel(vm, disk) < 0) + driver->securityDriver->domainSetSecurityImageLabel(driver->securityDriver, + vm, disk) < 0) return -1; if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) { @@ -7180,7 +7196,8 @@ error: if (driver->securityDriver && driver->securityDriver->domainRestoreSecurityImageLabel && - driver->securityDriver->domainRestoreSecurityImageLabel(vm, disk) < 0) + driver->securityDriver->domainRestoreSecurityImageLabel(driver->securityDriver, + vm, disk) < 0) VIR_WARN("Unable to restore security label on %s", disk->src); return -1; @@ -7322,7 +7339,8 @@ static int qemudDomainAttachSCSIDisk(struct qemud_driver *driver, if (driver->securityDriver && driver->securityDriver->domainSetSecurityImageLabel && - driver->securityDriver->domainSetSecurityImageLabel(vm, disk) < 0) + driver->securityDriver->domainSetSecurityImageLabel(driver->securityDriver, + vm, disk) < 0) return -1; /* We should have an address already, so make sure */ @@ -7408,7 +7426,8 @@ error: if (driver->securityDriver && driver->securityDriver->domainRestoreSecurityImageLabel && - driver->securityDriver->domainRestoreSecurityImageLabel(vm, disk) < 0) + driver->securityDriver->domainRestoreSecurityImageLabel(driver->securityDriver, + vm, disk) < 0) VIR_WARN("Unable to restore security label on %s", disk->src); return -1; @@ -7435,7 +7454,8 @@ static int qemudDomainAttachUsbMassstorageDevice(struct qemud_driver *driver, if (driver->securityDriver && driver->securityDriver->domainSetSecurityImageLabel && - driver->securityDriver->domainSetSecurityImageLabel(vm, disk) < 0) + driver->securityDriver->domainSetSecurityImageLabel(driver->securityDriver, + vm, disk) < 0) return -1; if (!disk->src) { @@ -7491,7 +7511,8 @@ error: if (driver->securityDriver && driver->securityDriver->domainRestoreSecurityImageLabel && - driver->securityDriver->domainRestoreSecurityImageLabel(vm, disk) < 0) + driver->securityDriver->domainRestoreSecurityImageLabel(driver->securityDriver, + vm, disk) < 0) VIR_WARN("Unable to restore security label on %s", disk->src); return -1; @@ -7928,7 +7949,8 @@ static int qemudDomainAttachHostDevice(struct qemud_driver *driver, if (driver->securityDriver && driver->securityDriver->domainSetSecurityHostdevLabel && - driver->securityDriver->domainSetSecurityHostdevLabel(vm, hostdev) < 0) + driver->securityDriver->domainSetSecurityHostdevLabel(driver->securityDriver, + vm, hostdev) < 0) return -1; switch (hostdev->source.subsys.type) { @@ -7956,7 +7978,8 @@ static int qemudDomainAttachHostDevice(struct qemud_driver *driver, error: if (driver->securityDriver && driver->securityDriver->domainRestoreSecurityHostdevLabel && - driver->securityDriver->domainRestoreSecurityHostdevLabel(vm, hostdev) < 0) + driver->securityDriver->domainRestoreSecurityHostdevLabel(driver->securityDriver, + vm, hostdev) < 0) VIR_WARN0("Unable to restore host device labelling on hotplug fail"); return -1; @@ -8401,7 +8424,8 @@ static int qemudDomainDetachPciDiskDevice(struct qemud_driver *driver, if (driver->securityDriver && driver->securityDriver->domainRestoreSecurityImageLabel && - driver->securityDriver->domainRestoreSecurityImageLabel(vm, dev->data.disk) < 0) + driver->securityDriver->domainRestoreSecurityImageLabel(driver->securityDriver, + vm, dev->data.disk) < 0) VIR_WARN("Unable to restore security label on %s", dev->data.disk->src); if (cgroup != NULL) { @@ -8464,7 +8488,8 @@ static int qemudDomainDetachSCSIDiskDevice(struct qemud_driver *driver, if (driver->securityDriver && driver->securityDriver->domainRestoreSecurityImageLabel && - driver->securityDriver->domainRestoreSecurityImageLabel(vm, dev->data.disk) < 0) + driver->securityDriver->domainRestoreSecurityImageLabel(driver->securityDriver, + vm, dev->data.disk) < 0) VIR_WARN("Unable to restore security label on %s", dev->data.disk->src); if (cgroup != NULL) { @@ -8889,7 +8914,8 @@ static int qemudDomainDetachHostDevice(struct qemud_driver *driver, if (driver->securityDriver && driver->securityDriver->domainRestoreSecurityHostdevLabel && - driver->securityDriver->domainRestoreSecurityHostdevLabel(vm, dev->data.hostdev) < 0) + driver->securityDriver->domainRestoreSecurityHostdevLabel(driver->securityDriver, + vm, dev->data.hostdev) < 0) VIR_WARN0("Failed to restore host device labelling"); return ret; diff --git a/src/qemu/qemu_security_dac.c b/src/qemu/qemu_security_dac.c index 770010d..0bbcf69 100644 --- a/src/qemu/qemu_security_dac.c +++ b/src/qemu/qemu_security_dac.c @@ -108,7 +108,8 @@ qemuSecurityDACSetSecurityFileLabel(virDomainDiskDefPtr disk ATTRIBUTE_UNUSED, static int -qemuSecurityDACSetSecurityImageLabel(virDomainObjPtr vm ATTRIBUTE_UNUSED, +qemuSecurityDACSetSecurityImageLabel(virSecurityDriverPtr drv ATTRIBUTE_UNUSED, + virDomainObjPtr vm ATTRIBUTE_UNUSED, virDomainDiskDefPtr disk) { @@ -124,7 +125,8 @@ qemuSecurityDACSetSecurityImageLabel(virDomainObjPtr vm ATTRIBUTE_UNUSED, static int -qemuSecurityDACRestoreSecurityImageLabelInt(virDomainObjPtr vm ATTRIBUTE_UNUSED, +qemuSecurityDACRestoreSecurityImageLabelInt(virSecurityDriverPtr drv ATTRIBUTE_UNUSED, + virDomainObjPtr vm ATTRIBUTE_UNUSED, virDomainDiskDefPtr disk, int migrated) { @@ -166,10 +168,11 @@ qemuSecurityDACRestoreSecurityImageLabelInt(virDomainObjPtr vm ATTRIBUTE_UNUSED, static int -qemuSecurityDACRestoreSecurityImageLabel(virDomainObjPtr vm, +qemuSecurityDACRestoreSecurityImageLabel(virSecurityDriverPtr drv, + virDomainObjPtr vm, virDomainDiskDefPtr disk) { - return qemuSecurityDACRestoreSecurityImageLabelInt(vm, disk, 0); + return qemuSecurityDACRestoreSecurityImageLabelInt(drv, vm, disk, 0); } @@ -192,7 +195,8 @@ qemuSecurityDACSetSecurityUSBLabel(usbDevice *dev ATTRIBUTE_UNUSED, static int -qemuSecurityDACSetSecurityHostdevLabel(virDomainObjPtr vm, +qemuSecurityDACSetSecurityHostdevLabel(virSecurityDriverPtr drv ATTRIBUTE_UNUSED, + virDomainObjPtr vm, virDomainHostdevDefPtr dev) { @@ -261,7 +265,8 @@ qemuSecurityDACRestoreSecurityUSBLabel(usbDevice *dev ATTRIBUTE_UNUSED, static int -qemuSecurityDACRestoreSecurityHostdevLabel(virDomainObjPtr vm ATTRIBUTE_UNUSED, +qemuSecurityDACRestoreSecurityHostdevLabel(virSecurityDriverPtr drv ATTRIBUTE_UNUSED, + virDomainObjPtr vm ATTRIBUTE_UNUSED, virDomainHostdevDefPtr dev) { @@ -407,7 +412,8 @@ qemuSecurityDACRestoreChardevCallback(virDomainDefPtr def ATTRIBUTE_UNUSED, static int -qemuSecurityDACRestoreSecurityAllLabel(virDomainObjPtr vm, +qemuSecurityDACRestoreSecurityAllLabel(virSecurityDriverPtr drv, + virDomainObjPtr vm, int migrated) { int i; @@ -420,12 +426,14 @@ qemuSecurityDACRestoreSecurityAllLabel(virDomainObjPtr vm, vm->def->name, migrated); for (i = 0 ; i < vm->def->nhostdevs ; i++) { - if (qemuSecurityDACRestoreSecurityHostdevLabel(vm, + if (qemuSecurityDACRestoreSecurityHostdevLabel(drv, + vm, vm->def->hostdevs[i]) < 0) rc = -1; } for (i = 0 ; i < vm->def->ndisks ; i++) { - if (qemuSecurityDACRestoreSecurityImageLabelInt(vm, + if (qemuSecurityDACRestoreSecurityImageLabelInt(drv, + vm, vm->def->disks[i], migrated) < 0) rc = -1; @@ -461,7 +469,9 @@ qemuSecurityDACSetChardevCallback(virDomainDefPtr def ATTRIBUTE_UNUSED, static int -qemuSecurityDACSetSecurityAllLabel(virDomainObjPtr vm, const char *stdin_path ATTRIBUTE_UNUSED) +qemuSecurityDACSetSecurityAllLabel(virSecurityDriverPtr drv, + virDomainObjPtr vm, + const char *stdin_path ATTRIBUTE_UNUSED) { int i; @@ -472,11 +482,15 @@ qemuSecurityDACSetSecurityAllLabel(virDomainObjPtr vm, const char *stdin_path AT /* XXX fixme - we need to recursively label the entriy tree :-( */ if (vm->def->disks[i]->type == VIR_DOMAIN_DISK_TYPE_DIR) continue; - if (qemuSecurityDACSetSecurityImageLabel(vm, vm->def->disks[i]) < 0) + if (qemuSecurityDACSetSecurityImageLabel(drv, + vm, + vm->def->disks[i]) < 0) return -1; } for (i = 0 ; i < vm->def->nhostdevs ; i++) { - if (qemuSecurityDACSetSecurityHostdevLabel(vm, vm->def->hostdevs[i]) < 0) + if (qemuSecurityDACSetSecurityHostdevLabel(drv, + vm, + vm->def->hostdevs[i]) < 0) return -1; } @@ -503,7 +517,8 @@ qemuSecurityDACSetSecurityAllLabel(virDomainObjPtr vm, const char *stdin_path AT static int -qemuSecurityDACSetSavedStateLabel(virDomainObjPtr vm ATTRIBUTE_UNUSED, +qemuSecurityDACSetSavedStateLabel(virSecurityDriverPtr drv ATTRIBUTE_UNUSED, + virDomainObjPtr vm ATTRIBUTE_UNUSED, const char *savefile) { if (!driver->privileged) @@ -514,7 +529,8 @@ qemuSecurityDACSetSavedStateLabel(virDomainObjPtr vm ATTRIBUTE_UNUSED, static int -qemuSecurityDACRestoreSavedStateLabel(virDomainObjPtr vm ATTRIBUTE_UNUSED, +qemuSecurityDACRestoreSavedStateLabel(virSecurityDriverPtr drv ATTRIBUTE_UNUSED, + virDomainObjPtr vm ATTRIBUTE_UNUSED, const char *savefile) { if (!driver->privileged) diff --git a/src/qemu/qemu_security_stacked.c b/src/qemu/qemu_security_stacked.c index df76135..432d095 100644 --- a/src/qemu/qemu_security_stacked.c +++ b/src/qemu/qemu_security_stacked.c @@ -57,18 +57,21 @@ qemuSecurityStackedVerify(virDomainDefPtr def) static int -qemuSecurityStackedGenLabel(virDomainObjPtr vm) +qemuSecurityStackedGenLabel(virSecurityDriverPtr drv ATTRIBUTE_UNUSED, + virDomainObjPtr vm) { int rc = 0; if (driver->securitySecondaryDriver && driver->securitySecondaryDriver->domainGenSecurityLabel && - driver->securitySecondaryDriver->domainGenSecurityLabel(vm) < 0) + driver->securitySecondaryDriver->domainGenSecurityLabel(driver->securitySecondaryDriver, + vm) < 0) rc = -1; if (driver->securityPrimaryDriver && driver->securityPrimaryDriver->domainGenSecurityLabel && - driver->securityPrimaryDriver->domainGenSecurityLabel(vm) < 0) + driver->securityPrimaryDriver->domainGenSecurityLabel(driver->securityPrimaryDriver, + vm) < 0) rc = -1; return rc; @@ -76,18 +79,21 @@ qemuSecurityStackedGenLabel(virDomainObjPtr vm) static int -qemuSecurityStackedReleaseLabel(virDomainObjPtr vm) +qemuSecurityStackedReleaseLabel(virSecurityDriverPtr drv ATTRIBUTE_UNUSED, + virDomainObjPtr vm) { int rc = 0; if (driver->securitySecondaryDriver && driver->securitySecondaryDriver->domainReleaseSecurityLabel && - driver->securitySecondaryDriver->domainReleaseSecurityLabel(vm) < 0) + driver->securitySecondaryDriver->domainReleaseSecurityLabel(driver->securitySecondaryDriver, + vm) < 0) rc = -1; if (driver->securityPrimaryDriver && driver->securityPrimaryDriver->domainReleaseSecurityLabel && - driver->securityPrimaryDriver->domainReleaseSecurityLabel(vm) < 0) + driver->securityPrimaryDriver->domainReleaseSecurityLabel(driver->securityPrimaryDriver, + vm) < 0) rc = -1; return rc; @@ -95,18 +101,21 @@ qemuSecurityStackedReleaseLabel(virDomainObjPtr vm) static int -qemuSecurityStackedReserveLabel(virDomainObjPtr vm) +qemuSecurityStackedReserveLabel(virSecurityDriverPtr drv ATTRIBUTE_UNUSED, + virDomainObjPtr vm) { int rc = 0; if (driver->securitySecondaryDriver && driver->securitySecondaryDriver->domainReserveSecurityLabel && - driver->securitySecondaryDriver->domainReserveSecurityLabel(vm) < 0) + driver->securitySecondaryDriver->domainReserveSecurityLabel(driver->securitySecondaryDriver, + vm) < 0) rc = -1; if (driver->securityPrimaryDriver && driver->securityPrimaryDriver->domainReserveSecurityLabel && - driver->securityPrimaryDriver->domainReserveSecurityLabel(vm) < 0) + driver->securityPrimaryDriver->domainReserveSecurityLabel(driver->securityPrimaryDriver, + vm) < 0) rc = -1; return rc; @@ -114,19 +123,22 @@ qemuSecurityStackedReserveLabel(virDomainObjPtr vm) static int -qemuSecurityStackedSetSecurityImageLabel(virDomainObjPtr vm, +qemuSecurityStackedSetSecurityImageLabel(virSecurityDriverPtr drv ATTRIBUTE_UNUSED, + virDomainObjPtr vm, virDomainDiskDefPtr disk) { int rc = 0; if (driver->securitySecondaryDriver && driver->securitySecondaryDriver->domainSetSecurityImageLabel && - driver->securitySecondaryDriver->domainSetSecurityImageLabel(vm, disk) < 0) + driver->securitySecondaryDriver->domainSetSecurityImageLabel(driver->securitySecondaryDriver, + vm, disk) < 0) rc = -1; if (driver->securityPrimaryDriver && driver->securityPrimaryDriver->domainSetSecurityImageLabel && - driver->securityPrimaryDriver->domainSetSecurityImageLabel(vm, disk) < 0) + driver->securityPrimaryDriver->domainSetSecurityImageLabel(driver->securityPrimaryDriver, + vm, disk) < 0) rc = -1; return rc; @@ -134,19 +146,22 @@ qemuSecurityStackedSetSecurityImageLabel(virDomainObjPtr vm, static int -qemuSecurityStackedRestoreSecurityImageLabel(virDomainObjPtr vm, +qemuSecurityStackedRestoreSecurityImageLabel(virSecurityDriverPtr drv ATTRIBUTE_UNUSED, + virDomainObjPtr vm, virDomainDiskDefPtr disk) { int rc = 0; if (driver->securitySecondaryDriver && driver->securitySecondaryDriver->domainRestoreSecurityImageLabel && - driver->securitySecondaryDriver->domainRestoreSecurityImageLabel(vm, disk) < 0) + driver->securitySecondaryDriver->domainRestoreSecurityImageLabel(driver->securitySecondaryDriver, + vm, disk) < 0) rc = -1; if (driver->securityPrimaryDriver && driver->securityPrimaryDriver->domainRestoreSecurityImageLabel && - driver->securityPrimaryDriver->domainRestoreSecurityImageLabel(vm, disk) < 0) + driver->securityPrimaryDriver->domainRestoreSecurityImageLabel(driver->securityPrimaryDriver, + vm, disk) < 0) rc = -1; return rc; @@ -154,7 +169,8 @@ qemuSecurityStackedRestoreSecurityImageLabel(virDomainObjPtr vm, static int -qemuSecurityStackedSetSecurityHostdevLabel(virDomainObjPtr vm, +qemuSecurityStackedSetSecurityHostdevLabel(virSecurityDriverPtr drv ATTRIBUTE_UNUSED, + virDomainObjPtr vm, virDomainHostdevDefPtr dev) { @@ -162,12 +178,14 @@ qemuSecurityStackedSetSecurityHostdevLabel(virDomainObjPtr vm, if (driver->securitySecondaryDriver && driver->securitySecondaryDriver->domainSetSecurityHostdevLabel && - driver->securitySecondaryDriver->domainSetSecurityHostdevLabel(vm, dev) < 0) + driver->securitySecondaryDriver->domainSetSecurityHostdevLabel(driver->securitySecondaryDriver, + vm, dev) < 0) rc = -1; if (driver->securityPrimaryDriver && driver->securityPrimaryDriver->domainSetSecurityHostdevLabel && - driver->securityPrimaryDriver->domainSetSecurityHostdevLabel(vm, dev) < 0) + driver->securityPrimaryDriver->domainSetSecurityHostdevLabel(driver->securityPrimaryDriver, + vm, dev) < 0) rc = -1; return rc; @@ -175,20 +193,22 @@ qemuSecurityStackedSetSecurityHostdevLabel(virDomainObjPtr vm, static int -qemuSecurityStackedRestoreSecurityHostdevLabel(virDomainObjPtr vm, +qemuSecurityStackedRestoreSecurityHostdevLabel(virSecurityDriverPtr drv ATTRIBUTE_UNUSED, + virDomainObjPtr vm, virDomainHostdevDefPtr dev) - { int rc = 0; if (driver->securitySecondaryDriver && driver->securitySecondaryDriver->domainRestoreSecurityHostdevLabel && - driver->securitySecondaryDriver->domainRestoreSecurityHostdevLabel(vm, dev) < 0) + driver->securitySecondaryDriver->domainRestoreSecurityHostdevLabel(driver->securitySecondaryDriver, + vm, dev) < 0) rc = -1; if (driver->securityPrimaryDriver && driver->securityPrimaryDriver->domainRestoreSecurityHostdevLabel && - driver->securityPrimaryDriver->domainRestoreSecurityHostdevLabel(vm, dev) < 0) + driver->securityPrimaryDriver->domainRestoreSecurityHostdevLabel(driver->securityPrimaryDriver, + vm, dev) < 0) rc = -1; return rc; @@ -196,18 +216,22 @@ qemuSecurityStackedRestoreSecurityHostdevLabel(virDomainObjPtr vm, static int -qemuSecurityStackedSetSecurityAllLabel(virDomainObjPtr vm, const char *stdin_path) +qemuSecurityStackedSetSecurityAllLabel(virSecurityDriverPtr drv ATTRIBUTE_UNUSED, + virDomainObjPtr vm, + const char *stdin_path) { int rc = 0; if (driver->securitySecondaryDriver && driver->securitySecondaryDriver->domainSetSecurityAllLabel && - driver->securitySecondaryDriver->domainSetSecurityAllLabel(vm, stdin_path) < 0) + driver->securitySecondaryDriver->domainSetSecurityAllLabel(driver->securitySecondaryDriver, + vm, stdin_path) < 0) rc = -1; if (driver->securityPrimaryDriver && driver->securityPrimaryDriver->domainSetSecurityAllLabel && - driver->securityPrimaryDriver->domainSetSecurityAllLabel(vm, stdin_path) < 0) + driver->securityPrimaryDriver->domainSetSecurityAllLabel(driver->securityPrimaryDriver, + vm, stdin_path) < 0) rc = -1; return rc; @@ -215,19 +239,22 @@ qemuSecurityStackedSetSecurityAllLabel(virDomainObjPtr vm, const char *stdin_pat static int -qemuSecurityStackedRestoreSecurityAllLabel(virDomainObjPtr vm, +qemuSecurityStackedRestoreSecurityAllLabel(virSecurityDriverPtr drv ATTRIBUTE_UNUSED, + virDomainObjPtr vm, int migrated) { int rc = 0; if (driver->securitySecondaryDriver && driver->securitySecondaryDriver->domainRestoreSecurityAllLabel && - driver->securitySecondaryDriver->domainRestoreSecurityAllLabel(vm, migrated) < 0) + driver->securitySecondaryDriver->domainRestoreSecurityAllLabel(driver->securitySecondaryDriver, + vm, migrated) < 0) rc = -1; if (driver->securityPrimaryDriver && driver->securityPrimaryDriver->domainRestoreSecurityAllLabel && - driver->securityPrimaryDriver->domainRestoreSecurityAllLabel(vm, migrated) < 0) + driver->securityPrimaryDriver->domainRestoreSecurityAllLabel(driver->securityPrimaryDriver, + vm, migrated) < 0) rc = -1; return rc; @@ -235,19 +262,22 @@ qemuSecurityStackedRestoreSecurityAllLabel(virDomainObjPtr vm, static int -qemuSecurityStackedSetSavedStateLabel(virDomainObjPtr vm, +qemuSecurityStackedSetSavedStateLabel(virSecurityDriverPtr drv ATTRIBUTE_UNUSED, + virDomainObjPtr vm, const char *savefile) { int rc = 0; if (driver->securitySecondaryDriver && driver->securitySecondaryDriver->domainSetSavedStateLabel && - driver->securitySecondaryDriver->domainSetSavedStateLabel(vm, savefile) < 0) + driver->securitySecondaryDriver->domainSetSavedStateLabel(driver->securitySecondaryDriver, + vm, savefile) < 0) rc = -1; if (driver->securityPrimaryDriver && driver->securityPrimaryDriver->domainSetSavedStateLabel && - driver->securityPrimaryDriver->domainSetSavedStateLabel(vm, savefile) < 0) + driver->securityPrimaryDriver->domainSetSavedStateLabel(driver->securityPrimaryDriver, + vm, savefile) < 0) rc = -1; return rc; @@ -255,19 +285,22 @@ qemuSecurityStackedSetSavedStateLabel(virDomainObjPtr vm, static int -qemuSecurityStackedRestoreSavedStateLabel(virDomainObjPtr vm, +qemuSecurityStackedRestoreSavedStateLabel(virSecurityDriverPtr drv ATTRIBUTE_UNUSED, + virDomainObjPtr vm, const char *savefile) { int rc = 0; if (driver->securitySecondaryDriver && driver->securitySecondaryDriver->domainRestoreSavedStateLabel && - driver->securitySecondaryDriver->domainRestoreSavedStateLabel(vm, savefile) < 0) + driver->securitySecondaryDriver->domainRestoreSavedStateLabel(driver->securitySecondaryDriver, + vm, savefile) < 0) rc = -1; if (driver->securityPrimaryDriver && driver->securityPrimaryDriver->domainRestoreSavedStateLabel && - driver->securityPrimaryDriver->domainRestoreSavedStateLabel(vm, savefile) < 0) + driver->securityPrimaryDriver->domainRestoreSavedStateLabel(driver->securityPrimaryDriver, + vm, savefile) < 0) rc = -1; return rc; @@ -296,14 +329,16 @@ qemuSecurityStackedSetProcessLabel(virSecurityDriverPtr drv ATTRIBUTE_UNUSED, } static int -qemuSecurityStackedGetProcessLabel(virDomainObjPtr vm, +qemuSecurityStackedGetProcessLabel(virSecurityDriverPtr drv ATTRIBUTE_UNUSED, + virDomainObjPtr vm, virSecurityLabelPtr seclabel) { int rc = 0; if (driver->securityPrimaryDriver && driver->securityPrimaryDriver->domainGetSecurityProcessLabel && - driver->securityPrimaryDriver->domainGetSecurityProcessLabel(vm, + driver->securityPrimaryDriver->domainGetSecurityProcessLabel(driver->securityPrimaryDriver, + vm, seclabel) < 0) rc = -1; diff --git a/src/security/security_apparmor.c b/src/security/security_apparmor.c index e883f69..cb5c739 100644 --- a/src/security/security_apparmor.c +++ b/src/security/security_apparmor.c @@ -148,7 +148,8 @@ profile_status_file(const char *str) * load (add) a profile. Will create one if necessary */ static int -load_profile(const char *profile, virDomainObjPtr vm, +load_profile(virSecurityDriverPtr drv, + const char *profile, virDomainObjPtr vm, const char *fn) { int rc = -1, status, ret; @@ -281,7 +282,8 @@ cleanup: * NULL. */ static int -reload_profile(virDomainObjPtr vm, const char *fn) +reload_profile(virSecurityDriverPtr drv, + virDomainObjPtr vm, const char *fn) { const virSecurityLabelDefPtr secdef = &vm->def->seclabel; int rc = -1; @@ -295,7 +297,7 @@ reload_profile(virDomainObjPtr vm, const char *fn) /* Update the profile only if it is loaded */ if (profile_loaded(secdef->imagelabel) >= 0) { - if (load_profile(secdef->imagelabel, vm, fn) < 0) { + if (load_profile(drv, secdef->imagelabel, vm, fn) < 0) { virSecurityReportError(VIR_ERR_INTERNAL_ERROR, _("cannot update AppArmor profile " "\'%s\'"), @@ -357,7 +359,8 @@ AppArmorSecurityDriverOpen(virSecurityDriverPtr drv) * called on shutdown. */ static int -AppArmorGenSecurityLabel(virDomainObjPtr vm) +AppArmorGenSecurityLabel(virSecurityDriverPtr drv ATTRIBUTE_UNUSED, + virDomainObjPtr vm) { int rc = -1; char *profile_name = NULL; @@ -411,14 +414,15 @@ AppArmorGenSecurityLabel(virDomainObjPtr vm) } static int -AppArmorSetSecurityAllLabel(virDomainObjPtr vm, const char *stdin_path) +AppArmorSetSecurityAllLabel(virSecurityDriverPtr drv, + virDomainObjPtr vm, const char *stdin_path) { if (vm->def->seclabel.type == VIR_DOMAIN_SECLABEL_STATIC) return 0; /* if the profile is not already loaded, then load one */ if (profile_loaded(vm->def->seclabel.label) < 0) { - if (load_profile(vm->def->seclabel.label, vm, stdin_path) < 0) { + if (load_profile(drv, vm->def->seclabel.label, vm, stdin_path) < 0) { virSecurityReportError(VIR_ERR_INTERNAL_ERROR, _("cannot generate AppArmor profile " "\'%s\'"), vm->def->seclabel.label); @@ -433,7 +437,9 @@ AppArmorSetSecurityAllLabel(virDomainObjPtr vm, const char *stdin_path) * running. */ static int -AppArmorGetSecurityProcessLabel(virDomainObjPtr vm, virSecurityLabelPtr sec) +AppArmorGetSecurityProcessLabel(virSecurityDriverPtr drv ATTRIBUTE_UNUSED, + virDomainObjPtr vm, + virSecurityLabelPtr sec) { int rc = -1; char *profile_name = NULL; @@ -465,7 +471,8 @@ AppArmorGetSecurityProcessLabel(virDomainObjPtr vm, virSecurityLabelPtr sec) * more details. Currently called via qemudShutdownVMDaemon. */ static int -AppArmorReleaseSecurityLabel(virDomainObjPtr vm) +AppArmorReleaseSecurityLabel(virSecurityDriverPtr drv ATTRIBUTE_UNUSED, + virDomainObjPtr vm) { const virSecurityLabelDefPtr secdef = &vm->def->seclabel; @@ -478,7 +485,8 @@ AppArmorReleaseSecurityLabel(virDomainObjPtr vm) static int -AppArmorRestoreSecurityAllLabel(virDomainObjPtr vm, +AppArmorRestoreSecurityAllLabel(virSecurityDriverPtr drv ATTRIBUTE_UNUSED, + virDomainObjPtr vm, int migrated ATTRIBUTE_UNUSED) { const virSecurityLabelDefPtr secdef = &vm->def->seclabel; @@ -533,15 +541,17 @@ AppArmorSetSecurityProcessLabel(virSecurityDriverPtr drv, virDomainObjPtr vm) /* Called when hotplugging */ static int -AppArmorRestoreSecurityImageLabel(virDomainObjPtr vm, +AppArmorRestoreSecurityImageLabel(virSecurityDriverPtr drv, + virDomainObjPtr vm, virDomainDiskDefPtr disk ATTRIBUTE_UNUSED) { - return reload_profile(vm, NULL); + return reload_profile(drv, vm, NULL); } /* Called when hotplugging */ static int -AppArmorSetSecurityImageLabel(virDomainObjPtr vm, virDomainDiskDefPtr disk) +AppArmorSetSecurityImageLabel(virSecurityDriverPtr drv, + virDomainObjPtr vm, virDomainDiskDefPtr disk) { const virSecurityLabelDefPtr secdef = &vm->def->seclabel; int rc = -1; @@ -566,7 +576,7 @@ AppArmorSetSecurityImageLabel(virDomainObjPtr vm, virDomainDiskDefPtr disk) /* update the profile only if it is loaded */ if (profile_loaded(secdef->imagelabel) >= 0) { - if (load_profile(secdef->imagelabel, vm, disk->src) < 0) { + if (load_profile(drv, secdef->imagelabel, vm, disk->src) < 0) { virSecurityReportError(VIR_ERR_INTERNAL_ERROR, _("cannot update AppArmor profile " "\'%s\'"), @@ -600,14 +610,16 @@ AppArmorSecurityVerify(virDomainDefPtr def) } static int -AppArmorReserveSecurityLabel(virDomainObjPtr vm ATTRIBUTE_UNUSED) +AppArmorReserveSecurityLabel(virSecurityDriverPtr drv ATTRIBUTE_UNUSED, + virDomainObjPtr vm ATTRIBUTE_UNUSED) { /* NOOP. Nothing to reserve with AppArmor */ return 0; } static int -AppArmorSetSecurityHostdevLabel(virDomainObjPtr vm, +AppArmorSetSecurityHostdevLabel(virSecurityDriverPtr drv ATTRIBUTE_UNUSED, + virDomainObjPtr vm, virDomainHostdevDefPtr dev ATTRIBUTE_UNUSED) { @@ -621,7 +633,8 @@ AppArmorSetSecurityHostdevLabel(virDomainObjPtr vm, } static int -AppArmorRestoreSecurityHostdevLabel(virDomainObjPtr vm, +AppArmorRestoreSecurityHostdevLabel(virSecurityDriverPtr drv ATTRIBUTE_UNUSED, + virDomainObjPtr vm, virDomainHostdevDefPtr dev ATTRIBUTE_UNUSED) { @@ -634,18 +647,20 @@ AppArmorRestoreSecurityHostdevLabel(virDomainObjPtr vm, } static int -AppArmorSetSavedStateLabel(virDomainObjPtr vm, - const char *savefile) +AppArmorSetSavedStateLabel(virSecurityDriverPtr drv, + virDomainObjPtr vm, + const char *savefile) { - return reload_profile(vm, savefile); + return reload_profile(drv, vm, savefile); } static int -AppArmorRestoreSavedStateLabel(virDomainObjPtr vm, +AppArmorRestoreSavedStateLabel(virSecurityDriverPtr drv, + virDomainObjPtr vm, const char *savefile ATTRIBUTE_UNUSED) { - return reload_profile(vm, NULL); + return reload_profile(drv, vm, NULL); } virSecurityDriver virAppArmorSecurityDriver = { diff --git a/src/security/security_driver.h b/src/security/security_driver.h index 99260a4..61c9eb0 100644 --- a/src/security/security_driver.h +++ b/src/security/security_driver.h @@ -28,32 +28,48 @@ typedef enum { typedef struct _virSecurityDriver virSecurityDriver; typedef virSecurityDriver *virSecurityDriverPtr; + +typedef struct _virSecurityDriverState virSecurityDriverState; +typedef virSecurityDriverState *virSecurityDriverStatePtr; + typedef virSecurityDriverStatus (*virSecurityDriverProbe) (void); typedef int (*virSecurityDriverOpen) (virSecurityDriverPtr drv); -typedef int (*virSecurityDomainRestoreImageLabel) (virDomainObjPtr vm, +typedef int (*virSecurityDomainRestoreImageLabel) (virSecurityDriverPtr drv, + virDomainObjPtr vm, virDomainDiskDefPtr disk); typedef int (*virSecurityDomainSetSocketLabel) (virSecurityDriverPtr drv, virDomainObjPtr vm); typedef int (*virSecurityDomainClearSocketLabel)(virSecurityDriverPtr drv, virDomainObjPtr vm); -typedef int (*virSecurityDomainSetImageLabel) (virDomainObjPtr vm, +typedef int (*virSecurityDomainSetImageLabel) (virSecurityDriverPtr drv, + virDomainObjPtr vm, virDomainDiskDefPtr disk); -typedef int (*virSecurityDomainRestoreHostdevLabel) (virDomainObjPtr vm, +typedef int (*virSecurityDomainRestoreHostdevLabel) (virSecurityDriverPtr drv, + virDomainObjPtr vm, virDomainHostdevDefPtr dev); -typedef int (*virSecurityDomainSetHostdevLabel) (virDomainObjPtr vm, +typedef int (*virSecurityDomainSetHostdevLabel) (virSecurityDriverPtr drv, + virDomainObjPtr vm, virDomainHostdevDefPtr dev); -typedef int (*virSecurityDomainSetSavedStateLabel) (virDomainObjPtr vm, +typedef int (*virSecurityDomainSetSavedStateLabel) (virSecurityDriverPtr drv, + virDomainObjPtr vm, const char *savefile); -typedef int (*virSecurityDomainRestoreSavedStateLabel) (virDomainObjPtr vm, +typedef int (*virSecurityDomainRestoreSavedStateLabel) (virSecurityDriverPtr drv, + virDomainObjPtr vm, const char *savefile); -typedef int (*virSecurityDomainGenLabel) (virDomainObjPtr sec); -typedef int (*virSecurityDomainReserveLabel) (virDomainObjPtr sec); -typedef int (*virSecurityDomainReleaseLabel) (virDomainObjPtr sec); -typedef int (*virSecurityDomainSetAllLabel) (virDomainObjPtr sec, +typedef int (*virSecurityDomainGenLabel) (virSecurityDriverPtr drv, + virDomainObjPtr sec); +typedef int (*virSecurityDomainReserveLabel) (virSecurityDriverPtr drv, + virDomainObjPtr sec); +typedef int (*virSecurityDomainReleaseLabel) (virSecurityDriverPtr drv, + virDomainObjPtr sec); +typedef int (*virSecurityDomainSetAllLabel) (virSecurityDriverPtr drv, + virDomainObjPtr sec, const char *stdin_path); -typedef int (*virSecurityDomainRestoreAllLabel) (virDomainObjPtr vm, +typedef int (*virSecurityDomainRestoreAllLabel) (virSecurityDriverPtr drv, + virDomainObjPtr vm, int migrated); -typedef int (*virSecurityDomainGetProcessLabel) (virDomainObjPtr vm, +typedef int (*virSecurityDomainGetProcessLabel) (virSecurityDriverPtr drv, + virDomainObjPtr vm, virSecurityLabelPtr sec); typedef int (*virSecurityDomainSetProcessLabel) (virSecurityDriverPtr drv, virDomainObjPtr vm); diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c index d191118..cc3812b 100644 --- a/src/security/security_selinux.c +++ b/src/security/security_selinux.c @@ -156,7 +156,8 @@ SELinuxInitialize(void) } static int -SELinuxGenSecurityLabel(virDomainObjPtr vm) +SELinuxGenSecurityLabel(virSecurityDriverPtr drv ATTRIBUTE_UNUSED, + virDomainObjPtr vm) { int rc = -1; char mcs[1024]; @@ -220,7 +221,8 @@ done: } static int -SELinuxReserveSecurityLabel(virDomainObjPtr vm) +SELinuxReserveSecurityLabel(virSecurityDriverPtr drv ATTRIBUTE_UNUSED, + virDomainObjPtr vm) { security_context_t pctx; context_t ctx = NULL; @@ -275,7 +277,8 @@ SELinuxSecurityDriverOpen(virSecurityDriverPtr drv) } static int -SELinuxGetSecurityProcessLabel(virDomainObjPtr vm, +SELinuxGetSecurityProcessLabel(virSecurityDriverPtr drv ATTRIBUTE_UNUSED, + virDomainObjPtr vm, virSecurityLabelPtr sec) { security_context_t ctx; @@ -387,7 +390,8 @@ err: } static int -SELinuxRestoreSecurityImageLabelInt(virDomainObjPtr vm, +SELinuxRestoreSecurityImageLabelInt(virSecurityDriverPtr drv ATTRIBUTE_UNUSED, + virDomainObjPtr vm, virDomainDiskDefPtr disk, int migrated) { @@ -431,10 +435,11 @@ SELinuxRestoreSecurityImageLabelInt(virDomainObjPtr vm, static int -SELinuxRestoreSecurityImageLabel(virDomainObjPtr vm, +SELinuxRestoreSecurityImageLabel(virSecurityDriverPtr drv, + virDomainObjPtr vm, virDomainDiskDefPtr disk) { - return SELinuxRestoreSecurityImageLabelInt(vm, disk, 0); + return SELinuxRestoreSecurityImageLabelInt(drv, vm, disk, 0); } @@ -462,7 +467,8 @@ SELinuxSetSecurityFileLabel(virDomainDiskDefPtr disk, } static int -SELinuxSetSecurityImageLabel(virDomainObjPtr vm, +SELinuxSetSecurityImageLabel(virSecurityDriverPtr drv ATTRIBUTE_UNUSED, + virDomainObjPtr vm, virDomainDiskDefPtr disk) { @@ -500,7 +506,8 @@ SELinuxSetSecurityUSBLabel(usbDevice *dev ATTRIBUTE_UNUSED, } static int -SELinuxSetSecurityHostdevLabel(virDomainObjPtr vm, +SELinuxSetSecurityHostdevLabel(virSecurityDriverPtr drv ATTRIBUTE_UNUSED, + virDomainObjPtr vm, virDomainHostdevDefPtr dev) { @@ -568,7 +575,8 @@ SELinuxRestoreSecurityUSBLabel(usbDevice *dev ATTRIBUTE_UNUSED, } static int -SELinuxRestoreSecurityHostdevLabel(virDomainObjPtr vm, +SELinuxRestoreSecurityHostdevLabel(virSecurityDriverPtr drv ATTRIBUTE_UNUSED, + virDomainObjPtr vm, virDomainHostdevDefPtr dev) { @@ -715,7 +723,8 @@ SELinuxRestoreSecurityChardevCallback(virDomainDefPtr def ATTRIBUTE_UNUSED, static int -SELinuxRestoreSecurityAllLabel(virDomainObjPtr vm, +SELinuxRestoreSecurityAllLabel(virSecurityDriverPtr drv ATTRIBUTE_UNUSED, + virDomainObjPtr vm, int migrated ATTRIBUTE_UNUSED) { const virSecurityLabelDefPtr secdef = &vm->def->seclabel; @@ -728,11 +737,14 @@ SELinuxRestoreSecurityAllLabel(virDomainObjPtr vm, return 0; for (i = 0 ; i < vm->def->nhostdevs ; i++) { - if (SELinuxRestoreSecurityHostdevLabel(vm, vm->def->hostdevs[i]) < 0) + if (SELinuxRestoreSecurityHostdevLabel(drv, + vm, + vm->def->hostdevs[i]) < 0) rc = -1; } for (i = 0 ; i < vm->def->ndisks ; i++) { - if (SELinuxRestoreSecurityImageLabelInt(vm, + if (SELinuxRestoreSecurityImageLabelInt(drv, + vm, vm->def->disks[i], migrated) < 0) rc = -1; @@ -756,7 +768,8 @@ SELinuxRestoreSecurityAllLabel(virDomainObjPtr vm, } static int -SELinuxReleaseSecurityLabel(virDomainObjPtr vm) +SELinuxReleaseSecurityLabel(virSecurityDriverPtr drv ATTRIBUTE_UNUSED, + virDomainObjPtr vm) { const virSecurityLabelDefPtr secdef = &vm->def->seclabel; @@ -779,7 +792,8 @@ SELinuxReleaseSecurityLabel(virDomainObjPtr vm) static int -SELinuxSetSavedStateLabel(virDomainObjPtr vm, +SELinuxSetSavedStateLabel(virSecurityDriverPtr drv ATTRIBUTE_UNUSED, + virDomainObjPtr vm, const char *savefile) { const virSecurityLabelDefPtr secdef = &vm->def->seclabel; @@ -792,7 +806,8 @@ SELinuxSetSavedStateLabel(virDomainObjPtr vm, static int -SELinuxRestoreSavedStateLabel(virDomainObjPtr vm, +SELinuxRestoreSavedStateLabel(virSecurityDriverPtr drv ATTRIBUTE_UNUSED, + virDomainObjPtr vm, const char *savefile) { const virSecurityLabelDefPtr secdef = &vm->def->seclabel; @@ -963,7 +978,9 @@ SELinuxSetSecurityChardevCallback(virDomainDefPtr def ATTRIBUTE_UNUSED, static int -SELinuxSetSecurityAllLabel(virDomainObjPtr vm, const char *stdin_path) +SELinuxSetSecurityAllLabel(virSecurityDriverPtr drv, + virDomainObjPtr vm, + const char *stdin_path) { const virSecurityLabelDefPtr secdef = &vm->def->seclabel; int i; @@ -978,11 +995,14 @@ SELinuxSetSecurityAllLabel(virDomainObjPtr vm, const char *stdin_path) vm->def->disks[i]->src, vm->def->disks[i]->dst); continue; } - if (SELinuxSetSecurityImageLabel(vm, vm->def->disks[i]) < 0) + if (SELinuxSetSecurityImageLabel(drv, + vm, vm->def->disks[i]) < 0) return -1; } for (i = 0 ; i < vm->def->nhostdevs ; i++) { - if (SELinuxSetSecurityHostdevLabel(vm, vm->def->hostdevs[i]) < 0) + if (SELinuxSetSecurityHostdevLabel(drv, + vm, + vm->def->hostdevs[i]) < 0) return -1; } -- 1.7.1.1

On Mon, Jul 12, 2010 at 02:30:44PM +0100, Daniel P. Berrange wrote:
The implementation of security driver callbacks often needs to access the security driver object. Currently only a handful of callbacks include the driver object as a parameter. Later patches require this is many more places.
* src/qemu/qemu_driver.c: Pass in the security driver object to all callbacks * src/qemu/qemu_security_dac.c, src/qemu/qemu_security_stacked.c, src/security/security_apparmor.c, src/security/security_driver.h, src/security/security_selinux.c: Add a virSecurityDriverPtr param to all security callbacks
ACK, Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

Disk format probing is now disabled by default. A new config option in /etc/qemu/qemu.conf will re-enable it for existing deployments where this causes trouble --- src/qemu/libvirtd_qemu.aug | 1 + src/qemu/qemu.conf | 12 ++++++++++++ src/qemu/qemu_conf.c | 4 ++++ src/qemu/qemu_conf.h | 1 + src/qemu/qemu_driver.c | 36 +++++++++++++++++++++++------------- src/qemu/qemu_security_dac.c | 2 +- src/qemu/test_libvirtd_qemu.aug | 4 ++++ src/security/security_apparmor.c | 12 ++++++++---- src/security/security_driver.c | 16 ++++++++++++++-- src/security/security_driver.h | 10 ++++++++-- src/security/security_selinux.c | 9 ++++++--- src/security/virt-aa-helper.c | 10 +++++++++- tests/seclabeltest.c | 2 +- 13 files changed, 92 insertions(+), 27 deletions(-) diff --git a/src/qemu/libvirtd_qemu.aug b/src/qemu/libvirtd_qemu.aug index 7c9f271..47d0525 100644 --- a/src/qemu/libvirtd_qemu.aug +++ b/src/qemu/libvirtd_qemu.aug @@ -40,6 +40,7 @@ module Libvirtd_qemu = | bool_entry "relaxed_acs_check" | bool_entry "vnc_allow_host_audio" | bool_entry "clear_emulator_capabilities" + | bool_entry "allow_disk_format_probing" (* Each enty in the config is one of the following three ... *) let entry = vnc_entry diff --git a/src/qemu/qemu.conf b/src/qemu/qemu.conf index 93934f3..dc8eb83 100644 --- a/src/qemu/qemu.conf +++ b/src/qemu/qemu.conf @@ -187,3 +187,15 @@ # exploit the privileges and possibly do damage to the host. # # clear_emulator_capabilities = 1 + + + +# If allow_disk_format_probing is enabled, libvirt will probe disk +# images to attempt to identify their format, when not otherwise +# specified in the XML. This is disabled by default. +# +# WARNING: Enabling probing is a security hole in almost all +# deployments. It is strongly recommended that users update their +# guest XML <disk> elements to include <driver type='XXXX'/> +# elements instead of enabling this option. +# allow_disk_format_probing = 1 diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c index 988220b..3ba48bf 100644 --- a/src/qemu/qemu_conf.c +++ b/src/qemu/qemu_conf.c @@ -365,6 +365,10 @@ int qemudLoadDriverConfig(struct qemud_driver *driver, CHECK_TYPE ("clear_emulator_capabilities", VIR_CONF_LONG); if (p) driver->clearEmulatorCapabilities = p->l; + p = virConfGetValue (conf, "allow_disk_format_probing"); + CHECK_TYPE ("allow_disk_format_probing", VIR_CONF_LONG); + if (p) driver->allowDiskFormatProbing = p->l; + virConfFree (conf); return 0; } diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h index ab5f158..30e9f20 100644 --- a/src/qemu/qemu_conf.h +++ b/src/qemu/qemu_conf.h @@ -141,6 +141,7 @@ struct qemud_driver { unsigned int relaxedACS : 1; unsigned int vncAllowHostAudio : 1; unsigned int clearEmulatorCapabilities : 1; + unsigned int allowDiskFormatProbing : 1; virCapsPtr caps; diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 616547c..3c479c5 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -1322,7 +1322,8 @@ qemudSecurityInit(struct qemud_driver *qemud_drv) qemuSecurityDACSetDriver(qemud_drv); ret = virSecurityDriverStartup(&security_drv, - qemud_drv->securityDriverName); + qemud_drv->securityDriverName, + qemud_drv->allowDiskFormatProbing); if (ret == -1) { VIR_ERROR0(_("Failed to start security driver")); return -1; @@ -3070,11 +3071,12 @@ static int qemuSetupDiskPathAllow(virDomainDiskDefPtr disk ATTRIBUTE_UNUSED, } -static int qemuSetupDiskCgroup(virCgroupPtr cgroup, +static int qemuSetupDiskCgroup(struct qemud_driver *driver, + virCgroupPtr cgroup, virDomainDiskDefPtr disk) { return virDomainDiskDefForeachPath(disk, - true, + driver->allowDiskFormatProbing, true, qemuSetupDiskPathAllow, cgroup); @@ -3109,11 +3111,12 @@ static int qemuTeardownDiskPathDeny(virDomainDiskDefPtr disk ATTRIBUTE_UNUSED, } -static int qemuTeardownDiskCgroup(virCgroupPtr cgroup, +static int qemuTeardownDiskCgroup(struct qemud_driver *driver, + virCgroupPtr cgroup, virDomainDiskDefPtr disk) { return virDomainDiskDefForeachPath(disk, - true, + driver->allowDiskFormatProbing, true, qemuTeardownDiskPathDeny, cgroup); @@ -3180,7 +3183,7 @@ static int qemuSetupCgroup(struct qemud_driver *driver, } for (i = 0; i < vm->def->ndisks ; i++) { - if (qemuSetupDiskCgroup(cgroup, vm->def->disks[i]) < 0) + if (qemuSetupDiskCgroup(driver, cgroup, vm->def->disks[i]) < 0) goto cleanup; } @@ -8033,7 +8036,7 @@ static int qemudDomainAttachDevice(virDomainPtr dom, vm->def->name); goto endjob; } - if (qemuSetupDiskCgroup(cgroup, dev->data.disk) < 0) + if (qemuSetupDiskCgroup(driver, cgroup, dev->data.disk) < 0) goto endjob; } @@ -8078,7 +8081,7 @@ static int qemudDomainAttachDevice(virDomainPtr dom, /* Fallthrough */ } if (ret != 0 && cgroup) { - if (qemuTeardownDiskCgroup(cgroup, dev->data.disk) < 0) + if (qemuTeardownDiskCgroup(driver, cgroup, dev->data.disk) < 0) VIR_WARN("Failed to teardown cgroup for disk path %s", NULLSTR(dev->data.disk->src)); } @@ -8278,7 +8281,7 @@ static int qemuDomainUpdateDeviceFlags(virDomainPtr dom, vm->def->name); goto endjob; } - if (qemuSetupDiskCgroup(cgroup, dev->data.disk) < 0) + if (qemuSetupDiskCgroup(driver, cgroup, dev->data.disk) < 0) goto endjob; } @@ -8301,7 +8304,7 @@ static int qemuDomainUpdateDeviceFlags(virDomainPtr dom, } if (ret != 0 && cgroup) { - if (qemuTeardownDiskCgroup(cgroup, dev->data.disk) < 0) + if (qemuTeardownDiskCgroup(driver, cgroup, dev->data.disk) < 0) VIR_WARN("Failed to teardown cgroup for disk path %s", NULLSTR(dev->data.disk->src)); } @@ -8429,7 +8432,7 @@ static int qemudDomainDetachPciDiskDevice(struct qemud_driver *driver, VIR_WARN("Unable to restore security label on %s", dev->data.disk->src); if (cgroup != NULL) { - if (qemuTeardownDiskCgroup(cgroup, dev->data.disk) < 0) + if (qemuTeardownDiskCgroup(driver, cgroup, dev->data.disk) < 0) VIR_WARN("Failed to teardown cgroup for disk path %s", NULLSTR(dev->data.disk->src)); } @@ -8493,7 +8496,7 @@ static int qemudDomainDetachSCSIDiskDevice(struct qemud_driver *driver, VIR_WARN("Unable to restore security label on %s", dev->data.disk->src); if (cgroup != NULL) { - if (qemuTeardownDiskCgroup(cgroup, dev->data.disk) < 0) + if (qemuTeardownDiskCgroup(driver, cgroup, dev->data.disk) < 0) VIR_WARN("Failed to teardown cgroup for disk path %s", NULLSTR(dev->data.disk->src)); } @@ -9672,8 +9675,15 @@ static int qemuDomainGetBlockInfo(virDomainPtr dom, goto cleanup; } } else { - if ((format = virStorageFileProbeFormat(disk->src)) < 0) + if (driver->allowDiskFormatProbing) { + if ((format = virStorageFileProbeFormat(disk->src)) < 0) + goto cleanup; + } else { + qemuReportError(VIR_ERR_INTERNAL_ERROR, + _("no disk format for %s and probing is disabled"), + disk->src); goto cleanup; + } } if (virStorageFileGetMetadataFromFD(path, fd, diff --git a/src/qemu/qemu_security_dac.c b/src/qemu/qemu_security_dac.c index 0bbcf69..55dc0c6 100644 --- a/src/qemu/qemu_security_dac.c +++ b/src/qemu/qemu_security_dac.c @@ -117,7 +117,7 @@ qemuSecurityDACSetSecurityImageLabel(virSecurityDriverPtr drv ATTRIBUTE_UNUSED, return 0; return virDomainDiskDefForeachPath(disk, - true, + driver->allowDiskFormatProbing, false, qemuSecurityDACSetSecurityFileLabel, NULL); diff --git a/src/qemu/test_libvirtd_qemu.aug b/src/qemu/test_libvirtd_qemu.aug index 3326cc5..f0c4a0d 100644 --- a/src/qemu/test_libvirtd_qemu.aug +++ b/src/qemu/test_libvirtd_qemu.aug @@ -101,6 +101,8 @@ relaxed_acs_check = 1 vnc_allow_host_audio = 1 clear_emulator_capabilities = 0 + +allow_disk_format_probing = 1 " test Libvirtd_qemu.lns get conf = @@ -212,3 +214,5 @@ clear_emulator_capabilities = 0 { "vnc_allow_host_audio" = "1" } { "#empty" } { "clear_emulator_capabilities" = "0" } +{ "#empty" } +{ "allow_disk_format_probing" = "1" } diff --git a/src/security/security_apparmor.c b/src/security/security_apparmor.c index cb5c739..c5f9829 100644 --- a/src/security/security_apparmor.c +++ b/src/security/security_apparmor.c @@ -157,6 +157,8 @@ load_profile(virSecurityDriverPtr drv, char *xml = NULL; int pipefd[2]; pid_t child; + const char *probe = virSecurityDriverGetAllowDiskFormatProbing(drv) + ? "1" : "0"; if (pipe(pipefd) < -1) { virReportSystemError(errno, "%s", _("unable to create pipe")); @@ -172,19 +174,19 @@ load_profile(virSecurityDriverPtr drv, if (create) { const char *const argv[] = { - VIRT_AA_HELPER, "-c", "-u", profile, NULL + VIRT_AA_HELPER, "-p", probe, "-c", "-u", profile, NULL }; ret = virExec(argv, NULL, NULL, &child, pipefd[0], NULL, NULL, VIR_EXEC_NONE); } else if (fn) { const char *const argv[] = { - VIRT_AA_HELPER, "-r", "-u", profile, "-f", fn, NULL + VIRT_AA_HELPER, "-p", probe, "-r", "-u", profile, "-f", fn, NULL }; ret = virExec(argv, NULL, NULL, &child, pipefd[0], NULL, NULL, VIR_EXEC_NONE); } else { const char *const argv[] = { - VIRT_AA_HELPER, "-r", "-u", profile, NULL + VIRT_AA_HELPER, "-p", probe, "-r", "-u", profile, NULL }; ret = virExec(argv, NULL, NULL, &child, pipefd[0], NULL, NULL, VIR_EXEC_NONE); @@ -347,9 +349,11 @@ AppArmorSecurityDriverProbe(void) * currently not used. */ static int -AppArmorSecurityDriverOpen(virSecurityDriverPtr drv) +AppArmorSecurityDriverOpen(virSecurityDriverPtr drv, + bool allowDiskFormatProbing) { virSecurityDriverSetDOI(drv, SECURITY_APPARMOR_VOID_DOI); + virSecurityDriverSetAllowDiskFormatProbing(drv, allowDiskFormatProbing); return 0; } diff --git a/src/security/security_driver.c b/src/security/security_driver.c index aac9f78..9e32fa4 100644 --- a/src/security/security_driver.c +++ b/src/security/security_driver.c @@ -56,7 +56,8 @@ virSecurityDriverVerify(virDomainDefPtr def) int virSecurityDriverStartup(virSecurityDriverPtr *drv, - const char *name) + const char *name, + bool allowDiskFormatProbing) { unsigned int i; @@ -72,7 +73,7 @@ virSecurityDriverStartup(virSecurityDriverPtr *drv, switch (tmp->probe()) { case SECURITY_DRIVER_ENABLE: virSecurityDriverInit(tmp); - if (tmp->open(tmp) == -1) { + if (tmp->open(tmp, allowDiskFormatProbing) == -1) { return -1; } else { *drv = tmp; @@ -125,3 +126,14 @@ virSecurityDriverGetModel(virSecurityDriverPtr drv) { return drv->name; } + +void virSecurityDriverSetAllowDiskFormatProbing(virSecurityDriverPtr drv, + bool allowDiskFormatProbing) +{ + drv->_private.allowDiskFormatProbing = allowDiskFormatProbing; +} + +bool virSecurityDriverGetAllowDiskFormatProbing(virSecurityDriverPtr drv) +{ + return drv->_private.allowDiskFormatProbing; +} diff --git a/src/security/security_driver.h b/src/security/security_driver.h index 61c9eb0..d768f32 100644 --- a/src/security/security_driver.h +++ b/src/security/security_driver.h @@ -33,7 +33,8 @@ typedef struct _virSecurityDriverState virSecurityDriverState; typedef virSecurityDriverState *virSecurityDriverStatePtr; typedef virSecurityDriverStatus (*virSecurityDriverProbe) (void); -typedef int (*virSecurityDriverOpen) (virSecurityDriverPtr drv); +typedef int (*virSecurityDriverOpen) (virSecurityDriverPtr drv, + bool allowDiskFormatProbing); typedef int (*virSecurityDomainRestoreImageLabel) (virSecurityDriverPtr drv, virDomainObjPtr vm, virDomainDiskDefPtr disk); @@ -102,12 +103,14 @@ struct _virSecurityDriver { */ struct { char doi[VIR_SECURITY_DOI_BUFLEN]; + bool allowDiskFormatProbing; } _private; }; /* Global methods */ int virSecurityDriverStartup(virSecurityDriverPtr *drv, - const char *name); + const char *name, + bool allowDiskFormatProbing); int virSecurityDriverVerify(virDomainDefPtr def); @@ -120,7 +123,10 @@ virSecurityDriverVerify(virDomainDefPtr def); void virSecurityDriverInit(virSecurityDriverPtr drv); int virSecurityDriverSetDOI(virSecurityDriverPtr drv, const char *doi); +void virSecurityDriverSetAllowDiskFormatProbing(virSecurityDriverPtr drv, + bool allowDiskFormatProbing); const char *virSecurityDriverGetDOI(virSecurityDriverPtr drv); const char *virSecurityDriverGetModel(virSecurityDriverPtr drv); +bool virSecurityDriverGetAllowDiskFormatProbing(virSecurityDriverPtr drv); #endif /* __VIR_SECURITY_H__ */ diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c index cc3812b..a9dd836 100644 --- a/src/security/security_selinux.c +++ b/src/security/security_selinux.c @@ -266,13 +266,15 @@ SELinuxSecurityDriverProbe(void) } static int -SELinuxSecurityDriverOpen(virSecurityDriverPtr drv) +SELinuxSecurityDriverOpen(virSecurityDriverPtr drv, + bool allowDiskFormatProbing) { /* * Where will the DOI come from? SELinux configuration, or qemu * configuration? For the moment, we'll just set it to "0". */ virSecurityDriverSetDOI(drv, SECURITY_SELINUX_VOID_DOI); + virSecurityDriverSetAllowDiskFormatProbing(drv, allowDiskFormatProbing); return SELinuxInitialize(); } @@ -467,18 +469,19 @@ SELinuxSetSecurityFileLabel(virDomainDiskDefPtr disk, } static int -SELinuxSetSecurityImageLabel(virSecurityDriverPtr drv ATTRIBUTE_UNUSED, +SELinuxSetSecurityImageLabel(virSecurityDriverPtr drv, virDomainObjPtr vm, virDomainDiskDefPtr disk) { const virSecurityLabelDefPtr secdef = &vm->def->seclabel; + bool allowDiskFormatProbing = virSecurityDriverGetAllowDiskFormatProbing(drv); if (secdef->type == VIR_DOMAIN_SECLABEL_STATIC) return 0; return virDomainDiskDefForeachPath(disk, - true, + allowDiskFormatProbing, false, SELinuxSetSecurityFileLabel, secdef); diff --git a/src/security/virt-aa-helper.c b/src/security/virt-aa-helper.c index 9ed0cd3..521545d 100644 --- a/src/security/virt-aa-helper.c +++ b/src/security/virt-aa-helper.c @@ -40,6 +40,7 @@ static char *progname; typedef struct { + bool allowDiskFormatProbing; char uuid[PROFILE_NAME_SIZE]; /* UUID of vm */ bool dryrun; /* dry run */ char cmd; /* 'c' create @@ -844,7 +845,7 @@ get_files(vahControl * ctl) for (i = 0; i < ctl->def->ndisks; i++) { int ret = virDomainDiskDefForeachPath(ctl->def->disks[i], - true, + ctl->allowDiskFormatProbing, false, add_file_path, &buf); @@ -943,6 +944,7 @@ vahParseArgv(vahControl * ctl, int argc, char **argv) { int arg, idx = 0; struct option opt[] = { + {"probing", 1, 0, 'p' }, {"add", 0, 0, 'a'}, {"create", 0, 0, 'c'}, {"dryrun", 0, 0, 'd'}, @@ -991,6 +993,12 @@ vahParseArgv(vahControl * ctl, int argc, char **argv) PROFILE_NAME_SIZE) == NULL) vah_error(ctl, 1, "error copying UUID"); break; + case 'p': + if (STREQ(optarg, "1")) + ctl->allowDiskFormatProbing = true; + else + ctl->allowDiskFormatProbing = false; + break; default: vah_error(ctl, 1, "unsupported option"); break; diff --git a/tests/seclabeltest.c b/tests/seclabeltest.c index 26d1f86..ef3f026 100644 --- a/tests/seclabeltest.c +++ b/tests/seclabeltest.c @@ -15,7 +15,7 @@ main (int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) const char *doi, *model; virSecurityDriverPtr security_drv; - ret = virSecurityDriverStartup (&security_drv, "selinux"); + ret = virSecurityDriverStartup (&security_drv, "selinux", false); if (ret == -1) { fprintf (stderr, "Failed to start security driver"); -- 1.7.1.1

On Mon, Jul 12, 2010 at 02:30:45PM +0100, Daniel P. Berrange wrote:
Disk format probing is now disabled by default. A new config option in /etc/qemu/qemu.conf will re-enable it for existing deployments where this causes trouble
Okay, my answer to question on patch 2 :-) ACK Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

Record a default driver name/type in capabilities struct. Use this when parsing disks if value is not set in XML config. * src/conf/capabilities.h: Record default driver name/type for disks * src/conf/domain_conf.c: Fallback to default driver name/type when parsing disks * src/qemu/qemu_driver.c: Set default driver name/type to raw --- src/conf/capabilities.h | 2 ++ src/conf/domain_conf.c | 16 +++++++++++++++- src/qemu/qemu_driver.c | 8 ++++++++ 3 files changed, 25 insertions(+), 1 deletions(-) diff --git a/src/conf/capabilities.h b/src/conf/capabilities.h index 9290c82..f676eb8 100644 --- a/src/conf/capabilities.h +++ b/src/conf/capabilities.h @@ -123,6 +123,8 @@ struct _virCaps { virCapsGuestPtr *guests; unsigned char macPrefix[VIR_MAC_PREFIX_BUFLEN]; unsigned int emulatorRequired : 1; + const char *defaultDiskDriverName; + const char *defaultDiskDriverType; void *(*privateDataAllocFunc)(void); void (*privateDataFreeFunc)(void *); int (*privateDataXMLFormat)(virBufferPtr, void *); diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index b20ca97..f3b8cfa 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -1639,6 +1639,16 @@ virDomainDiskDefParseXML(virCapsPtr caps, def->serial = serial; serial = NULL; + if (!def->driverType && + caps->defaultDiskDriverType && + !(def->driverType = strdup(caps->defaultDiskDriverType))) + goto no_memory; + + if (!def->driverName && + caps->defaultDiskDriverName && + !(def->driverName = strdup(caps->defaultDiskDriverName))) + goto no_memory; + if (def->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE && virDomainDiskDefAssignAddress(caps, def) < 0) goto error; @@ -1659,6 +1669,9 @@ cleanup: return def; +no_memory: + virReportOOMError(); + error: virDomainDiskDefFree(def); def = NULL; @@ -4275,7 +4288,8 @@ static virDomainDefPtr virDomainDefParseXML(virCapsPtr caps, if (n && VIR_ALLOC_N(def->disks, n) < 0) goto no_memory; for (i = 0 ; i < n ; i++) { - virDomainDiskDefPtr disk = virDomainDiskDefParseXML(caps, nodes[i], + virDomainDiskDefPtr disk = virDomainDiskDefParseXML(caps, + nodes[i], flags); if (!disk) goto error; diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 3c479c5..14b790e 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -1357,6 +1357,14 @@ qemuCreateCapabilities(virCapsPtr oldcaps, return NULL; } + if (driver->allowDiskFormatProbing) { + caps->defaultDiskDriverName = NULL; + caps->defaultDiskDriverType = NULL; + } else { + caps->defaultDiskDriverName = "qemu"; + caps->defaultDiskDriverType = "raw"; + } + /* Domain XML parser hooks */ caps->privateDataAllocFunc = qemuDomainObjPrivateAlloc; caps->privateDataFreeFunc = qemuDomainObjPrivateFree; -- 1.7.1.1

On Mon, Jul 12, 2010 at 02:30:46PM +0100, Daniel P. Berrange wrote:
Record a default driver name/type in capabilities struct. Use this when parsing disks if value is not set in XML config.
* src/conf/capabilities.h: Record default driver name/type for disks * src/conf/domain_conf.c: Fallback to default driver name/type when parsing disks * src/qemu/qemu_driver.c: Set default driver name/type to raw --- src/conf/capabilities.h | 2 ++ src/conf/domain_conf.c | 16 +++++++++++++++- src/qemu/qemu_driver.c | 8 ++++++++ 3 files changed, 25 insertions(+), 1 deletions(-)
diff --git a/src/conf/capabilities.h b/src/conf/capabilities.h index 9290c82..f676eb8 100644 --- a/src/conf/capabilities.h +++ b/src/conf/capabilities.h @@ -123,6 +123,8 @@ struct _virCaps { virCapsGuestPtr *guests; unsigned char macPrefix[VIR_MAC_PREFIX_BUFLEN]; unsigned int emulatorRequired : 1; + const char *defaultDiskDriverName; + const char *defaultDiskDriverType; void *(*privateDataAllocFunc)(void); void (*privateDataFreeFunc)(void *); int (*privateDataXMLFormat)(virBufferPtr, void *); diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index b20ca97..f3b8cfa 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -1639,6 +1639,16 @@ virDomainDiskDefParseXML(virCapsPtr caps, def->serial = serial; serial = NULL;
+ if (!def->driverType && + caps->defaultDiskDriverType && + !(def->driverType = strdup(caps->defaultDiskDriverType))) + goto no_memory; + + if (!def->driverName && + caps->defaultDiskDriverName && + !(def->driverName = strdup(caps->defaultDiskDriverName))) + goto no_memory; + if (def->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE && virDomainDiskDefAssignAddress(caps, def) < 0) goto error;
Hum, I find suspsicious that those 2 strings for the new fields are allocated with strdup, but nowhere in the patch I can see code for freeing them, so I suspect some kid of leak here, right ? Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

When creating qcow2 files with a backing store, it is important to set an explicit format to prevent QEMU probing. The storage backend was only doing this if it found a 'kvm-img' binary. This is wrong because plenty of kvm-img binaries don't support an explicit format, and plenty of 'qemu-img' binaries do support a format. The result was that most qcow2 files were not getting a backing store format. This patch runs 'qemu-img -h' to check for the two support argument formats '-o backing_format=raw' '-F raw' and use whichever option it finds * src/storage/storage_backend.c: Query binary to determine how to set the backing store format --- src/storage/storage_backend.c | 214 +++++++++++++++++++++++++++++------------ 1 files changed, 152 insertions(+), 62 deletions(-) diff --git a/src/storage/storage_backend.c b/src/storage/storage_backend.c index aba8937..c185693 100644 --- a/src/storage/storage_backend.c +++ b/src/storage/storage_backend.c @@ -561,6 +561,69 @@ static int virStorageBackendCreateExecCommand(virStoragePoolObjPtr pool, return 0; } +enum { + QEMU_IMG_BACKING_FORMAT_NONE = 0, + QEMU_IMG_BACKING_FORMAT_FLAG, + QEMU_IMG_BACKING_FORMAT_OPTIONS, +}; + +static int virStorageBackendQEMUImgBackingFormat(const char *qemuimg) +{ + const char *const qemuarg[] = { qemuimg, "-h", NULL }; + const char *const qemuenv[] = { "LC_ALL=C", NULL }; + pid_t child = 0; + int status; + int newstdout = -1; + char *help = NULL; + enum { MAX_HELP_OUTPUT_SIZE = 1024*8 }; + int len; + char *start; + char *end; + char *tmp; + int ret = -1; + + if (virExec(qemuarg, qemuenv, NULL, + &child, -1, &newstdout, NULL, VIR_EXEC_CLEAR_CAPS) < 0) + goto cleanup; + + if ((len = virFileReadLimFD(newstdout, MAX_HELP_OUTPUT_SIZE, &help)) < 0) { + virReportSystemError(errno, + _("Unable to read '%s -h' output"), + qemuimg); + goto cleanup; + } + + start = strstr(help, " create "); + end = strstr(start, "\n"); + if ((tmp = strstr(start, "-F fmt")) && tmp < end) + ret = QEMU_IMG_BACKING_FORMAT_FLAG; + else if ((tmp = strstr(start, "[-o options]")) && tmp < end) + ret = QEMU_IMG_BACKING_FORMAT_OPTIONS; + else + ret = QEMU_IMG_BACKING_FORMAT_NONE; + +cleanup: + VIR_FREE(help); + close(newstdout); +rewait: + if (child) { + if (waitpid(child, &status, 0) != child) { + if (errno == EINTR) + goto rewait; + + VIR_ERROR(_("Unexpected exit status from qemu %d pid %lu"), + WEXITSTATUS(status), (unsigned long)child); + } + if (WEXITSTATUS(status) != 0) { + VIR_WARN("Unexpected exit status '%d', qemu probably failed", + WEXITSTATUS(status)); + } + } + + return ret; +} + + static int virStorageBackendCreateQemuImg(virConnectPtr conn, virStoragePoolObjPtr pool, @@ -568,10 +631,9 @@ virStorageBackendCreateQemuImg(virConnectPtr conn, virStorageVolDefPtr inputvol, unsigned int flags ATTRIBUTE_UNUSED) { - int ret; + int ret = -1; char size[100]; char *create_tool; - short use_kvmimg; const char *type = virStorageFileFormatTypeToString(vol->target.format); const char *backingType = vol->backingStore.path ? @@ -582,41 +644,10 @@ virStorageBackendCreateQemuImg(virConnectPtr conn, const char *inputPath = inputvol ? inputvol->target.path : NULL; /* Treat input block devices as 'raw' format */ const char *inputType = inputPath ? - virStorageFileFormatTypeToString(inputvol->type == VIR_STORAGE_VOL_BLOCK ? VIR_STORAGE_FILE_RAW : inputvol->target.format) : - NULL; - - const char **imgargv; - /* The extra NULL field is for indicating encryption (-e). */ - const char *imgargvnormal[] = { - NULL, "create", - "-f", type, - vol->target.path, - size, - NULL, - NULL - }; - /* Extra NULL fields are for including "backingType" when using - * kvm-img (-F backingType), and for indicating encryption (-e). - */ - const char *imgargvbacking[] = { - NULL, "create", - "-f", type, - "-b", vol->backingStore.path, - vol->target.path, - size, - NULL, - NULL, - NULL, - NULL - }; - const char *convargv[] = { - NULL, "convert", - "-f", inputType, - "-O", type, - inputPath, - vol->target.path, - NULL, - }; + virStorageFileFormatTypeToString(inputvol->type == VIR_STORAGE_VOL_BLOCK ? + VIR_STORAGE_FILE_RAW : + inputvol->target.format) : + NULL; if (type == NULL) { virStorageReportError(VIR_ERR_INTERNAL_ERROR, @@ -690,44 +721,103 @@ virStorageBackendCreateQemuImg(virConnectPtr conn, } } - if ((create_tool = virFindFileInPath("kvm-img")) != NULL) - use_kvmimg = 1; - else if ((create_tool = virFindFileInPath("qemu-img")) != NULL) - use_kvmimg = 0; - else { + /* Size in KB */ + snprintf(size, sizeof(size), "%lluK", vol->capacity/1024); + + /* KVM is usually ahead of qemu on features, so try that first */ + create_tool = virFindFileInPath("kvm-img"); + if (!create_tool) + create_tool = virFindFileInPath("qemu-img"); + + if (!create_tool) { virStorageReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("unable to find kvm-img or qemu-img")); return -1; } if (inputvol) { - convargv[0] = create_tool; - imgargv = convargv; + const char *imgargv[] = { + create_tool, + "convert", + "-f", inputType, + "-O", type, + inputPath, + vol->target.path, + NULL, + }; + + ret = virStorageBackendCreateExecCommand(pool, vol, imgargv); } else if (vol->backingStore.path) { - imgargvbacking[0] = create_tool; - if (use_kvmimg) { - imgargvbacking[6] = "-F"; - imgargvbacking[7] = backingType; - imgargvbacking[8] = vol->target.path; - imgargvbacking[9] = size; + const char *imgargv[] = { + create_tool, + "create", + "-f", type, + "-b", vol->backingStore.path, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL + }; + int imgformat = virStorageBackendQEMUImgBackingFormat(create_tool); + char *optflag = NULL; + if (imgformat < 0) + goto cleanup; + + switch (imgformat) { + case QEMU_IMG_BACKING_FORMAT_FLAG: + imgargv[6] = "-F"; + imgargv[7] = backingType; + imgargv[8] = vol->target.path; + imgargv[9] = size; + if (vol->target.encryption != NULL) + imgargv[10] = "-e"; + break; + + case QEMU_IMG_BACKING_FORMAT_OPTIONS: + if (virAsprintf(&optflag, "backing_fmt=%s", backingType) < 0) { + virReportOOMError(); + goto cleanup; + } + imgargv[6] = "-o"; + imgargv[7] = optflag; + imgargv[8] = vol->target.path; + imgargv[9] = size; if (vol->target.encryption != NULL) - imgargvbacking[10] = "-e"; - } else if (vol->target.encryption != NULL) - imgargvbacking[8] = "-e"; - imgargv = imgargvbacking; + imgargv[10] = "-e"; + break; + + default: + VIR_INFO("Unable to set backing store format for %s with %s", + vol->target.path, create_tool); + imgargv[6] = vol->target.path; + imgargv[7] = size; + if (vol->target.encryption != NULL) + imgargv[8] = "-e"; + } + + ret = virStorageBackendCreateExecCommand(pool, vol, imgargv); + VIR_FREE(optflag); } else { - imgargvnormal[0] = create_tool; - imgargv = imgargvnormal; + /* The extra NULL field is for indicating encryption (-e). */ + const char *imgargv[] = { + create_tool, + "create", + "-f", type, + vol->target.path, + size, + NULL, + NULL + }; if (vol->target.encryption != NULL) imgargv[6] = "-e"; - } + ret = virStorageBackendCreateExecCommand(pool, vol, imgargv); + } - /* Size in KB */ - snprintf(size, sizeof(size), "%lluK", vol->capacity/1024); - - ret = virStorageBackendCreateExecCommand(pool, vol, imgargv); - VIR_FREE(imgargv[0]); + cleanup: + VIR_FREE(create_tool); return ret; } -- 1.7.1.1

On Mon, Jul 12, 2010 at 02:30:47PM +0100, Daniel P. Berrange wrote:
When creating qcow2 files with a backing store, it is important to set an explicit format to prevent QEMU probing. The storage backend was only doing this if it found a 'kvm-img' binary. This is wrong because plenty of kvm-img binaries don't support an explicit format, and plenty of 'qemu-img' binaries do support a format. The result was that most qcow2 files were not getting a backing store format.
This patch runs 'qemu-img -h' to check for the two support argument formats
'-o backing_format=raw' '-F raw'
and use whichever option it finds
* src/storage/storage_backend.c: Query binary to determine how to set the backing store format --- src/storage/storage_backend.c | 214 +++++++++++++++++++++++++++++------------ 1 files changed, 152 insertions(+), 62 deletions(-)
ACK, Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

The storage volume lookup code was probing for the backing store format, instead of using the format extracted from the file itself. This meant it could report in accurate information. If a format is included in the file, then use that in preference, with probing as a fallback. * src/storage/storage_backend_fs.c: Use extracted backing store format --- src/storage/storage_backend_fs.c | 80 +++++++++++++++++--------------------- 1 files changed, 36 insertions(+), 44 deletions(-) diff --git a/src/storage/storage_backend_fs.c b/src/storage/storage_backend_fs.c index d3ac0fe..ffb0071 100644 --- a/src/storage/storage_backend_fs.c +++ b/src/storage/storage_backend_fs.c @@ -51,6 +51,7 @@ static int virStorageBackendProbeTarget(virStorageVolTargetPtr target, char **backingStore, + int *backingStoreFormat, unsigned long long *allocation, unsigned long long *capacity, virStorageEncryptionPtr *encryption) @@ -58,6 +59,10 @@ virStorageBackendProbeTarget(virStorageVolTargetPtr target, int fd, ret; virStorageFileMetadata meta; + if (backingStore) + *backingStore = NULL; + if (backingStoreFormat) + *backingStoreFormat = VIR_STORAGE_FILE_AUTO; if (encryption) *encryption = NULL; @@ -89,22 +94,30 @@ virStorageBackendProbeTarget(virStorageVolTargetPtr target, close(fd); - if (backingStore) { - *backingStore = meta.backingStore; - meta.backingStore = NULL; + if (meta.backingStore) { + if (backingStore) { + *backingStore = meta.backingStore; + meta.backingStore = NULL; + if (meta.backingStoreFormat == VIR_STORAGE_FILE_AUTO) { + if ((*backingStoreFormat = virStorageFileProbeFormat(*backingStore)) < 0) { + close(fd); + goto cleanup; + } + } else { + *backingStoreFormat = meta.backingStoreFormat; + } + } else { + VIR_FREE(meta.backingStore); + } } - VIR_FREE(meta.backingStore); - if (capacity && meta.capacity) *capacity = meta.capacity; if (encryption != NULL && meta.encrypted) { if (VIR_ALLOC(*encryption) < 0) { virReportOOMError(); - if (backingStore) - VIR_FREE(*backingStore); - return -1; + goto cleanup; } switch (target->format) { @@ -124,6 +137,11 @@ virStorageBackendProbeTarget(virStorageVolTargetPtr target, } return 0; + +cleanup: + if (backingStore) + VIR_FREE(*backingStore); + return -1; } #if WITH_STORAGE_FS @@ -585,6 +603,7 @@ virStorageBackendFileSystemRefresh(virConnectPtr conn ATTRIBUTE_UNUSED, while ((ent = readdir(dir)) != NULL) { int ret; char *backingStore; + int backingStoreFormat; if (VIR_ALLOC(vol) < 0) goto no_memory; @@ -604,6 +623,7 @@ virStorageBackendFileSystemRefresh(virConnectPtr conn ATTRIBUTE_UNUSED, if ((ret = virStorageBackendProbeTarget(&vol->target, &backingStore, + &backingStoreFormat, &vol->allocation, &vol->capacity, &vol->target.encryption)) < 0) { @@ -619,46 +639,18 @@ virStorageBackendFileSystemRefresh(virConnectPtr conn ATTRIBUTE_UNUSED, } if (backingStore != NULL) { - if (vol->target.format == VIR_STORAGE_FILE_QCOW2 && - STRPREFIX("fmt:", backingStore)) { - char *fmtstr = backingStore + 4; - char *path = strchr(fmtstr, ':'); - if (!path) { - VIR_FREE(backingStore); - } else { - *path = '\0'; - if ((vol->backingStore.format = - virStorageFileFormatTypeFromString(fmtstr)) < 0) { - VIR_FREE(backingStore); - } else { - memmove(backingStore, path, strlen(path) + 1); - vol->backingStore.path = backingStore; - - if (virStorageBackendUpdateVolTargetInfo(&vol->backingStore, - NULL, - NULL) < 0) - VIR_FREE(vol->backingStore); - } - } - } else { - vol->backingStore.path = backingStore; - - if ((ret = virStorageBackendProbeTarget(&vol->backingStore, - NULL, NULL, NULL, - NULL)) < 0) { - if (ret == -1) - goto cleanup; - else { - /* Silently ignore non-regular files, - * eg '.' '..', 'lost+found' */ - VIR_FREE(vol->backingStore); - } - } + vol->backingStore.path = backingStore; + vol->backingStore.format = backingStoreFormat; + + if (virStorageBackendUpdateVolTargetInfo(&vol->backingStore, + NULL, + NULL) < 0) { + VIR_FREE(vol->backingStore.path); + goto cleanup; } } - if (VIR_REALLOC_N(pool->volumes.objs, pool->volumes.count+1) < 0) goto no_memory; -- 1.7.1.1

On Mon, Jul 12, 2010 at 02:30:48PM +0100, Daniel P. Berrange wrote:
The storage volume lookup code was probing for the backing store format, instead of using the format extracted from the file itself. This meant it could report in accurate information. If a format is included in the file, then use that in preference, with probing as a fallback.
* src/storage/storage_backend_fs.c: Use extracted backing store format --- src/storage/storage_backend_fs.c | 80 +++++++++++++++++--------------------- 1 files changed, 36 insertions(+), 44 deletions(-)
ACK, Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/
participants (2)
-
Daniel P. Berrange
-
Daniel Veillard