update to libvirt 0.8.3

OBS-URL: https://build.opensuse.org/package/show/Virtualization/libvirt?expand=0&rev=61
This commit is contained in:
James Fehlig 2010-08-07 04:24:13 +00:00 committed by Git OBS Bridge
parent 274bce922a
commit 8b4217ed93
23 changed files with 25 additions and 4689 deletions

View File

@ -1,339 +0,0 @@
>From 7b91c43bef0348c8cc18037bec5aef668b51fc90 Mon Sep 17 00:00:00 2001
From: Daniel P. Berrange <berrange@redhat.com>
Date: Mon, 14 Jun 2010 15:53:59 +0100
Subject: [PATCH 01/10] Extract the backing store format as well as name, if available
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 | 192 ++++++++++++++++++++++++++++++++++++++++------
src/util/storage_file.h | 2 +
2 files changed, 169 insertions(+), 25 deletions(-)
Index: libvirt-0.8.1/src/util/storage_file.c
===================================================================
--- libvirt-0.8.1.orig/src/util/storage_file.c
+++ libvirt-0.8.1/src/util/storage_file.c
@@ -71,12 +71,18 @@ 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);
static struct FileTypeInfo const fileTypeInfo[] = {
@@ -112,11 +118,11 @@ static struct FileTypeInfo const fileTyp
/* 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 },
+ 4+4+8+4+4, 8, 1, 4+4+8+4+4+8+1+1+2, 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 },
+ 4+4+8+4+4, 8, 1, 4+4+8+4+4+8, qcow2GetBackingStore },
/* VMDK 3 */
/* XXX Untested
{ VIR_STORAGE_FILE_VMDK, "COWD", NULL,
@@ -137,11 +143,14 @@ static struct FileTypeInfo const fileTyp
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] */
@@ -155,31 +164,101 @@ cowGetBackingStore(char **res,
return BACKING_STORE_OK;
}
+
+
+#define QCOWX_HDR_BACKING_FILE_OFFSET 4+4
+#define QCOWX_HDR_BACKING_FILE_SIZE 4+4+8
+
+#define QCOW2_HDR_TOTAL_SIZE 4+4+8+4+4+8+4+4+8+8+4+4+8
+#define QCOW2_HDR_EXTENSION_END 0
+#define QCOW2_HDR_EXTENSION_BACKING_FORMAT 0xE2792ACA
+
+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)) {
+ int magic = (buf[offset] << 24) +
+ (buf[offset+1] << 16) +
+ (buf[offset+2] << 8) +
+ (buf[offset+3]);
+ int len = (buf[offset+4] << 24) +
+ (buf[offset+5] << 16) +
+ (buf[offset+6] << 8) +
+ (buf[offset+7]);
+
+ offset += 8;
+
+ 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)
@@ -192,12 +271,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)
{
@@ -207,6 +337,12 @@ vmdk4GetBackingStore(char **res,
size_t len;
*res = NULL;
+ /* XXX should we set VMDK instead ? QEMU does auto
+ * probing, but this isn't in compliance with the
+ * VMDK spec/VMWare impl which presumes only VMDK
+ * backing format
+ */
+ *format = VIR_STORAGE_FILE_AUTO;
if (buf_size <= 0x200)
return BACKING_STORE_INVALID;
@@ -351,9 +487,12 @@ virStorageFileGetMetadataFromFD(const ch
/* 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;
@@ -363,13 +502,16 @@ virStorageFileGetMetadataFromFD(const ch
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;
Index: libvirt-0.8.1/src/util/storage_file.h
===================================================================
--- libvirt-0.8.1.orig/src/util/storage_file.h
+++ libvirt-0.8.1/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;

View File

@ -1,158 +0,0 @@
>From 66c633413960e869a15062cee8667db51e6c817a Mon Sep 17 00:00:00 2001
From: Daniel P. Berrange <berrange@redhat.com>
Date: Mon, 14 Jun 2010 16:39:32 +0100
Subject: [PATCH 02/10] Remove 'type' field from FileTypeInfo struct
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(-)
Index: libvirt-0.8.1/src/util/storage_file.c
===================================================================
--- libvirt-0.8.1.orig/src/util/storage_file.c
+++ libvirt-0.8.1/src/util/storage_file.c
@@ -51,7 +51,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 */
@@ -86,60 +85,59 @@ static int vmdk4GetBackingStore(char **,
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,
- 4+4+8+4+4, 8, 1, 4+4+8+4+4+8+1+1+2, 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, 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 */
- /* XXX Untested
- { VIR_STORAGE_FILE_VPC, "conectix", NULL,
- LV_BIG_ENDIAN, -1, 0,
- -1, 0, 0, -1, NULL},
- */
+ [VIR_STORAGE_FILE_RAW] = { NULL, NULL, LV_LITTLE_ENDIAN, 0, 0, 0, 0, 0, 0, NULL },
+ [VIR_STORAGE_FILE_DIR] = { NULL, NULL, LV_LITTLE_ENDIAN, 0, 0, 0, 0, 0, 0, NULL },
+ [VIR_STORAGE_FILE_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,
+ 4+4+8+4+4, 8, 1, 4+4+8+4+4+8+1+1+2, qcow1GetBackingStore
+ },
+ [VIR_STORAGE_FILE_QCOW2] = {
+ "QFI", NULL,
+ LV_BIG_ENDIAN, 4, 2,
+ 4+4+8+4+4, 8, 1, 4+4+8+4+4+8, 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,
@@ -485,7 +483,7 @@ virStorageFileGetMetadataFromFD(const ch
}
/* 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;
@@ -525,7 +523,7 @@ virStorageFileGetMetadataFromFD(const ch
if (!virFileHasSuffix(path, fileTypeInfo[i].extension))
continue;
- meta->format = fileTypeInfo[i].type;
+ meta->format = i;
return 0;
}

View File

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

View File

@ -1,218 +0,0 @@
>From 7b2c30d0af7938df533b85e948918cfdff2e5f01 Mon Sep 17 00:00:00 2001
From: Daniel P. Berrange <berrange@redhat.com>
Date: Tue, 15 Jun 2010 16:15:51 +0100
Subject: [PATCH 04/10] Require format to be passed into virStorageFileGetMetadata
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
caling 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 | 15 ++++++++++++---
src/util/storage_file.h | 3 ++-
7 files changed, 54 insertions(+), 14 deletions(-)
Index: libvirt-0.8.1/src/qemu/qemu_driver.c
===================================================================
--- libvirt-0.8.1.orig/src/qemu/qemu_driver.c
+++ libvirt-0.8.1/src/qemu/qemu_driver.c
@@ -9059,8 +9059,10 @@ static int qemuDomainGetBlockInfo(virDom
int fd = -1;
off_t end;
virStorageFileMetadata meta;
+ virDomainDiskDefPtr disk = NULL;
struct stat sb;
int i;
+ int format;
virCheckFlags(0, -1);
@@ -9086,6 +9088,7 @@ static int qemuDomainGetBlockInfo(virDom
if (vm->def->disks[i]->src != NULL &&
STREQ (vm->def->disks[i]->src, path)) {
ret = 0;
+ disk = vm->def->disks[i];
break;
}
}
@@ -9108,7 +9111,21 @@ static int qemuDomainGetBlockInfo(virDom
/* Probe for magic formats */
memset(&meta, 0, sizeof(meta));
- 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 */
Index: libvirt-0.8.1/src/qemu/qemu_security_dac.c
===================================================================
--- libvirt-0.8.1.orig/src/qemu/qemu_security_dac.c
+++ libvirt-0.8.1/src/qemu/qemu_security_dac.c
@@ -118,7 +118,9 @@ qemuSecurityDACSetSecurityImageLabel(vir
memset(&meta, 0, sizeof(meta));
- ret = virStorageFileGetMetadata(path, &meta);
+ ret = virStorageFileGetMetadata(path,
+ VIR_STORAGE_FILE_AUTO,
+ &meta);
if (path != disk->src)
VIR_FREE(path);
Index: libvirt-0.8.1/src/security/security_selinux.c
===================================================================
--- libvirt-0.8.1.orig/src/security/security_selinux.c
+++ libvirt-0.8.1/src/security/security_selinux.c
@@ -431,7 +431,9 @@ SELinuxSetSecurityImageLabel(virDomainOb
memset(&meta, 0, sizeof(meta));
- ret = virStorageFileGetMetadata(path, &meta);
+ ret = virStorageFileGetMetadata(path,
+ VIR_STORAGE_FILE_AUTO,
+ &meta);
if (path != disk->src)
VIR_FREE(path);
Index: libvirt-0.8.1/src/security/virt-aa-helper.c
===================================================================
--- libvirt-0.8.1.orig/src/security/virt-aa-helper.c
+++ libvirt-0.8.1/src/security/virt-aa-helper.c
@@ -833,7 +833,9 @@ get_files(vahControl * ctl)
memset(&meta, 0, sizeof(meta));
- ret = virStorageFileGetMetadata(path, &meta);
+ ret = virStorageFileGetMetadata(path,
+ VIR_STORAGE_FILE_AUTO,
+ &meta);
if (path != ctl->def->disks[i]->src)
VIR_FREE(path);
Index: libvirt-0.8.1/src/storage/storage_backend_fs.c
===================================================================
--- libvirt-0.8.1.orig/src/storage/storage_backend_fs.c
+++ libvirt-0.8.1/src/storage/storage_backend_fs.c
@@ -77,14 +77,19 @@ virStorageBackendProbeTarget(virStorageV
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;
Index: libvirt-0.8.1/src/util/storage_file.c
===================================================================
--- libvirt-0.8.1.orig/src/util/storage_file.c
+++ libvirt-0.8.1/src/util/storage_file.c
@@ -653,6 +653,7 @@ virStorageFileProbeFormat(const char *pa
int
virStorageFileGetMetadataFromFD(const char *path,
int fd,
+ int format,
virStorageFileMetadata *meta)
{
unsigned char head[20*512]; /* vmdk4GetBackingStore needs this much. */
@@ -670,9 +671,16 @@ virStorageFileGetMetadataFromFD(const ch
return -1;
}
- meta->format = virStorageFileProbeFormatFromBuf(path, head, len);
+ if (format == VIR_STORAGE_FILE_AUTO)
+ format = virStorageFileProbeFormatFromBuf(path, head, len);
- return virStorageFileGetMetadataFromBuf(meta->format, path, head, len, meta);
+ if (format < 0 ||
+ format >= VIR_STORAGE_FILE_LAST) {
+ virReportSystemError(EINVAL, _("unknown storage file format %d"), format);
+ return -1;
+ }
+
+ return virStorageFileGetMetadataFromBuf(format, path, head, len, meta);
}
/**
@@ -688,6 +696,7 @@ virStorageFileGetMetadataFromFD(const ch
*/
int
virStorageFileGetMetadata(const char *path,
+ int format,
virStorageFileMetadata *meta)
{
int fd, ret;
@@ -697,7 +706,7 @@ virStorageFileGetMetadata(const char *pa
return -1;
}
- ret = virStorageFileGetMetadataFromFD(path, fd, meta);
+ ret = virStorageFileGetMetadataFromFD(path, fd, format, meta);
close(fd);
Index: libvirt-0.8.1/src/util/storage_file.h
===================================================================
--- libvirt-0.8.1.orig/src/util/storage_file.h
+++ libvirt-0.8.1/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(cons
int fd);
int virStorageFileGetMetadata(const char *path,
+ int format,
virStorageFileMetadata *meta);
int virStorageFileGetMetadataFromFD(const char *path,
int fd,
+ int format,
virStorageFileMetadata *meta);
#endif /* __VIR_STORAGE_FILE_H__ */

View File

@ -1,167 +0,0 @@
>From 494b96317334716f846436a5ec485963411cb4a3 Mon Sep 17 00:00:00 2001
From: Daniel P. Berrange <berrange@redhat.com>
Date: Mon, 14 Jun 2010 18:09:15 +0100
Subject: [PATCH 05/10] Add an API for iterating over disk paths
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(-)
Index: libvirt-0.8.1/src/conf/domain_conf.c
===================================================================
--- libvirt-0.8.1.orig/src/conf/domain_conf.c
+++ libvirt-0.8.1/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
@@ -6928,4 +6929,102 @@ int virDomainSnapshotHasChildren(virDoma
}
+int virDomainDiskDefForeachPath(virDomainDiskDefPtr disk,
+ bool allowProbing,
+ bool ignoreOpenFailure,
+ virDomainDiskDefPathIterator iter,
+ void *opaque)
+{
+ virHashTablePtr paths;
+ int format;
+ int ret = -1;
+ int 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 */
Index: libvirt-0.8.1/src/conf/domain_conf.h
===================================================================
--- libvirt-0.8.1.orig/src/conf/domain_conf.h
+++ libvirt-0.8.1/src/conf/domain_conf.h
@@ -1057,6 +1057,17 @@ int virDomainObjListGetInactiveNames(vir
int maxnames);
+typedef int (*virDomainDiskDefPathIterator)(virDomainDiskDefPtr disk,
+ const char *path,
+ unsigned int 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)
Index: libvirt-0.8.1/src/libvirt_private.syms
===================================================================
--- libvirt-0.8.1.orig/src/libvirt_private.syms
+++ libvirt-0.8.1/src/libvirt_private.syms
@@ -223,6 +223,7 @@ virDomainSnapshotObjUnref;
virDomainSnapshotDefParseString;
virDomainSnapshotDefFormat;
virDomainSnapshotAssignDef;
+virDomainDiskDefForeachPath;
# domain_event.h

View File

@ -1,273 +0,0 @@
>From e2ebe4b785eccb930f36f400a22940fa9660a24b Mon Sep 17 00:00:00 2001
From: Daniel P. Berrange <berrange@redhat.com>
Date: Tue, 15 Jun 2010 16:40:47 +0100
Subject: [PATCH 06/10] Convert all disk backing store loops to shared helper API
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(-)
Index: libvirt-0.8.1/src/qemu/qemu_security_dac.c
===================================================================
--- libvirt-0.8.1.orig/src/qemu/qemu_security_dac.c
+++ libvirt-0.8.1/src/qemu/qemu_security_dac.c
@@ -99,47 +99,28 @@ err:
static int
+qemuSecurityDACSetSecurityFileLabel(virDomainDiskDefPtr disk ATTRIBUTE_UNUSED,
+ const char *path,
+ unsigned int 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;
-
- memset(&meta, 0, sizeof(meta));
-
- 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);
}
Index: libvirt-0.8.1/src/security/security_selinux.c
===================================================================
--- libvirt-0.8.1.orig/src/security/security_selinux.c
+++ libvirt-0.8.1/src/security/security_selinux.c
@@ -411,56 +411,43 @@ SELinuxRestoreSecurityImageLabel(virDoma
}
static int
+SELinuxSetSecurityFileLabel(virDomainDiskDefPtr disk,
+ const char *path,
+ unsigned int 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;
-
- memset(&meta, 0, sizeof(meta));
-
- 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);
}
Index: libvirt-0.8.1/src/security/virt-aa-helper.c
===================================================================
--- libvirt-0.8.1.orig/src/security/virt-aa-helper.c
+++ libvirt-0.8.1/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;
@@ -802,6 +801,28 @@ file_iterate_pci_cb(pciDevice *dev ATTRI
}
static int
+add_file_path(virDomainDiskDefPtr disk,
+ const char *path,
+ unsigned int 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;
@@ -822,47 +843,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;
-
- memset(&meta, 0, sizeof(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)

File diff suppressed because it is too large Load Diff

View File

@ -1,385 +0,0 @@
>From e7db25186de8cb278f2b5f5c51e965129defaa11 Mon Sep 17 00:00:00 2001
From: Daniel P. Berrange <berrange@redhat.com>
Date: Tue, 15 Jun 2010 17:58:58 +0100
Subject: [PATCH 08/10] Disable all disk probing in QEMU driver & add config option to re-enable
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(-)
Index: libvirt-0.8.1/src/qemu/libvirtd_qemu.aug
===================================================================
--- libvirt-0.8.1.orig/src/qemu/libvirtd_qemu.aug
+++ libvirt-0.8.1/src/qemu/libvirtd_qemu.aug
@@ -38,6 +38,7 @@ module Libvirtd_qemu =
| str_entry "save_image_format"
| str_entry "hugetlbfs_mount"
| bool_entry "relaxed_acs_check"
+ | bool_entry "allow_disk_format_probing"
(* Each enty in the config is one of the following three ... *)
let entry = vnc_entry
Index: libvirt-0.8.1/src/qemu/qemu.conf
===================================================================
--- libvirt-0.8.1.orig/src/qemu/qemu.conf
+++ libvirt-0.8.1/src/qemu/qemu.conf
@@ -168,3 +168,15 @@
# be assigned to guests.
#
# relaxed_acs_check = 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
Index: libvirt-0.8.1/src/qemu/qemu_conf.c
===================================================================
--- libvirt-0.8.1.orig/src/qemu/qemu_conf.c
+++ libvirt-0.8.1/src/qemu/qemu_conf.c
@@ -351,6 +351,10 @@ int qemudLoadDriverConfig(struct qemud_d
CHECK_TYPE ("relaxed_acs_check", VIR_CONF_LONG);
if (p) driver->relaxedACS = 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;
}
Index: libvirt-0.8.1/src/qemu/qemu_driver.c
===================================================================
--- libvirt-0.8.1.orig/src/qemu/qemu_driver.c
+++ libvirt-0.8.1/src/qemu/qemu_driver.c
@@ -1289,7 +1289,8 @@ qemudSecurityInit(struct qemud_driver *q
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;
@@ -9145,8 +9146,15 @@ static int qemuDomainGetBlockInfo(virDom
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,
Index: libvirt-0.8.1/src/qemu/qemu_security_dac.c
===================================================================
--- libvirt-0.8.1.orig/src/qemu/qemu_security_dac.c
+++ libvirt-0.8.1/src/qemu/qemu_security_dac.c
@@ -118,7 +118,7 @@ qemuSecurityDACSetSecurityImageLabel(vir
return 0;
return virDomainDiskDefForeachPath(disk,
- true,
+ driver->allowDiskFormatProbing,
false,
qemuSecurityDACSetSecurityFileLabel,
NULL);
Index: libvirt-0.8.1/src/qemu/test_libvirtd_qemu.aug
===================================================================
--- libvirt-0.8.1.orig/src/qemu/test_libvirtd_qemu.aug
+++ libvirt-0.8.1/src/qemu/test_libvirtd_qemu.aug
@@ -97,6 +97,8 @@ save_image_format = \"gzip\"
hugetlbfs_mount = \"/dev/hugepages\"
relaxed_acs_check = 1
+
+allow_disk_format_probing = 1
"
test Libvirtd_qemu.lns get conf =
@@ -204,3 +206,5 @@ relaxed_acs_check = 1
{ "hugetlbfs_mount" = "/dev/hugepages" }
{ "#empty" }
{ "relaxed_acs_check" = "1" }
+{ "#empty" }
+{ "allow_disk_format_probing" = "1" }
Index: libvirt-0.8.1/src/security/security_apparmor.c
===================================================================
--- libvirt-0.8.1.orig/src/security/security_apparmor.c
+++ libvirt-0.8.1/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 (disk && disk->src) {
const char *const argv[] = {
- VIRT_AA_HELPER, "-r", "-u", profile, "-f", disk->src, NULL
+ VIRT_AA_HELPER, "-p", probe, "-r", "-u", profile, "-f", disk->src, 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);
@@ -312,9 +314,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;
}
Index: libvirt-0.8.1/src/security/security_driver.c
===================================================================
--- libvirt-0.8.1.orig/src/security/security_driver.c
+++ libvirt-0.8.1/src/security/security_driver.c
@@ -56,7 +56,8 @@ virSecurityDriverVerify(virDomainDefPtr
int
virSecurityDriverStartup(virSecurityDriverPtr *drv,
- const char *name)
+ const char *name,
+ bool allowDiskFormatProbing)
{
unsigned int i;
@@ -72,7 +73,7 @@ virSecurityDriverStartup(virSecurityDriv
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(virSecurityDri
{
return drv->name;
}
+
+void virSecurityDriverSetAllowDiskFormatProbing(virSecurityDriverPtr drv,
+ bool allowDiskFormatProbing)
+{
+ drv->_private.allowDiskFormatProbing = allowDiskFormatProbing;
+}
+
+bool virSecurityDriverGetAllowDiskFormatProbing(virSecurityDriverPtr drv)
+{
+ return drv->_private.allowDiskFormatProbing;
+}
Index: libvirt-0.8.1/src/security/security_driver.h
===================================================================
--- libvirt-0.8.1.orig/src/security/security_driver.h
+++ libvirt-0.8.1/src/security/security_driver.h
@@ -33,7 +33,8 @@ typedef struct _virSecurityDriverState v
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);
@@ -94,12 +95,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);
@@ -112,7 +115,10 @@ virSecurityDriverVerify(virDomainDefPtr
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__ */
Index: libvirt-0.8.1/src/security/security_selinux.c
===================================================================
--- libvirt-0.8.1.orig/src/security/security_selinux.c
+++ libvirt-0.8.1/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();
}
@@ -438,18 +440,19 @@ SELinuxSetSecurityFileLabel(virDomainDis
}
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);
Index: libvirt-0.8.1/src/security/virt-aa-helper.c
===================================================================
--- libvirt-0.8.1.orig/src/security/virt-aa-helper.c
+++ libvirt-0.8.1/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
@@ -845,7 +846,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);
@@ -944,6 +945,7 @@ vahParseArgv(vahControl * ctl, int argc,
{
int arg, idx = 0;
struct option opt[] = {
+ {"probing", 1, 0, 'p' },
{"add", 0, 0, 'a'},
{"create", 0, 0, 'c'},
{"dryrun", 0, 0, 'd'},
@@ -992,6 +994,12 @@ vahParseArgv(vahControl * ctl, int argc,
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;
Index: libvirt-0.8.1/tests/seclabeltest.c
===================================================================
--- libvirt-0.8.1.orig/tests/seclabeltest.c
+++ libvirt-0.8.1/tests/seclabeltest.c
@@ -15,7 +15,7 @@ main (int argc ATTRIBUTE_UNUSED, char **
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");
Index: libvirt-0.8.1/src/qemu/qemu_conf.h
===================================================================
--- libvirt-0.8.1.orig/src/qemu/qemu_conf.h
+++ libvirt-0.8.1/src/qemu/qemu_conf.h
@@ -137,6 +137,7 @@ struct qemud_driver {
ebtablesContext *ebtables;
unsigned int relaxedACS : 1;
+ unsigned int allowDiskFormatProbing : 1;
virCapsPtr caps;
Index: libvirt-0.8.1/tests/secaatest.c
===================================================================
--- libvirt-0.8.1.orig/tests/secaatest.c
+++ libvirt-0.8.1/tests/secaatest.c
@@ -15,7 +15,7 @@ main (int argc ATTRIBUTE_UNUSED, char **
const char *doi, *model;
virSecurityDriverPtr security_drv;
- ret = virSecurityDriverStartup (&security_drv, "apparmor");
+ ret = virSecurityDriverStartup (&security_drv, "apparmor", false);
if (ret == -1)
{
fprintf (stderr, "Failed to start security driver");

View File

@ -1,110 +0,0 @@
>From f087f0656f882be305783e24d55921b57fbbcb97 Mon Sep 17 00:00:00 2001
From: Daniel P. Berrange <berrange@redhat.com>
Date: Mon, 14 Jun 2010 16:08:55 +0100
Subject: [PATCH 09/10] Add ability to set a default driver name/type when parsing disks
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 | 21 ++++++++++++++++++---
src/qemu/qemu_driver.c | 8 ++++++++
3 files changed, 28 insertions(+), 3 deletions(-)
Index: libvirt-0.8.1/src/conf/capabilities.h
===================================================================
--- libvirt-0.8.1.orig/src/conf/capabilities.h
+++ libvirt-0.8.1/src/conf/capabilities.h
@@ -120,6 +120,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 *);
Index: libvirt-0.8.1/src/conf/domain_conf.c
===================================================================
--- libvirt-0.8.1.orig/src/conf/domain_conf.c
+++ libvirt-0.8.1/src/conf/domain_conf.c
@@ -1366,7 +1366,8 @@ virDomainDiskDefAssignAddress(virDomainD
* @param node XML nodeset to parse for disk definition
*/
static virDomainDiskDefPtr
-virDomainDiskDefParseXML(xmlNodePtr node,
+virDomainDiskDefParseXML(virCapsPtr caps,
+ xmlNodePtr node,
int flags) {
virDomainDiskDefPtr def;
xmlNodePtr cur;
@@ -1595,6 +1596,16 @@ virDomainDiskDefParseXML(xmlNodePtr node
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(def) < 0)
goto error;
@@ -1615,6 +1626,9 @@ cleanup:
return def;
+no_memory:
+ virReportOOMError();
+
error:
virDomainDiskDefFree(def);
def = NULL;
@@ -3521,7 +3535,7 @@ virDomainDeviceDefPtr virDomainDeviceDef
if (xmlStrEqual(node->name, BAD_CAST "disk")) {
dev->type = VIR_DOMAIN_DEVICE_DISK;
- if (!(dev->data.disk = virDomainDiskDefParseXML(node, flags)))
+ if (!(dev->data.disk = virDomainDiskDefParseXML(caps, node, flags)))
goto error;
} else if (xmlStrEqual(node->name, BAD_CAST "filesystem")) {
dev->type = VIR_DOMAIN_DEVICE_FS;
@@ -4028,7 +4042,8 @@ static virDomainDefPtr virDomainDefParse
if (n && VIR_ALLOC_N(def->disks, n) < 0)
goto no_memory;
for (i = 0 ; i < n ; i++) {
- virDomainDiskDefPtr disk = virDomainDiskDefParseXML(nodes[i],
+ virDomainDiskDefPtr disk = virDomainDiskDefParseXML(caps,
+ nodes[i],
flags);
if (!disk)
goto error;
Index: libvirt-0.8.1/src/qemu/qemu_driver.c
===================================================================
--- libvirt-0.8.1.orig/src/qemu/qemu_driver.c
+++ libvirt-0.8.1/src/qemu/qemu_driver.c
@@ -1324,6 +1324,14 @@ qemuCreateCapabilities(virCapsPtr oldcap
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;

View File

@ -1,288 +0,0 @@
>From 6883117e3c6a6cabd760b6e6a468b69ad7b02839 Mon Sep 17 00:00:00 2001
From: Daniel P. Berrange <berrange@redhat.com>
Date: Wed, 16 Jun 2010 14:14:05 +0100
Subject: [PATCH 10/10] Rewrite qemu-img backing store format handling
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(-)
Index: libvirt-0.8.1/src/storage/storage_backend.c
===================================================================
--- libvirt-0.8.1.orig/src/storage/storage_backend.c
+++ libvirt-0.8.1/src/storage/storage_backend.c
@@ -563,6 +563,69 @@ static int virStorageBackendCreateExecCo
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,
@@ -570,10 +633,9 @@ virStorageBackendCreateQemuImg(virConnec
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 ?
@@ -584,41 +646,10 @@ virStorageBackendCreateQemuImg(virConnec
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,
@@ -692,44 +723,103 @@ virStorageBackendCreateQemuImg(virConnec
}
}
- 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)
+ 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)
- imgargvbacking[10] = "-e";
- } else if (vol->target.encryption != NULL)
- imgargvbacking[8] = "-e";
- imgargv = imgargvbacking;
+ 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";
- }
-
- /* Size in KB */
- snprintf(size, sizeof(size), "%lluK", vol->capacity/1024);
+ ret = virStorageBackendCreateExecCommand(pool, vol, imgargv);
+ }
- ret = virStorageBackendCreateExecCommand(pool, vol, imgargv);
- VIR_FREE(imgargv[0]);
+ cleanup:
+ VIR_FREE(create_tool);
return ret;
}

View File

@ -1,262 +0,0 @@
From 02318d5d46e1952294c20b41427dea124cbebb0a Mon Sep 17 00:00:00 2001
From: Daniel P. Berrange <berrange@redhat.com>
Date: Thu, 10 Jun 2010 12:50:38 -0400
Subject: [PATCH] Apply a source port mapping to virtual network masquerading
IPtables will seek to preserve the source port unchanged when
doing masquerading, if possible. NFS has a pseudo-security
option where it checks for the source port <= 1023 before
allowing a mount request. If an admin has used this to make the
host OS trusted for mounts, the default iptables behaviour will
potentially allow NAT'd guests access too. This needs to be
stopped.
With this change, the iptables -t nat -L -n -v rules for the
default network will be
Chain POSTROUTING (policy ACCEPT 95 packets, 9163 bytes)
pkts bytes target prot opt in out source destination
14 840 MASQUERADE tcp -- * * 192.168.122.0/24 !192.168.122.0/24 masq ports: 1024-65535
75 5752 MASQUERADE udp -- * * 192.168.122.0/24 !192.168.122.0/24 masq ports: 1024-65535
0 0 MASQUERADE all -- * * 192.168.122.0/24 !192.168.122.0/24
* src/network/bridge_driver.c: Add masquerade rules for TCP
and UDP protocols
* src/util/iptables.c, src/util/iptables.c: Add source port
mappings for TCP & UDP protocols when masquerading.
---
src/network/bridge_driver.c | 73 ++++++++++++++++++++++++++++++++++++++++--
src/util/iptables.c | 70 +++++++++++++++++++++++++++++------------
src/util/iptables.h | 6 ++-
3 files changed, 122 insertions(+), 27 deletions(-)
Index: libvirt-0.8.1/src/network/bridge_driver.c
===================================================================
--- libvirt-0.8.1.orig/src/network/bridge_driver.c
+++ libvirt-0.8.1/src/network/bridge_driver.c
@@ -638,18 +638,75 @@ networkAddMasqueradingIptablesRules(stru
goto masqerr2;
}
+ /*
+ * Enable masquerading.
+ *
+ * We need to end up with 3 rules in the table in this order
+ *
+ * 1. protocol=tcp with sport mapping restricton
+ * 2. protocol=udp with sport mapping restricton
+ * 3. generic any protocol
+ *
+ * The sport mappings are required, because default IPtables
+ * MASQUERADE is maintain port number unchanged where possible.
+ *
+ * NFS can be configured to only "trust" port numbers < 1023.
+ *
+ * Guests using NAT thus need to be prevented from having port
+ * numbers < 1023, otherwise they can bypass the NFS "security"
+ * check on the source port number.
+ *
+ * Since we use '--insert' to add rules to the header of the
+ * chain, we actually need to add them in the reverse of the
+ * order just mentioned !
+ */
+
+ /* First the generic masquerade rule for other protocols */
/* enable masquerading */
if ((err = iptablesAddForwardMasquerade(driver->iptables,
network->def->network,
- network->def->forwardDev))) {
+ network->def->forwardDev,
+ NULL))) {
virReportSystemError(err,
_("failed to add iptables rule to enable masquerading to '%s'\n"),
network->def->forwardDev ? network->def->forwardDev : NULL);
goto masqerr3;
}
+ /* UDP with a source port restriction */
+ if ((err = iptablesAddForwardMasquerade(driver->iptables,
+ network->def->network,
+ network->def->forwardDev,
+ "udp"))) {
+ virReportSystemError(err,
+ _("failed to add iptables rule to enable UDP masquerading to '%s'"),
+ network->def->forwardDev ? network->def->forwardDev : NULL);
+ goto masqerr4;
+ }
+
+ /* TCP with a source port restriction */
+ if ((err = iptablesAddForwardMasquerade(driver->iptables,
+ network->def->network,
+ network->def->forwardDev,
+ "tcp"))) {
+ virReportSystemError(err,
+ _("failed to add iptables rule to enable TCP masquerading to '%s'"),
+ network->def->forwardDev ? network->def->forwardDev : NULL);
+ goto masqerr5;
+ }
+
return 1;
+ masqerr5:
+ iptablesRemoveForwardMasquerade(driver->iptables,
+ network->def->network,
+ network->def->forwardDev,
+ "udp");
+ masqerr4:
+ iptablesRemoveForwardMasquerade(driver->iptables,
+ network->def->network,
+ network->def->forwardDev,
+ NULL);
masqerr3:
iptablesRemoveForwardAllowRelatedIn(driver->iptables,
network->def->network,
@@ -801,8 +858,17 @@ networkRemoveIptablesRules(struct networ
if (network->def->forwardType != VIR_NETWORK_FORWARD_NONE) {
if (network->def->forwardType == VIR_NETWORK_FORWARD_NAT) {
iptablesRemoveForwardMasquerade(driver->iptables,
- network->def->network,
- network->def->forwardDev);
+ network->def->network,
+ network->def->forwardDev,
+ "tcp");
+ iptablesRemoveForwardMasquerade(driver->iptables,
+ network->def->network,
+ network->def->forwardDev,
+ "udp");
+ iptablesRemoveForwardMasquerade(driver->iptables,
+ network->def->network,
+ network->def->forwardDev,
+ NULL);
iptablesRemoveForwardAllowRelatedIn(driver->iptables,
network->def->network,
network->def->bridge,
Index: libvirt-0.8.1/src/util/iptables.c
===================================================================
--- libvirt-0.8.1.orig/src/util/iptables.c
+++ libvirt-0.8.1/src/util/iptables.c
@@ -692,25 +692,49 @@ iptablesRemoveForwardRejectIn(iptablesCo
*/
static int
iptablesForwardMasquerade(iptablesContext *ctx,
- const char *network,
- const char *physdev,
- int action)
+ const char *network,
+ const char *physdev,
+ const char *protocol,
+ int action)
{
- if (physdev && physdev[0]) {
- return iptablesAddRemoveRule(ctx->nat_postrouting,
- action,
- "--source", network,
- "!", "--destination", network,
- "--out-interface", physdev,
- "--jump", "MASQUERADE",
- NULL);
+ if (protocol && protocol[0]) {
+ if (physdev && physdev[0]) {
+ return iptablesAddRemoveRule(ctx->nat_postrouting,
+ action,
+ "--source", network,
+ "-p", protocol,
+ "!", "--destination", network,
+ "--out-interface", physdev,
+ "--jump", "MASQUERADE",
+ "--to-ports", "1024-65535",
+ NULL);
+ } else {
+ return iptablesAddRemoveRule(ctx->nat_postrouting,
+ action,
+ "--source", network,
+ "-p", protocol,
+ "!", "--destination", network,
+ "--jump", "MASQUERADE",
+ "--to-ports", "1024-65535",
+ NULL);
+ }
} else {
- return iptablesAddRemoveRule(ctx->nat_postrouting,
- action,
- "--source", network,
- "!", "--destination", network,
- "--jump", "MASQUERADE",
- NULL);
+ if (physdev && physdev[0]) {
+ return iptablesAddRemoveRule(ctx->nat_postrouting,
+ action,
+ "--source", network,
+ "!", "--destination", network,
+ "--out-interface", physdev,
+ "--jump", "MASQUERADE",
+ NULL);
+ } else {
+ return iptablesAddRemoveRule(ctx->nat_postrouting,
+ action,
+ "--source", network,
+ "!", "--destination", network,
+ "--jump", "MASQUERADE",
+ NULL);
+ }
}
}
@@ -719,6 +743,7 @@ iptablesForwardMasquerade(iptablesContex
* @ctx: pointer to the IP table context
* @network: the source network name
* @physdev: the physical input device or NULL
+ * @protocol: the network protocol or NULL
*
* Add rules to the IP table context to allow masquerading
* network @network on @physdev. This allow the bridge to
@@ -729,9 +754,10 @@ iptablesForwardMasquerade(iptablesContex
int
iptablesAddForwardMasquerade(iptablesContext *ctx,
const char *network,
- const char *physdev)
+ const char *physdev,
+ const char *protocol)
{
- return iptablesForwardMasquerade(ctx, network, physdev, ADD);
+ return iptablesForwardMasquerade(ctx, network, physdev, protocol, ADD);
}
/**
@@ -739,6 +765,7 @@ iptablesAddForwardMasquerade(iptablesCon
* @ctx: pointer to the IP table context
* @network: the source network name
* @physdev: the physical input device or NULL
+ * @protocol: the network protocol or NULL
*
* Remove rules from the IP table context to stop masquerading
* network @network on @physdev. This stops the bridge from
@@ -749,7 +776,8 @@ iptablesAddForwardMasquerade(iptablesCon
int
iptablesRemoveForwardMasquerade(iptablesContext *ctx,
const char *network,
- const char *physdev)
+ const char *physdev,
+ const char *protocol)
{
- return iptablesForwardMasquerade(ctx, network, physdev, REMOVE);
+ return iptablesForwardMasquerade(ctx, network, physdev, protocol, REMOVE);
}
Index: libvirt-0.8.1/src/util/iptables.h
===================================================================
--- libvirt-0.8.1.orig/src/util/iptables.h
+++ libvirt-0.8.1/src/util/iptables.h
@@ -85,9 +85,11 @@ int iptablesRemoveForwardRe
int iptablesAddForwardMasquerade (iptablesContext *ctx,
const char *network,
- const char *physdev);
+ const char *physdev,
+ const char *protocol);
int iptablesRemoveForwardMasquerade (iptablesContext *ctx,
const char *network,
- const char *physdev);
+ const char *physdev,
+ const char *protocol);
#endif /* __QEMUD_IPTABLES_H__ */

View File

@ -1,29 +0,0 @@
commit ce49cfb48ad5e9cac79819d0ccde4394c237af25
Author: Eric Blake <eblake@redhat.com>
Date: Wed Jun 2 09:03:57 2010 -0600
bitmap: reject zero-size bitmap
* src/util/bitmap.c (virBitmapAlloc): Tighten sanity check.
diff --git a/src/util/bitmap.c b/src/util/bitmap.c
index 69094a5..44edb49 100644
--- a/src/util/bitmap.c
+++ b/src/util/bitmap.c
@@ -1,6 +1,7 @@
/*
* bitmap.h: Simple bitmap operations
*
+ * Copyright (C) 2010 Red Hat, Inc.
* Copyright (C) 2010 Novell, Inc.
*
* This library is free software; you can redistribute it and/or
@@ -58,7 +59,7 @@ virBitmapPtr virBitmapAlloc(size_t size)
virBitmapPtr bitmap;
size_t sz;
- if (SIZE_MAX - VIR_BITMAP_BITS_PER_UNIT < size)
+ if (SIZE_MAX - VIR_BITMAP_BITS_PER_UNIT < size || size == 0)
return NULL;
sz = (size + VIR_BITMAP_BITS_PER_UNIT - 1) /

View File

@ -1,59 +0,0 @@
If VM startup fails early enough (can't find a referenced USB device),
libvirtd will crash trying to clear the VNC port bit, since port = 0,
which overflows us out of the bitmap bounds.
Fix this by being more defensive in the bitmap operations, and only
clearing a previously set VNC port.
v2: Add safety check to all relevant bitmap ops.
Signed-off-by: Cole Robinson <crobinso@redhat.com>
---
src/qemu/qemu_driver.c | 2 +-
src/util/bitmap.c | 6 +++---
2 files changed, 4 insertions(+), 4 deletions(-)
Index: libvirt-0.8.1/src/qemu/qemu_driver.c
===================================================================
--- libvirt-0.8.1.orig/src/qemu/qemu_driver.c
+++ libvirt-0.8.1/src/qemu/qemu_driver.c
@@ -3635,7 +3635,7 @@ retry:
if ((vm->def->ngraphics == 1) &&
vm->def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC &&
vm->def->graphics[0]->data.vnc.autoport &&
- vm->def->graphics[0]->data.vnc.port != -1) {
+ vm->def->graphics[0]->data.vnc.port >= QEMU_VNC_PORT_MIN) {
if (virBitmapClearBit(driver->reservedVNCPorts,
vm->def->graphics[0]->data.vnc.port - \
QEMU_VNC_PORT_MIN) < 0) {
Index: libvirt-0.8.1/src/util/bitmap.c
===================================================================
--- libvirt-0.8.1.orig/src/util/bitmap.c
+++ libvirt-0.8.1/src/util/bitmap.c
@@ -101,7 +101,7 @@ void virBitmapFree(virBitmapPtr bitmap)
*/
int virBitmapSetBit(virBitmapPtr bitmap, size_t b)
{
- if (b > bitmap->size - 1)
+ if (bitmap->size <= b)
return -1;
bitmap->map[VIR_BITMAP_UNIT_OFFSET(b)] |= (1 << VIR_BITMAP_BIT_OFFSET(b));
@@ -119,7 +119,7 @@ int virBitmapSetBit(virBitmapPtr bitmap,
*/
int virBitmapClearBit(virBitmapPtr bitmap, size_t b)
{
- if (b > bitmap->size - 1)
+ if (bitmap->size <= b)
return -1;
bitmap->map[VIR_BITMAP_UNIT_OFFSET(b)] &= ~(1 << VIR_BITMAP_BIT_OFFSET(b));
@@ -141,7 +141,7 @@ int virBitmapGetBit(virBitmapPtr bitmap,
{
uint32_t bit;
- if (b > bitmap->size - 1)
+ if (bitmap->size <= b)
return -1;
bit = bitmap->map[VIR_BITMAP_UNIT_OFFSET(b)] &

View File

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:037256df745a96ba141dbfc4e4197e8bc16c51f21c834f4f89c599c379792698
size 7706670

3
libvirt-0.8.3.tar.bz2 Normal file
View File

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:759f4957e6f2b905857897a84e36cbe73f7dc3a5150637430ff086c3e2b414b4
size 8250164

View File

@ -1,3 +1,12 @@
-------------------------------------------------------------------
Fri Aug 6 21:53:21 MDT 2010 - jfehlig@novell.com
- Update to libvirt 0.8.3
- Support vSphere 4.1
- Qemu arbitrary monitor commands
- Qemu Monitor API entry point
- lots of improvements and bug fixes
-------------------------------------------------------------------
Fri Jul 9 14:35:04 MDT 2010 - jfehlig@novell.com

View File

@ -1,5 +1,5 @@
#
# spec file for package libvirt (Version 0.8.1)
# spec file for package libvirt (Version 0.8.3)
#
# Copyright (c) 2010 SUSE LINUX Products GmbH, Nuernberg, Germany.
#
@ -44,6 +44,7 @@
%define with_udev 0
%define with_hal 0
%define with_yajl 0
%define with_macvtap 0
# Xen is available only on i386 x86_64
%ifnarch %ix86 x86_64
@ -110,14 +111,17 @@ BuildRequires: PolicyKit-devel >= 0.6
%if %{with_phyp}
BuildRequires: libssh2-devel
%endif
%if %{with_macvtap}
BuildRequires: libnl-devel
%endif
# Only for directory ownership:
BuildRequires: gtk-doc
Url: http://libvirt.org/
License: LGPLv2.1+
Group: Development/Libraries/C and C++
AutoReqProv: yes
Version: 0.8.1
Release: 2
Version: 0.8.3
Release: 1
Summary: A C toolkit to interract with the virtualization capabilities of Linux
# The client side, i.e. shared libs and virsh are in a subpackage
Requires: %{name}-client = %{version}-%{release}
@ -141,25 +145,6 @@ Requires: PolicyKit >= 0.6
Source0: %{name}-%{version}.tar.bz2
Source1: libvirtd.init
# Upstream patches
Patch0: remote-rm-unused-field.patch
Patch1: vnc-race-1.patch
Patch2: vnc-race-2.patch
Patch3: vnc-race-3.patch
Patch4: bitmap-alloc.patch
Patch5: bitmap-fixes.patch
Patch6: xend-content-buf.patch
Patch7: xend-content-buf-fix.patch
Patch8: CVE-2010-223x-0001.patch
Patch9: CVE-2010-223x-0002.patch
Patch10: CVE-2010-223x-0003.patch
Patch11: CVE-2010-223x-0004.patch
Patch12: CVE-2010-223x-0005.patch
Patch13: CVE-2010-223x-0006.patch
Patch14: CVE-2010-223x-0007.patch
Patch15: CVE-2010-223x-0008.patch
Patch16: CVE-2010-223x-0009.patch
Patch17: CVE-2010-223x-0010.patch
Patch18: CVE-2010-2242-nat.patch
# Need to go upstream
Patch100: xen-name-for-devid.patch
Patch102: clone.patch
@ -272,25 +257,6 @@ Authors:
%prep
%setup -q
%patch0 -p1
%patch1 -p1
%patch2 -p1
%patch3 -p1
%patch4 -p1
%patch5 -p1
%patch6 -p1
%patch7 -p1
%patch8 -p1
%patch9 -p1
%patch10 -p1
%patch11 -p1
%patch12 -p1
%patch13 -p1
%patch14 -p1
%patch15 -p1
%patch16 -p1
%patch17 -p1
%patch18 -p1
%patch100 -p1
%patch102
%patch103 -p1
@ -351,6 +317,9 @@ Authors:
%if ! %{with_yajl}
%define _without_yajl --without-yajl
%endif
%if ! %{with_macvtap}
%define _without_macvtap --without-macvtap
%endif
autoreconf -f -i
export CFLAGS="$RPM_OPT_FLAGS"
%configure --disable-static --with-pic \
@ -372,6 +341,7 @@ export CFLAGS="$RPM_OPT_FLAGS"
%{?_without_hal} \
%{?_without_udev} \
%{?_without_yajl} \
%{?_without_macvtap} \
--without-xen-proxy \
--libexecdir=%{_libdir}/%{name} \
--with-init-script=none \
@ -497,6 +467,7 @@ rm -rf $RPM_BUILD_ROOT
%if 0%{with_storage_disk}
%{_libdir}/%{name}/libvirt_parthelper
%endif
%doc %{_mandir}/man8/libvirtd.8*
%files client -f %{name}.lang
%defattr(-, root, root)
@ -525,6 +496,7 @@ rm -rf $RPM_BUILD_ROOT
%{_datadir}/libvirt/schemas/storageencryption.rng
%{_datadir}/libvirt/cpu_map.xml
%{_datadir}/libvirt/schemas/nwfilter.rng
%{_datadir}/libvirt/schemas/domainsnapshot.rng
%config(noreplace) %{_sysconfdir}/sasl2/libvirt.conf
%files devel

View File

@ -1,50 +0,0 @@
commit 34a7f3f6be9c63ac3d4c4604c1fb2482a4e5053b
Author: Matthew Booth <mbooth@redhat.com>
Date: Fri May 7 16:38:05 2010 +0200
Remove unused nwfilter field from struct remote_error
Change 965466c1 added a new field to struct remote_error, which broke
the RPC protocol. Fortunately the new field is unused, so this change
simply removes it again.
* src/remote/remote_protocol.(c|h|x): Remove remote_nwfilter from struct
remote_error
diff --git a/src/remote/remote_protocol.c b/src/remote/remote_protocol.c
index 187281d..972bf52 100644
--- a/src/remote/remote_protocol.c
+++ b/src/remote/remote_protocol.c
@@ -227,8 +227,6 @@ xdr_remote_error (XDR *xdrs, remote_error *objp)
return FALSE;
if (!xdr_remote_network (xdrs, &objp->net))
return FALSE;
- if (!xdr_remote_nwfilter (xdrs, &objp->nwfilter))
- return FALSE;
return TRUE;
}
diff --git a/src/remote/remote_protocol.h b/src/remote/remote_protocol.h
index 6f01da7..a600af6 100644
--- a/src/remote/remote_protocol.h
+++ b/src/remote/remote_protocol.h
@@ -143,7 +143,6 @@ struct remote_error {
int int1;
int int2;
remote_network net;
- remote_nwfilter nwfilter;
};
typedef struct remote_error remote_error;
diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x
index 8000ee0..1ce488c 100644
--- a/src/remote/remote_protocol.x
+++ b/src/remote/remote_protocol.x
@@ -266,7 +266,6 @@ struct remote_error {
int int1;
int int2;
remote_network net;
- remote_nwfilter nwfilter;
};
/* Authentication types available thus far.... */

View File

@ -1,281 +0,0 @@
commit 2f32d7afd5bd71f79c0e756c87813702065c6d1a
Author: Jim Fehlig <jfehlig@novell.com>
Date: Thu May 20 22:23:48 2010 -0600
Add simple bitmap operations to utils
V2:
- Move bitmap impl to src/util/bitmap.[ch]
- Use CHAR_BIT instead of explicit '8'
- Use size_t instead of unsigned int
- Fix calculation of bitmap size in virBitmapAlloc
- Ensure bit is within range of map in the set, clear, and get
operations
- Use bool in virBitmapGetBit
- Add virBitmapFree to free-like funcs in cfg.mk
V3:
- Check for overflow in virBitmapAlloc
- Fix copy and paste bug in virBitmapAlloc
- Use size_t in prototypes
- Add ATTRIBUTE_NONNULL in prototypes where appropriate
and remove NULL check from impl
V4:
- Add ATTRIBUTE_RETURN_CHECK in prototypes where appropriate.
Index: libvirt-0.8.1/src/Makefile.am
===================================================================
--- libvirt-0.8.1.orig/src/Makefile.am
+++ libvirt-0.8.1/src/Makefile.am
@@ -50,6 +50,7 @@ augeastest_DATA =
# helper APIs for various purposes
UTIL_SOURCES = \
util/authhelper.c util/authhelper.h \
+ util/bitmap.c util/bitmap.h \
util/bridge.c util/bridge.h \
util/buf.c util/buf.h \
util/conf.c util/conf.h \
Index: libvirt-0.8.1/src/libvirt_private.syms
===================================================================
--- libvirt-0.8.1.orig/src/libvirt_private.syms
+++ libvirt-0.8.1/src/libvirt_private.syms
@@ -4,6 +4,14 @@
#
+# bitmap.h
+virBitmapAlloc;
+virBitmapFree;
+virBitmapSetBit;
+virBitmapClearBit;
+virBitmapGetBit;
+
+
# buf.h
virBufferVSprintf;
virBufferEscapeString;
Index: libvirt-0.8.1/src/util/bitmap.c
===================================================================
--- /dev/null
+++ libvirt-0.8.1/src/util/bitmap.c
@@ -0,0 +1,151 @@
+/*
+ * bitmap.h: Simple bitmap operations
+ *
+ * Copyright (C) 2010 Novell, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Jim Fehlig <jfehlig@novell.com>
+ */
+
+#include <config.h>
+
+#include <limits.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+
+#include "bitmap.h"
+#include "memory.h"
+
+
+struct _virBitmap {
+ size_t size;
+ uint32_t *map;
+};
+
+
+#define VIR_BITMAP_BITS_PER_UNIT (sizeof(uint32_t) * CHAR_BIT)
+#define VIR_BITMAP_UNIT_OFFSET(b) ((b) / VIR_BITMAP_BITS_PER_UNIT)
+#define VIR_BITMAP_BIT_OFFSET(b) ((b) % VIR_BITMAP_BITS_PER_UNIT)
+
+
+/**
+ * virBitmapAlloc:
+ * @size: number of bits
+ *
+ * Allocate a bitmap capable of containing @size bits.
+ *
+ * Returns a pointer to the allocated bitmap or NULL if
+ * memory cannot be allocated.
+ */
+virBitmapPtr virBitmapAlloc(size_t size)
+{
+ virBitmapPtr bitmap;
+ size_t sz;
+
+ if (SIZE_MAX - VIR_BITMAP_BITS_PER_UNIT < size)
+ return NULL;
+
+ sz = (size + VIR_BITMAP_BITS_PER_UNIT - 1) /
+ VIR_BITMAP_BITS_PER_UNIT;
+
+ if (VIR_ALLOC(bitmap) < 0)
+ return NULL;
+
+ if (VIR_ALLOC_N(bitmap->map, sz) < 0) {
+ VIR_FREE(bitmap);
+ return NULL;
+ }
+
+ return bitmap;
+}
+
+/**
+ * virBitmapFree:
+ * @bitmap: previously allocated bitmap
+ *
+ * Free @bitmap previously allocated by virBitmapAlloc.
+ */
+void virBitmapFree(virBitmapPtr bitmap)
+{
+ if (bitmap) {
+ VIR_FREE(bitmap->map);
+ VIR_FREE(bitmap);
+ }
+}
+
+/**
+ * virBitmapSetBit:
+ * @bitmap: Pointer to bitmap
+ * @b: bit position to set
+ *
+ * Set bit position @b in @bitmap
+ *
+ * Returns 0 on if bit is successfully set, -1 on error.
+ */
+int virBitmapSetBit(virBitmapPtr bitmap, size_t b)
+{
+ if (b > bitmap->size - 1)
+ return -1;
+
+ bitmap->map[VIR_BITMAP_UNIT_OFFSET(b)] |= (1 << VIR_BITMAP_BIT_OFFSET(b));
+ return 0;
+}
+
+/**
+ * virBitmapClearBit:
+ * @bitmap: Pointer to bitmap
+ * @b: bit position to clear
+ *
+ * Clear bit position @b in @bitmap
+ *
+ * Returns 0 on if bit is successfully clear, -1 on error.
+ */
+int virBitmapClearBit(virBitmapPtr bitmap, size_t b)
+{
+ if (b > bitmap->size - 1)
+ return -1;
+
+ bitmap->map[VIR_BITMAP_UNIT_OFFSET(b)] &= ~(1 << VIR_BITMAP_BIT_OFFSET(b));
+ return 0;
+}
+
+/**
+ * virBitmapGetBit:
+ * @bitmap: Pointer to bitmap
+ * @b: bit position to get
+ * @result: bool pointer to receive bit setting
+ *
+ * Get setting of bit position @b in @bitmap and store in @result
+ *
+ * On success, @result will contain the setting of @b and 0 is
+ * returned. On failure, -1 is returned and @result is unchanged.
+ */
+int virBitmapGetBit(virBitmapPtr bitmap, size_t b, bool *result)
+{
+ uint32_t bit;
+
+ if (b > bitmap->size - 1)
+ return -1;
+
+ bit = bitmap->map[VIR_BITMAP_UNIT_OFFSET(b)] &
+ (1 << VIR_BITMAP_BIT_OFFSET(b));
+
+ *result = bit != 0;
+ return 0;
+}
Index: libvirt-0.8.1/src/util/bitmap.h
===================================================================
--- /dev/null
+++ libvirt-0.8.1/src/util/bitmap.h
@@ -0,0 +1,63 @@
+/*
+ * bitmap.h: Simple bitmap operations
+ *
+ * Copyright (C) 2010 Novell, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Jim Fehlig <jfehlig@novell.com>
+ */
+
+#ifndef __BITMAP_H__
+# define __BITMAP_H__
+
+#include "internal.h"
+
+#include <stdbool.h>
+#include <sys/types.h>
+
+
+typedef struct _virBitmap virBitmap;
+typedef virBitmap *virBitmapPtr;
+
+/*
+ * Allocate a bitmap capable of containing @size bits.
+ */
+virBitmapPtr virBitmapAlloc(size_t size) ATTRIBUTE_RETURN_CHECK;
+
+/*
+ * Free previously allocated bitmap
+ */
+void virBitmapFree(virBitmapPtr bitmap);
+
+/*
+ * Set bit position @b in @bitmap
+ */
+int virBitmapSetBit(virBitmapPtr bitmap, size_t b)
+ ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK;
+
+/*
+ * Clear bit position @b in @bitmap
+ */
+int virBitmapClearBit(virBitmapPtr bitmap, size_t b)
+ ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK;
+
+/*
+ * Get setting of bit position @b in @bitmap and store in @result
+ */
+int virBitmapGetBit(virBitmapPtr bitmap, size_t b, bool *result)
+ ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(3) ATTRIBUTE_RETURN_CHECK;
+
+#endif

View File

@ -1,29 +0,0 @@
commit c020f6203e3735a531135bc4321415ce5520fbde
Author: Jim Fehlig <jfehlig@novell.com>
Date: Thu May 20 22:25:16 2010 -0600
Add defines for QEMU_VNC_PORT_{MIN,MAX} and use them
Index: libvirt-0.8.1/src/qemu/qemu_driver.c
===================================================================
--- libvirt-0.8.1.orig/src/qemu/qemu_driver.c
+++ libvirt-0.8.1/src/qemu/qemu_driver.c
@@ -89,6 +89,9 @@
#define VIR_FROM_THIS VIR_FROM_QEMU
+#define QEMU_VNC_PORT_MIN 5900
+#define QEMU_VNC_PORT_MAX 65535
+
/* Only 1 job is allowed at any time
* A job includes *all* monitor commands, even those just querying
* information, not merely actions */
@@ -2607,7 +2610,7 @@ qemuInitPCIAddresses(struct qemud_driver
static int qemudNextFreeVNCPort(struct qemud_driver *driver ATTRIBUTE_UNUSED) {
int i;
- for (i = 5900 ; i < 65535 ; i++) {
+ for (i = QEMU_VNC_PORT_MIN; i < QEMU_VNC_PORT_MAX; i++) {
int fd;
int reuse = 1;
struct sockaddr_in addr;

View File

@ -1,130 +0,0 @@
commit ba196952f57f2cb22be75fa5a4f363035a111103
Author: Jim Fehlig <jfehlig@novell.com>
Date: Fri May 21 07:52:09 2010 -0600
Fix race in finding available vnc port
The qemu driver contains a subtle race in the logic to find next
available vnc port. Currently it iterates through all available ports
and returns the first for which bind(2) succeeds. However it is possible
that a previously issued port has not yet been bound by qemu, resulting
in the same port used for a subsequent domain.
This patch addresses the race by using a simple bitmap to "reserve" the
ports allocated by libvirt.
V2:
- Put port bitmap in struct qemud_driver
- Initialize bitmap in qemudStartup
V3:
- Check for failure of virBitmapGetBit
- Additional check for port != -1 before calling virbitmapClearBit
V4:
- Check for failure of virBitmap{Set,Clear}Bit
Index: libvirt-0.8.1/src/qemu/qemu_conf.h
===================================================================
--- libvirt-0.8.1.orig/src/qemu/qemu_conf.h
+++ libvirt-0.8.1/src/qemu/qemu_conf.h
@@ -39,6 +39,7 @@
# include "pci.h"
# include "cpu_conf.h"
# include "driver.h"
+# include "bitmap.h"
# define qemudDebug(fmt, ...) do {} while(0)
@@ -153,6 +154,8 @@ struct qemud_driver {
char *saveImageFormat;
pciDeviceList *activePciHostdevs;
+
+ virBitmapPtr reservedVNCPorts;
};
typedef struct _qemuDomainPCIAddressSet qemuDomainPCIAddressSet;
Index: libvirt-0.8.1/src/qemu/qemu_driver.c
===================================================================
--- libvirt-0.8.1.orig/src/qemu/qemu_driver.c
+++ libvirt-0.8.1/src/qemu/qemu_driver.c
@@ -1479,6 +1479,11 @@ qemudStartup(int privileged) {
virEventAddTimeout(-1, qemuDomainEventFlush, qemu_driver, NULL)) < 0)
goto error;
+ /* Allocate bitmap for vnc port reservation */
+ if ((qemu_driver->reservedVNCPorts =
+ virBitmapAlloc(QEMU_VNC_PORT_MAX - QEMU_VNC_PORT_MIN)) == NULL)
+ goto out_of_memory;
+
if (privileged) {
if (virAsprintf(&qemu_driver->logDir,
"%s/log/libvirt/qemu", LOCAL_STATE_DIR) == -1)
@@ -1775,6 +1780,7 @@ qemudShutdown(void) {
virCapabilitiesFree(qemu_driver->caps);
virDomainObjListDeinit(&qemu_driver->domains);
+ virBitmapFree(qemu_driver->reservedVNCPorts);
VIR_FREE(qemu_driver->securityDriverName);
VIR_FREE(qemu_driver->logDir);
@@ -2607,13 +2613,22 @@ qemuInitPCIAddresses(struct qemud_driver
return ret;
}
-static int qemudNextFreeVNCPort(struct qemud_driver *driver ATTRIBUTE_UNUSED) {
+static int qemudNextFreeVNCPort(struct qemud_driver *driver) {
int i;
for (i = QEMU_VNC_PORT_MIN; i < QEMU_VNC_PORT_MAX; i++) {
int fd;
int reuse = 1;
struct sockaddr_in addr;
+ bool used = false;
+
+ if (virBitmapGetBit(driver->reservedVNCPorts,
+ i - QEMU_VNC_PORT_MIN, &used) < 0)
+ VIR_DEBUG("virBitmapGetBit failed on bit %d", i - QEMU_VNC_PORT_MIN);
+
+ if (used)
+ continue;
+
addr.sin_family = AF_INET;
addr.sin_port = htons(i);
addr.sin_addr.s_addr = htonl(INADDR_ANY);
@@ -2629,6 +2644,12 @@ static int qemudNextFreeVNCPort(struct q
if (bind(fd, (struct sockaddr*)&addr, sizeof(addr)) == 0) {
/* Not in use, lets grab it */
close(fd);
+ /* Add port to bitmap of reserved ports */
+ if (virBitmapSetBit(driver->reservedVNCPorts,
+ i - QEMU_VNC_PORT_MIN) < 0) {
+ VIR_DEBUG("virBitmapSetBit failed on bit %d",
+ i - QEMU_VNC_PORT_MIN);
+ }
return i;
}
close(fd);
@@ -3608,6 +3629,21 @@ retry:
qemudRemoveDomainStatus(driver, vm);
+ /* Remove VNC port from port reservation bitmap, but only if it was
+ reserved by the driver (autoport=yes)
+ */
+ if ((vm->def->ngraphics == 1) &&
+ vm->def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC &&
+ vm->def->graphics[0]->data.vnc.autoport &&
+ vm->def->graphics[0]->data.vnc.port != -1) {
+ if (virBitmapClearBit(driver->reservedVNCPorts,
+ vm->def->graphics[0]->data.vnc.port - \
+ QEMU_VNC_PORT_MIN) < 0) {
+ VIR_DEBUG("virBitmapClearBit failed on bit %d",
+ vm->def->graphics[0]->data.vnc.port - QEMU_VNC_PORT_MIN);
+ }
+ }
+
vm->pid = -1;
vm->def->id = -1;
vm->state = VIR_DOMAIN_SHUTOFF;

View File

@ -1,79 +0,0 @@
commit b1eb7f2e987d21b1711e86e5cb63a69abfce82f1
Author: Jim Fehlig <jfehlig@linux-ypgk.site>
Date: Fri Jun 4 10:04:03 2010 -0600
Fixes for commit 211dd1e9
Fixes for issues in commit 211dd1e9 noted by by Jim Meyering.
1. Allocate content buffer of size content_length + 1 to ensure
NUL-termination.
2. Limit content buffer size to 64k
3. Fix whitespace issue
V2:
- Add comment to clarify allocation of content buffer
- Add ATTRIBUTE_NONNULL where appropriate
- User NULLSTR macro
diff --git a/src/xen/xend_internal.c b/src/xen/xend_internal.c
index 0c1a738..51cad92 100644
--- a/src/xen/xend_internal.c
+++ b/src/xen/xend_internal.c
@@ -68,6 +68,7 @@
# define XEND_CONFIG_MIN_VERS_PVFB_NEWCONF 3
#endif
+#define XEND_RCV_BUF_MAX_LEN 65536
#ifndef PROXY
static int
@@ -310,7 +311,7 @@ istartswith(const char *haystack, const char *needle)
* Returns the HTTP return code and @content is set to the
* allocated memory containing HTTP content.
*/
-static int
+static int ATTRIBUTE_NONNULL (2)
xend_req(int fd, char **content)
{
char buffer[4096];
@@ -330,7 +331,19 @@ xend_req(int fd, char **content)
if (content_length > 0) {
ssize_t ret;
- if (VIR_ALLOC_N(*content, content_length) < 0 ) {
+ if (content_length > XEND_RCV_BUF_MAX_LEN) {
+ virXendError(VIR_ERR_INTERNAL_ERROR,
+ _("Xend returned HTTP Content-Length of %d, "
+ "which exceeds maximum of %d"),
+ content_length,
+ XEND_RCV_BUF_MAX_LEN);
+ return -1;
+ }
+
+ /* Allocate one byte beyond the end of the largest buffer we will read.
+ Combined with the fact that VIR_ALLOC_N zeros the returned buffer,
+ this guarantees that "content" will always be NUL-terminated. */
+ if (VIR_ALLOC_N(*content, content_length + 1) < 0 ) {
virReportOOMError();
return -1;
}
@@ -353,7 +366,7 @@ xend_req(int fd, char **content)
*
* Returns the HTTP return code or -1 in case or error.
*/
-static int
+static int ATTRIBUTE_NONNULL(3)
xend_get(virConnectPtr xend, const char *path,
char **content)
{
@@ -379,8 +392,7 @@ xend_get(virConnectPtr xend, const char *path,
((ret != 404) || (!STRPREFIX(path, "/xend/domain/")))) {
virXendError(VIR_ERR_GET_FAILED,
_("%d status from xen daemon: %s:%s"),
- ret, path,
- content ? *content: "NULL");
+ ret, path, NULLSTR(*content));
}
return ret;

View File

@ -1,244 +0,0 @@
commit 211dd1e9c54a9ba92e2e648acacbc18981374073
Author: Jim Fehlig <jfehlig@novell.com>
Date: Wed Jun 2 18:07:17 2010 -0600
Allocate buffer to hold xend response
There are cases when a response from xend can exceed 4096 bytes, in
which case anything beyond 4096 is ignored. This patch changes the
current fixed-size, stack-allocated buffer to a dynamically allocated
buffer based on Content-Length in HTTP header.
diff --git a/src/xen/xend_internal.c b/src/xen/xend_internal.c
index e763bad..0c1a738 100644
--- a/src/xen/xend_internal.c
+++ b/src/xen/xend_internal.c
@@ -302,17 +302,19 @@ istartswith(const char *haystack, const char *needle)
* xend_req:
* @fd: the file descriptor
* @content: the buffer to store the content
- * @n_content: the size of the buffer
*
* Read the HTTP response from a Xen Daemon request.
+ * If the response contains content, memory is allocated to
+ * hold the content.
*
- * Returns the HTTP return code.
+ * Returns the HTTP return code and @content is set to the
+ * allocated memory containing HTTP content.
*/
static int
-xend_req(int fd, char *content, size_t n_content)
+xend_req(int fd, char **content)
{
char buffer[4096];
- int content_length = -1;
+ int content_length = 0;
int retcode = 0;
while (sreads(fd, buffer, sizeof(buffer)) > 0) {
@@ -325,19 +327,17 @@ xend_req(int fd, char *content, size_t n_content)
retcode = atoi(buffer + 9);
}
- if (content_length > -1) {
+ if (content_length > 0) {
ssize_t ret;
- if ((unsigned int) content_length > (n_content + 1))
- content_length = n_content - 1;
+ if (VIR_ALLOC_N(*content, content_length) < 0 ) {
+ virReportOOMError();
+ return -1;
+ }
- ret = sread(fd, content, content_length);
+ ret = sread(fd, *content, content_length);
if (ret < 0)
return -1;
-
- content[ret] = 0;
- } else {
- content[0] = 0;
}
return retcode;
@@ -348,7 +348,6 @@ xend_req(int fd, char *content, size_t n_content)
* @xend: pointer to the Xen Daemon structure
* @path: the path used for the HTTP request
* @content: the buffer to store the content
- * @n_content: the size of the buffer
*
* Do an HTTP GET RPC with the Xen Daemon
*
@@ -356,7 +355,7 @@ xend_req(int fd, char *content, size_t n_content)
*/
static int
xend_get(virConnectPtr xend, const char *path,
- char *content, size_t n_content)
+ char **content)
{
int ret;
int s = do_connect(xend);
@@ -373,14 +372,15 @@ xend_get(virConnectPtr xend, const char *path,
"Accept-Encoding: identity\r\n"
"Content-Type: application/x-www-form-urlencoded\r\n" "\r\n");
- ret = xend_req(s, content, n_content);
+ ret = xend_req(s, content);
close(s);
if (((ret < 0) || (ret >= 300)) &&
((ret != 404) || (!STRPREFIX(path, "/xend/domain/")))) {
virXendError(VIR_ERR_GET_FAILED,
_("%d status from xen daemon: %s:%s"),
- ret, path, content);
+ ret, path,
+ content ? *content: "NULL");
}
return ret;
@@ -392,8 +392,6 @@ xend_get(virConnectPtr xend, const char *path,
* @xend: pointer to the Xen Daemon structure
* @path: the path used for the HTTP request
* @ops: the information sent for the POST
- * @content: the buffer to store the content
- * @n_content: the size of the buffer
*
* Do an HTTP POST RPC with the Xen Daemon, this usually makes changes at the
* Xen level.
@@ -401,10 +399,10 @@ xend_get(virConnectPtr xend, const char *path,
* Returns the HTTP return code or -1 in case or error.
*/
static int
-xend_post(virConnectPtr xend, const char *path, const char *ops,
- char *content, size_t n_content)
+xend_post(virConnectPtr xend, const char *path, const char *ops)
{
char buffer[100];
+ char *err_buf = NULL;
int ret;
int s = do_connect(xend);
@@ -425,26 +423,28 @@ xend_post(virConnectPtr xend, const char *path, const char *ops,
swrites(s, "\r\n\r\n");
swrites(s, ops);
- ret = xend_req(s, content, n_content);
+ ret = xend_req(s, &err_buf);
close(s);
if ((ret < 0) || (ret >= 300)) {
virXendError(VIR_ERR_POST_FAILED,
- _("xend_post: error from xen daemon: %s"), content);
- } else if ((ret == 202) && (strstr(content, "failed") != NULL)) {
+ _("xend_post: error from xen daemon: %s"), err_buf);
+ } else if ((ret == 202) && err_buf && (strstr(err_buf, "failed") != NULL)) {
virXendError(VIR_ERR_POST_FAILED,
- _("xend_post: error from xen daemon: %s"), content);
+ _("xend_post: error from xen daemon: %s"), err_buf);
ret = -1;
- } else if (((ret >= 200) && (ret <= 202)) && (strstr(content, "xend.err") != NULL)) {
+ } else if (((ret >= 200) && (ret <= 202)) && err_buf &&
+ (strstr(err_buf, "xend.err") != NULL)) {
/* This is to catch case of things like 'virsh dump Domain-0 foo'
* which returns a success code, but the word 'xend.err'
* in body to indicate error :-(
*/
virXendError(VIR_ERR_POST_FAILED,
- _("xend_post: error from xen daemon: %s"), content);
+ _("xend_post: error from xen daemon: %s"), err_buf);
ret = -1;
}
+ VIR_FREE(err_buf);
return ret;
}
#endif /* ! PROXY */
@@ -487,8 +487,6 @@ http2unix(int ret)
* xend_op_ext:
* @xend: pointer to the Xen Daemon structure
* @path: path for the object
- * @error: buffer for the error output
- * @n_error: size of @error
* @key: the key for the operation
* @ap: input values to pass to the operation
*
@@ -497,8 +495,7 @@ http2unix(int ret)
* Returns 0 in case of success, -1 in case of failure.
*/
static int
-xend_op_ext(virConnectPtr xend, const char *path, char *error,
- size_t n_error, const char *key, va_list ap)
+xend_op_ext(virConnectPtr xend, const char *path, const char *key, va_list ap)
{
const char *k = key, *v;
virBuffer buf = VIR_BUFFER_INITIALIZER;
@@ -524,7 +521,7 @@ xend_op_ext(virConnectPtr xend, const char *path, char *error,
}
content = virBufferContentAndReset(&buf);
- ret = http2unix(xend_post(xend, path, content, error, n_error));
+ ret = http2unix(xend_post(xend, path, content));
VIR_FREE(content);
return ret;
@@ -535,8 +532,6 @@ xend_op_ext(virConnectPtr xend, const char *path, char *error,
* xend_op:
* @xend: pointer to the Xen Daemon structure
* @name: the domain name target of this operation
- * @error: buffer for the error output
- * @n_error: size of @error
* @key: the key for the operation
* @ap: input values to pass to the operation
* @...: input values to pass to the operation
@@ -550,14 +545,13 @@ static int ATTRIBUTE_SENTINEL
xend_op(virConnectPtr xend, const char *name, const char *key, ...)
{
char buffer[1024];
- char error[1024];
va_list ap;
int ret;
snprintf(buffer, sizeof(buffer), "/xend/domain/%s", name);
va_start(ap, key);
- ret = xend_op_ext(xend, buffer, error, sizeof(error), key, ap);
+ ret = xend_op_ext(xend, buffer, key, ap);
va_end(ap);
return ret;
@@ -581,21 +575,29 @@ static struct sexpr *sexpr_get(virConnectPtr xend, const char *fmt, ...)
static struct sexpr *
sexpr_get(virConnectPtr xend, const char *fmt, ...)
{
- char buffer[4096];
+ char *buffer = NULL;
char path[1024];
va_list ap;
int ret;
+ struct sexpr *res = NULL;
va_start(ap, fmt);
vsnprintf(path, sizeof(path), fmt, ap);
va_end(ap);
- ret = xend_get(xend, path, buffer, sizeof(buffer));
+ ret = xend_get(xend, path, &buffer);
ret = http2unix(ret);
if (ret == -1)
- return NULL;
+ goto cleanup;
+
+ if (buffer == NULL)
+ goto cleanup;
+
+ res = string2sexpr(buffer);
- return string2sexpr(buffer);
+cleanup:
+ VIR_FREE(buffer);
+ return res;
}
/**