Compare commits

..

23 Commits

Author SHA1 Message Date
Fedora Release Engineering 9774b83ea4 dist-git conversion 2010-07-29 07:21:37 +00:00
Daniel P. Berrange 90784d2b79 Disable broken nwfilterxml2xmltest on ppc 2010-07-12 15:30:24 +00:00
Daniel P. Berrange e865884872 Ensure %with_libnl is defined on PPC 2010-07-12 14:22:15 +00:00
Daniel P. Berrange d150192fd8 Update to 0.8.2 release. Fix CVE-2010-2237, CVE-2010-2238, CVE-2010-2239, CVE-2010-2242 2010-07-12 14:13:54 +00:00
Daniel P. Berrange 14695477a0 Update to 0.8.2 release. Fix CVE-2010-2237, CVE-2010-2238, CVE-2010-2239, CVE-2010-2242 2010-07-12 14:13:51 +00:00
Cole Robinson 96c8a1c6b6 Bump spec for rebuild after applying all patches 2010-06-17 16:20:59 +00:00
Cole Robinson efdae0e168 Actually apply all committed packages 2010-06-17 15:53:20 +00:00
Cole Robinson e942243cd0 Fix attach-device crash on cgroup cleanup (bz 556791)
Fix crash on bad LXC URI (bz 554191)
Add qemu.conf options for audio workaround
Fix permissions of storage backing stores (bz 579067)
Fix parsing certain USB sysfs files (bz 598272)
Improve migration error reporting (bz 499750)
Sanitize pool target paths (bz 494005)
Add qemu.conf for clear emulator capabilities
2010-06-17 15:39:42 +00:00
Cole Robinson 4f371cb8c3 Fix crash with invalid QEmu URI (bz 566070)
Fix VNC TLS crash (bz 544305)
Fix USB devices with high bus/addr values (bz 542639)
Fix save/restore with non-root guests (bz 534143, bz 532654)
Fix USB devices attached via virt-manager (bz 537227)
2010-05-18 16:42:36 +00:00
Bill Nottingham 29768222f1 Fix typo that causes a failure to update the common directory. (releng #2781) 2009-11-26 01:55:06 +00:00
Mark McLoughlin 68c271bad8 * Thu Oct 29 2009 Mark McLoughlin <markmc@redhat.com> - 0.7.1-15
- Avoid compressing small log files (#531030)
2009-10-29 17:26:12 +00:00
Mark McLoughlin 21a9f1ec41 * Thu Oct 29 2009 Mark McLoughlin <markmc@redhat.com> - 0.7.1-14
- Fix xen driver recounting (#531429)
- Fix crash on virsh error (#531429)
- Fix segfault where XML parsing fails in qemu disk hotplug
- Fix segfault where interface target device name is ommitted (#523418)
2009-10-29 10:40:45 +00:00
Mark McLoughlin 39bacac57d * Thu Oct 29 2009 Mark McLoughlin <markmc@redhat.com> - 0.7.1-14
- Make libvirt-devel require libvirt-client, not libvirt
2009-10-29 10:14:00 +00:00
Mark McLoughlin 7d9775ba12 * Mon Oct 19 2009 Mark McLoughlin <markmc@redhat.com> - 0.7.1-13
- Misc fixes to qemu machine types handling
- A couple of XML formatting fixes
2009-10-19 10:14:07 +00:00
Mark McLoughlin 3cfccddffa Add the second patch for #523158 2009-10-13 15:43:51 +00:00
Mark McLoughlin 1bc3776fdb * Tue Oct 13 2009 Mark McLoughlin <markmc@redhat.com> - 0.7.1-12
- Fix restore of qemu guest using raw save format (#523158)
2009-10-13 15:34:19 +00:00
Mark McLoughlin 3a44160f46 * Fri Oct 9 2009 Mark McLoughlin <markmc@redhat.com> - 0.7.1-11
- Fix libvirtd memory leak during error reply sending (#528162)
- Add several PCI hot-unplug typo fixes from upstream
2009-10-09 14:55:28 +00:00
Mark McLoughlin 5e8ea6c64c * Tue Oct 6 2009 Mark McLoughlin <markmc@redhat.com> - 0.7.1-10
- Create /var/log/libvirt/{lxc,uml} dirs for logrotate
- Make libvirt-python dependon on libvirt-client
- Sync misc minor changes from upstream spec
2009-10-06 12:42:16 +00:00
Mark McLoughlin 00ce651fb8 * Tue Oct 6 2009 Mark McLoughlin <markmc@redhat.com> - 0.7.1-9
- Change logrotate config to weekly (#526769)
2009-10-06 09:43:52 +00:00
Mark McLoughlin 3c684a55ed - Re-label qcow2 backing files (#497131) 2009-10-01 15:17:32 +00:00
Mark McLoughlin b1ea570e48 * Thu Oct 1 2009 Mark McLoughlin <markmc@redhat.com> - 0.7.1-8
- Disable sound backend, even when selinux is disabled (#524499)
2009-10-01 08:35:16 +00:00
Mark McLoughlin 6ccf4c1a0c * Wed Sep 30 2009 Mark McLoughlin <markmc@redhat.com> - 0.7.1-7
- Fix USB device passthrough (#522683)
2009-09-30 17:57:50 +00:00
Jesse Keating dbaa6786af Initialize branch F-12 for libvirt 2009-09-29 05:24:04 +00:00
43 changed files with 5525 additions and 4698 deletions
+1 -1
View File
@@ -2,4 +2,4 @@
*.rpm
i686
x86_64
libvirt-*.tar.xz
libvirt-*.tar.gz
@@ -1,34 +0,0 @@
From: Stefan Berger <stefanb@linux.vnet.ibm.com>
Date: Thu, 29 Jun 2017 14:01:11 -0400
Subject: [PATCH] tpm: Use /dev/null for cancel path if none was found
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
TPM 2 does not implement sysfs files for cancellation of commands.
We therefore use /dev/null for the cancel path passed to QEMU.
Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
Tested-by: Javier Martinez Canillas <javierm@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
(cherry picked from commit dfbb15b75433e520fb1b905c1c3e28753e53e4a5)
---
src/util/virtpm.c | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/src/util/virtpm.c b/src/util/virtpm.c
index 6d9b0657a..d5c10da38 100644
--- a/src/util/virtpm.c
+++ b/src/util/virtpm.c
@@ -61,9 +61,7 @@ virTPMCreateCancelPath(const char *devpath)
VIR_FREE(path);
}
if (!path)
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("No usable sysfs TPM cancel file could be "
- "found"));
+ ignore_value(VIR_STRDUP(path, "/dev/null"));
} else {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("TPM device path %s is invalid"), devpath);
@@ -1,108 +0,0 @@
From: Cole Robinson <crobinso@redhat.com>
Date: Sun, 27 Aug 2017 11:23:47 -0400
Subject: [PATCH] security: add MANAGER_MOUNT_NAMESPACE flag
The VIR_SECURITY_MANAGER_MOUNT_NAMESPACE flag informs the DAC driver
if mount namespaces are in use for the VM. Will be used for future
changes.
Wire it up in the qemu driver
(cherry picked from commit 321031e482425dfeae0f125cdac6df870f079efd)
---
src/qemu/qemu_driver.c | 2 ++
src/security/security_dac.c | 10 ++++++++++
src/security/security_dac.h | 3 +++
src/security/security_manager.c | 4 +++-
src/security/security_manager.h | 1 +
5 files changed, 19 insertions(+), 1 deletion(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index b7824512c..1f9264639 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -419,6 +419,8 @@ qemuSecurityInit(virQEMUDriverPtr driver)
if (virQEMUDriverIsPrivileged(driver)) {
if (cfg->dynamicOwnership)
flags |= VIR_SECURITY_MANAGER_DYNAMIC_OWNERSHIP;
+ if (virBitmapIsBitSet(cfg->namespaces, QEMU_DOMAIN_NS_MOUNT))
+ flags |= VIR_SECURITY_MANAGER_MOUNT_NAMESPACE;
if (!(mgr = qemuSecurityNewDAC(QEMU_DRIVER_NAME,
cfg->user,
cfg->group,
diff --git a/src/security/security_dac.c b/src/security/security_dac.c
index ca7a6af6d..507be44a2 100644
--- a/src/security/security_dac.c
+++ b/src/security/security_dac.c
@@ -57,6 +57,7 @@ struct _virSecurityDACData {
gid_t *groups;
int ngroups;
bool dynamicOwnership;
+ bool mountNamespace;
char *baselabel;
virSecurityManagerDACChownCallback chownCallback;
};
@@ -237,6 +238,15 @@ virSecurityDACSetDynamicOwnership(virSecurityManagerPtr mgr,
priv->dynamicOwnership = dynamicOwnership;
}
+void
+virSecurityDACSetMountNamespace(virSecurityManagerPtr mgr,
+ bool mountNamespace)
+{
+ virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);
+ priv->mountNamespace = mountNamespace;
+}
+
+
void
virSecurityDACSetChownCallback(virSecurityManagerPtr mgr,
virSecurityManagerDACChownCallback chownCallback)
diff --git a/src/security/security_dac.h b/src/security/security_dac.h
index 846cefbb5..97681c961 100644
--- a/src/security/security_dac.h
+++ b/src/security/security_dac.h
@@ -32,6 +32,9 @@ int virSecurityDACSetUserAndGroup(virSecurityManagerPtr mgr,
void virSecurityDACSetDynamicOwnership(virSecurityManagerPtr mgr,
bool dynamic);
+void virSecurityDACSetMountNamespace(virSecurityManagerPtr mgr,
+ bool mountNamespace);
+
void virSecurityDACSetChownCallback(virSecurityManagerPtr mgr,
virSecurityManagerDACChownCallback chownCallback);
diff --git a/src/security/security_manager.c b/src/security/security_manager.c
index 95b995230..e43c99d4f 100644
--- a/src/security/security_manager.c
+++ b/src/security/security_manager.c
@@ -146,7 +146,8 @@ virSecurityManagerNewDAC(const char *virtDriver,
virSecurityManagerPtr mgr;
virCheckFlags(VIR_SECURITY_MANAGER_NEW_MASK |
- VIR_SECURITY_MANAGER_DYNAMIC_OWNERSHIP, NULL);
+ VIR_SECURITY_MANAGER_DYNAMIC_OWNERSHIP |
+ VIR_SECURITY_MANAGER_MOUNT_NAMESPACE, NULL);
mgr = virSecurityManagerNewDriver(&virSecurityDriverDAC,
virtDriver,
@@ -161,6 +162,7 @@ virSecurityManagerNewDAC(const char *virtDriver,
}
virSecurityDACSetDynamicOwnership(mgr, flags & VIR_SECURITY_MANAGER_DYNAMIC_OWNERSHIP);
+ virSecurityDACSetMountNamespace(mgr, flags & VIR_SECURITY_MANAGER_MOUNT_NAMESPACE);
virSecurityDACSetChownCallback(mgr, chownCallback);
return mgr;
diff --git a/src/security/security_manager.h b/src/security/security_manager.h
index 01296d339..08fb89203 100644
--- a/src/security/security_manager.h
+++ b/src/security/security_manager.h
@@ -36,6 +36,7 @@ typedef enum {
VIR_SECURITY_MANAGER_REQUIRE_CONFINED = 1 << 2,
VIR_SECURITY_MANAGER_PRIVILEGED = 1 << 3,
VIR_SECURITY_MANAGER_DYNAMIC_OWNERSHIP = 1 << 4,
+ VIR_SECURITY_MANAGER_MOUNT_NAMESPACE = 1 << 5,
} virSecurityManagerNewFlags;
# define VIR_SECURITY_MANAGER_NEW_MASK \
@@ -1,101 +0,0 @@
From: Cole Robinson <crobinso@redhat.com>
Date: Mon, 17 Jul 2017 08:57:57 -0400
Subject: [PATCH] security: dac: relabel spice rendernode
For a logged in user this a path like /dev/dri/renderD128 will have
default ownership root:video which won't work for the qemu:qemu user,
so we need to chown it.
We only do this when mount namespaces are enabled in the qemu driver,
so the chown'ing doesn't interfere with other users of the shared
render node path
https://bugzilla.redhat.com/show_bug.cgi?id=1460804
(cherry picked from commit 98931187eefdec6f2dea5cb82ab6d23a3ffa6634)
---
src/security/security_dac.c | 58 +++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 58 insertions(+)
diff --git a/src/security/security_dac.c b/src/security/security_dac.c
index 507be44a2..349dbe81d 100644
--- a/src/security/security_dac.c
+++ b/src/security/security_dac.c
@@ -1380,6 +1380,54 @@ virSecurityDACRestoreTPMFileLabel(virSecurityManagerPtr mgr,
}
+static int
+virSecurityDACSetGraphicsLabel(virSecurityManagerPtr mgr,
+ virDomainDefPtr def,
+ virDomainGraphicsDefPtr gfx)
+
+{
+ virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);
+ virSecurityLabelDefPtr seclabel;
+ uid_t user;
+ gid_t group;
+
+ /* Skip chowning the shared render file if namespaces are disabled */
+ if (!priv->mountNamespace)
+ return 0;
+
+ seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_DAC_NAME);
+ if (seclabel && !seclabel->relabel)
+ return 0;
+
+ if (virSecurityDACGetIds(seclabel, priv, &user, &group, NULL, NULL) < 0)
+ return -1;
+
+ if (gfx->type == VIR_DOMAIN_GRAPHICS_TYPE_SPICE &&
+ gfx->data.spice.gl == VIR_TRISTATE_BOOL_YES &&
+ gfx->data.spice.rendernode) {
+ if (virSecurityDACSetOwnership(priv, NULL,
+ gfx->data.spice.rendernode,
+ user, group) < 0)
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int
+virSecurityDACRestoreGraphicsLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
+ virDomainDefPtr def ATTRIBUTE_UNUSED,
+ virDomainGraphicsDefPtr gfx ATTRIBUTE_UNUSED)
+
+{
+ /* The only graphics labelling we do is dependent on mountNamespaces,
+ in which case 'restoring' the label doesn't actually accomplish
+ anything, so there's nothing to do here */
+ return 0;
+}
+
+
static int
virSecurityDACSetInputLabel(virSecurityManagerPtr mgr,
virDomainDefPtr def,
@@ -1491,6 +1539,11 @@ virSecurityDACRestoreAllLabel(virSecurityManagerPtr mgr,
rc = -1;
}
+ for (i = 0; i < def->ngraphics; i++) {
+ if (virSecurityDACRestoreGraphicsLabel(mgr, def, def->graphics[i]) < 0)
+ return -1;
+ }
+
for (i = 0; i < def->ninputs; i++) {
if (virSecurityDACRestoreInputLabel(mgr, def, def->inputs[i]) < 0)
rc = -1;
@@ -1611,6 +1664,11 @@ virSecurityDACSetAllLabel(virSecurityManagerPtr mgr,
return -1;
}
+ for (i = 0; i < def->ngraphics; i++) {
+ if (virSecurityDACSetGraphicsLabel(mgr, def, def->graphics[i]) < 0)
+ return -1;
+ }
+
for (i = 0; i < def->ninputs; i++) {
if (virSecurityDACSetInputLabel(mgr, def, def->inputs[i]) < 0)
return -1;
@@ -1,72 +0,0 @@
From: "Daniel P. Berrange" <berrange@redhat.com>
Date: Thu, 5 Oct 2017 17:54:28 +0100
Subject: [PATCH] qemu: ensure TLS clients always verify the server certificate
The default_tls_x509_verify (and related) parameters in qemu.conf
control whether the QEMU TLS servers request & verify certificates
from clients. This works as a simple access control system for
servers by requiring the CA to issue certs to permitted clients.
This use of client certificates is disabled by default, since it
requires extra work to issue client certificates.
Unfortunately the code was using this configuration parameter when
setting up both TLS clients and servers in QEMU. The result was that
TLS clients for character devices and disk devices had verification
turned off, meaning they would ignore errors while validating the
server certificate.
This allows for trivial MITM attacks between client and server,
as any certificate returned by the attacker will be accepted by
the client.
This is assigned CVE-2017-1000256 / LSN-2017-0002
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
(cherry picked from commit 441d3eb6d1be940a67ce45a286602a967601b157)
(cherry picked from commit dc6c41798d1eb5c52c75365ffa22f7672709dfa7)
---
src/qemu/qemu_command.c | 2 +-
tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-chardev.args | 2 +-
.../qemuxml2argv-serial-tcp-tlsx509-secret-chardev.args | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 9a27987d4..ae78cd17e 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -718,7 +718,7 @@ qemuBuildTLSx509BackendProps(const char *tlspath,
if (virJSONValueObjectCreate(propsret,
"s:dir", path,
"s:endpoint", (isListen ? "server": "client"),
- "b:verify-peer", verifypeer,
+ "b:verify-peer", (isListen ? verifypeer : true),
NULL) < 0)
goto cleanup;
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-chardev.args b/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-chardev.args
index 5aff7734e..ab5f7e27f 100644
--- a/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-chardev.args
+++ b/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-chardev.args
@@ -26,7 +26,7 @@ server,nowait \
localport=1111 \
-device isa-serial,chardev=charserial0,id=serial0 \
-object tls-creds-x509,id=objcharserial1_tls0,dir=/etc/pki/libvirt-chardev,\
-endpoint=client,verify-peer=no \
+endpoint=client,verify-peer=yes \
-chardev socket,id=charserial1,host=127.0.0.1,port=5555,\
tls-creds=objcharserial1_tls0 \
-device isa-serial,chardev=charserial1,id=serial1 \
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-secret-chardev.args b/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-secret-chardev.args
index 91f1fe0cd..2567abbfa 100644
--- a/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-secret-chardev.args
+++ b/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-secret-chardev.args
@@ -31,7 +31,7 @@ localport=1111 \
data=9eao5F8qtkGt+seB1HYivWIxbtwUu6MQtg1zpj/oDtUsPr1q8wBYM91uEHCn6j/1,\
keyid=masterKey0,iv=AAECAwQFBgcICQoLDA0ODw==,format=base64 \
-object tls-creds-x509,id=objcharserial1_tls0,dir=/etc/pki/libvirt-chardev,\
-endpoint=client,verify-peer=no,passwordid=charserial1-secret0 \
+endpoint=client,verify-peer=yes,passwordid=charserial1-secret0 \
-chardev socket,id=charserial1,host=127.0.0.1,port=5555,\
tls-creds=objcharserial1_tls0 \
-device isa-serial,chardev=charserial1,id=serial1 \
@@ -1,177 +0,0 @@
From: Peter Krempa <pkrempa@redhat.com>
Date: Wed, 15 Nov 2017 13:15:57 +0100
Subject: [PATCH] qemu: Move snapshot disk validation functions into one
Move the code so that both the new image and old image can be verified
in the same function.
(cherry picked from commit 8ffdeed455650557df531aafc66c20b31bd4e0c4)
---
src/qemu/qemu_driver.c | 91 ++++++++++++++++++++------------------------------
1 file changed, 36 insertions(+), 55 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 1f9264639..57f0c2bf4 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -13793,17 +13793,19 @@ qemuDomainSnapshotCreateActiveInternal(virConnectPtr conn,
static int
-qemuDomainSnapshotPrepareDiskExternalBackingInactive(virDomainDiskDefPtr disk)
+qemuDomainSnapshotPrepareDiskExternalInactive(virDomainSnapshotDiskDefPtr snapdisk,
+ virDomainDiskDefPtr domdisk)
{
- int actualType = virStorageSourceGetActualType(disk->src);
+ int domDiskType = virStorageSourceGetActualType(domdisk->src);
+ int snapDiskType = virStorageSourceGetActualType(snapdisk->src);
- switch ((virStorageType) actualType) {
+ switch ((virStorageType) domDiskType) {
case VIR_STORAGE_TYPE_BLOCK:
case VIR_STORAGE_TYPE_FILE:
- return 0;
+ break;
case VIR_STORAGE_TYPE_NETWORK:
- switch ((virStorageNetProtocol) disk->src->protocol) {
+ switch ((virStorageNetProtocol) domdisk->src->protocol) {
case VIR_STORAGE_NET_PROTOCOL_NONE:
case VIR_STORAGE_NET_PROTOCOL_NBD:
case VIR_STORAGE_NET_PROTOCOL_RBD:
@@ -13820,7 +13822,7 @@ qemuDomainSnapshotPrepareDiskExternalBackingInactive(virDomainDiskDefPtr disk)
virReportError(VIR_ERR_INTERNAL_ERROR,
_("external inactive snapshots are not supported on "
"'network' disks using '%s' protocol"),
- virStorageNetProtocolTypeToString(disk->src->protocol));
+ virStorageNetProtocolTypeToString(domdisk->src->protocol));
return -1;
}
break;
@@ -13831,7 +13833,23 @@ qemuDomainSnapshotPrepareDiskExternalBackingInactive(virDomainDiskDefPtr disk)
case VIR_STORAGE_TYPE_LAST:
virReportError(VIR_ERR_INTERNAL_ERROR,
_("external inactive snapshots are not supported on "
- "'%s' disks"), virStorageTypeToString(actualType));
+ "'%s' disks"), virStorageTypeToString(domDiskType));
+ return -1;
+ }
+
+ switch ((virStorageType) snapDiskType) {
+ case VIR_STORAGE_TYPE_BLOCK:
+ case VIR_STORAGE_TYPE_FILE:
+ break;
+
+ case VIR_STORAGE_TYPE_NETWORK:
+ case VIR_STORAGE_TYPE_DIR:
+ case VIR_STORAGE_TYPE_VOLUME:
+ case VIR_STORAGE_TYPE_NONE:
+ case VIR_STORAGE_TYPE_LAST:
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("external inactive snapshots are not supported on "
+ "'%s' disks"), virStorageTypeToString(snapDiskType));
return -1;
}
@@ -13840,33 +13858,27 @@ qemuDomainSnapshotPrepareDiskExternalBackingInactive(virDomainDiskDefPtr disk)
static int
-qemuDomainSnapshotPrepareDiskExternalBackingActive(virDomainDiskDefPtr disk)
+qemuDomainSnapshotPrepareDiskExternalActive(virDomainSnapshotDiskDefPtr snapdisk,
+ virDomainDiskDefPtr domdisk)
{
- if (disk->device == VIR_DOMAIN_DISK_DEVICE_LUN) {
+ int actualType = virStorageSourceGetActualType(snapdisk->src);
+
+ if (domdisk->device == VIR_DOMAIN_DISK_DEVICE_LUN) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("external active snapshots are not supported on scsi "
"passthrough devices"));
return -1;
}
- return 0;
-}
-
-
-static int
-qemuDomainSnapshotPrepareDiskExternalOverlayActive(virDomainSnapshotDiskDefPtr disk)
-{
- int actualType = virStorageSourceGetActualType(disk->src);
-
switch ((virStorageType) actualType) {
case VIR_STORAGE_TYPE_BLOCK:
case VIR_STORAGE_TYPE_FILE:
- return 0;
+ break;
case VIR_STORAGE_TYPE_NETWORK:
- switch ((virStorageNetProtocol) disk->src->protocol) {
+ switch ((virStorageNetProtocol) snapdisk->src->protocol) {
case VIR_STORAGE_NET_PROTOCOL_GLUSTER:
- return 0;
+ break;
case VIR_STORAGE_NET_PROTOCOL_NONE:
case VIR_STORAGE_NET_PROTOCOL_NBD:
@@ -13883,7 +13895,7 @@ qemuDomainSnapshotPrepareDiskExternalOverlayActive(virDomainSnapshotDiskDefPtr d
virReportError(VIR_ERR_INTERNAL_ERROR,
_("external active snapshots are not supported on "
"'network' disks using '%s' protocol"),
- virStorageNetProtocolTypeToString(disk->src->protocol));
+ virStorageNetProtocolTypeToString(snapdisk->src->protocol));
return -1;
}
@@ -13903,31 +13915,6 @@ qemuDomainSnapshotPrepareDiskExternalOverlayActive(virDomainSnapshotDiskDefPtr d
}
-static int
-qemuDomainSnapshotPrepareDiskExternalOverlayInactive(virDomainSnapshotDiskDefPtr disk)
-{
- int actualType = virStorageSourceGetActualType(disk->src);
-
- switch ((virStorageType) actualType) {
- case VIR_STORAGE_TYPE_BLOCK:
- case VIR_STORAGE_TYPE_FILE:
- return 0;
-
- case VIR_STORAGE_TYPE_NETWORK:
- case VIR_STORAGE_TYPE_DIR:
- case VIR_STORAGE_TYPE_VOLUME:
- case VIR_STORAGE_TYPE_NONE:
- case VIR_STORAGE_TYPE_LAST:
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("external inactive snapshots are not supported on "
- "'%s' disks"), virStorageTypeToString(actualType));
- return -1;
- }
-
- return 0;
-}
-
-
static int
qemuDomainSnapshotPrepareDiskExternal(virConnectPtr conn,
virDomainDiskDefPtr disk,
@@ -13945,16 +13932,10 @@ qemuDomainSnapshotPrepareDiskExternal(virConnectPtr conn,
if (virStorageTranslateDiskSourcePool(conn, disk) < 0)
return -1;
- if (qemuDomainSnapshotPrepareDiskExternalBackingInactive(disk) < 0)
- return -1;
-
- if (qemuDomainSnapshotPrepareDiskExternalOverlayInactive(snapdisk) < 0)
+ if (qemuDomainSnapshotPrepareDiskExternalInactive(snapdisk, disk) < 0)
return -1;
} else {
- if (qemuDomainSnapshotPrepareDiskExternalBackingActive(disk) < 0)
- return -1;
-
- if (qemuDomainSnapshotPrepareDiskExternalOverlayActive(snapdisk) < 0)
+ if (qemuDomainSnapshotPrepareDiskExternalActive(snapdisk, disk) < 0)
return -1;
}
@@ -1,55 +0,0 @@
From: Peter Krempa <pkrempa@redhat.com>
Date: Tue, 14 Nov 2017 15:34:46 +0100
Subject: [PATCH] qemu: block: Add function to check if storage source allows
concurrent access
Storage source format backing a shared device (e.g. running a cluster
filesystem) needs to support the sharing so that metadata are not
corrupted. Add a central function for checking this.
(cherry picked from commit 1fc3cd8731640aefc48bbd9fc489f21cb99c6f67)
---
src/qemu/qemu_block.c | 15 +++++++++++++++
src/qemu/qemu_block.h | 3 +++
2 files changed, 18 insertions(+)
diff --git a/src/qemu/qemu_block.c b/src/qemu/qemu_block.c
index 7fb12ea5a..4c0a5eb78 100644
--- a/src/qemu/qemu_block.c
+++ b/src/qemu/qemu_block.c
@@ -379,6 +379,21 @@ qemuBlockGetNodeData(virJSONValuePtr data)
}
+/**
+ * qemuBlockStorageSourceSupportsConcurrentAccess:
+ * @src: disk storage source
+ *
+ * Returns true if the given storage format supports concurrent access from two
+ * separate processes.
+ */
+bool
+qemuBlockStorageSourceSupportsConcurrentAccess(virStorageSourcePtr src)
+{
+ /* no need to check in backing chain since only RAW storage supports this */
+ return src->format == VIR_STORAGE_FILE_RAW;
+}
+
+
/**
* qemuBlockStorageSourceBuildHostsJSONSocketAddress:
* @src: disk storage source
diff --git a/src/qemu/qemu_block.h b/src/qemu/qemu_block.h
index f0a2c9aa7..ebf3149ce 100644
--- a/src/qemu/qemu_block.h
+++ b/src/qemu/qemu_block.h
@@ -53,6 +53,9 @@ qemuBlockNodeNamesDetect(virQEMUDriverPtr driver,
virHashTablePtr
qemuBlockGetNodeData(virJSONValuePtr data);
+bool
+qemuBlockStorageSourceSupportsConcurrentAccess(virStorageSourcePtr src);
+
virJSONValuePtr
qemuBlockStorageSourceGetBackendProps(virStorageSourcePtr src);
@@ -1,146 +0,0 @@
From: Peter Krempa <pkrempa@redhat.com>
Date: Tue, 14 Nov 2017 15:37:09 +0100
Subject: [PATCH] qemu: domain: Reject shared disk access if backing format
does not support it
Disk sharing between two VMs may corrupt the images if the format driver
does not support it. Check that the user declared use of a supported
storage format when they want to share the disk.
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1511480
(cherry picked from commit 3b03a27cd00c2f032661d2bf8905795425752fc7)
---
src/qemu/qemu_domain.c | 29 +++++++++++++++++++++-
.../qemuxml2argv-disk-drive-shared-qcow.xml | 28 +++++++++++++++++++++
.../qemuxml2argv-disk-drive-shared.args | 2 +-
.../qemuxml2argv-disk-drive-shared.xml | 2 +-
tests/qemuxml2argvtest.c | 1 +
5 files changed, 59 insertions(+), 3 deletions(-)
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-disk-drive-shared-qcow.xml
diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
index b98ffffae..42d17c1b0 100644
--- a/src/qemu/qemu_domain.c
+++ b/src/qemu/qemu_domain.c
@@ -25,6 +25,7 @@
#include "qemu_domain.h"
#include "qemu_alias.h"
+#include "qemu_block.h"
#include "qemu_cgroup.h"
#include "qemu_command.h"
#include "qemu_process.h"
@@ -3299,6 +3300,29 @@ qemuDomainRedirdevDefValidate(const virDomainRedirdevDef *def)
}
+static int
+qemuDomainDeviceDefValidateDisk(const virDomainDiskDef *disk)
+{
+ if (disk->src->shared && !disk->src->readonly) {
+ if (disk->src->format <= VIR_STORAGE_FILE_AUTO) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("shared access for disk '%s' requires use of "
+ "explicitly specified disk format"), disk->dst);
+ return -1;
+ }
+
+ if (!qemuBlockStorageSourceSupportsConcurrentAccess(disk->src)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("shared access for disk '%s' requires use of "
+ "supported storage format"), disk->dst);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+
static int
qemuDomainDeviceDefValidate(const virDomainDeviceDef *dev,
const virDomainDef *def ATTRIBUTE_UNUSED,
@@ -3308,7 +3332,10 @@ qemuDomainDeviceDefValidate(const virDomainDeviceDef *dev,
virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
int ret = -1;
- if (dev->type == VIR_DOMAIN_DEVICE_NET) {
+ if (dev->type == VIR_DOMAIN_DEVICE_DISK) {
+ if (qemuDomainDeviceDefValidateDisk(dev->data.disk) < 0)
+ goto cleanup;
+ } else if (dev->type == VIR_DOMAIN_DEVICE_NET) {
const virDomainNetDef *net = dev->data.net;
if (net->guestIP.nroutes || net->guestIP.nips) {
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-shared-qcow.xml b/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-shared-qcow.xml
new file mode 100644
index 000000000..ca88a944b
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-shared-qcow.xml
@@ -0,0 +1,28 @@
+<domain type='qemu'>
+ <name>QEMUGuest1</name>
+ <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+ <memory unit='KiB'>219136</memory>
+ <currentMemory unit='KiB'>219136</currentMemory>
+ <vcpu placement='static'>1</vcpu>
+ <os>
+ <type arch='i686' machine='pc'>hvm</type>
+ <boot dev='hd'/>
+ </os>
+ <clock offset='utc'/>
+ <on_poweroff>destroy</on_poweroff>
+ <on_reboot>restart</on_reboot>
+ <on_crash>destroy</on_crash>
+ <devices>
+ <emulator>/usr/bin/qemu-system-i686</emulator>
+ <disk type='block' device='disk'>
+ <driver name='qemu' type='qcow2'/>
+ <source dev='/dev/HostVG/QEMUGuest1'/>
+ <target dev='hda' bus='ide'/>
+ <shareable/>
+ <address type='drive' controller='0' bus='0' target='0' unit='0'/>
+ </disk>
+ <controller type='usb' index='0'/>
+ <controller type='ide' index='0'/>
+ <memballoon model='virtio'/>
+ </devices>
+</domain>
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-shared.args b/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-shared.args
index 502157bf8..326fde1b3 100644
--- a/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-shared.args
+++ b/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-shared.args
@@ -19,7 +19,7 @@ server,nowait \
-no-acpi \
-boot c \
-usb \
--drive file=/dev/HostVG/QEMUGuest1,format=qcow2,if=none,id=drive-ide0-0-0,\
+-drive file=/dev/HostVG/QEMUGuest1,format=raw,if=none,id=drive-ide0-0-0,\
serial=XYZXYZXYZYXXYZYZYXYZY,cache=none \
-device ide-drive,bus=ide.0,unit=0,drive=drive-ide0-0-0,id=ide0-0-0 \
-drive file=/dev/HostVG/QEMUGuest2,format=raw,if=none,media=cdrom,\
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-shared.xml b/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-shared.xml
index 9f7472378..677c2b0b7 100644
--- a/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-shared.xml
+++ b/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-shared.xml
@@ -15,7 +15,7 @@
<devices>
<emulator>/usr/bin/qemu-system-i686</emulator>
<disk type='block' device='disk'>
- <driver name='qemu' type='qcow2'/>
+ <driver name='qemu' type='raw'/>
<source dev='/dev/HostVG/QEMUGuest1'/>
<target dev='hda' bus='ide'/>
<shareable/>
diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c
index 18f06e5aa..93f892229 100644
--- a/tests/qemuxml2argvtest.c
+++ b/tests/qemuxml2argvtest.c
@@ -895,6 +895,7 @@ mymain(void)
QEMU_CAPS_DRIVE_BOOT);
DO_TEST("disk-drive-shared",
QEMU_CAPS_DRIVE_SERIAL);
+ DO_TEST_PARSE_ERROR("disk-drive-shared-qcow", NONE);
DO_TEST("disk-drive-error-policy-stop",
QEMU_CAPS_MONITOR_JSON);
DO_TEST("disk-drive-error-policy-enospace",
@@ -1,63 +0,0 @@
From: Peter Krempa <pkrempa@redhat.com>
Date: Wed, 15 Nov 2017 13:41:01 +0100
Subject: [PATCH] qemu: snapshot: Disallow snapshot of unsupported shared disks
Creating a snapshot would introduce a possibly unsupported member for
sharing into the backing chain. Add a check to prevent that from
happening.
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1511480
(cherry picked from commit 9b2fbfa6f6b535b9f41a7503531d43d86d7a8868)
---
src/qemu/qemu_driver.c | 24 ++++++++++++++++++++++++
1 file changed, 24 insertions(+)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 57f0c2bf4..91119a494 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -13792,6 +13792,24 @@ qemuDomainSnapshotCreateActiveInternal(virConnectPtr conn,
}
+static int
+qemuDomainSnapshotPrepareDiskShared(virDomainSnapshotDiskDefPtr snapdisk,
+ virDomainDiskDefPtr domdisk)
+{
+ if (!domdisk->src->shared || domdisk->src->readonly)
+ return 0;
+
+ if (!qemuBlockStorageSourceSupportsConcurrentAccess(snapdisk->src)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("shared access for disk '%s' requires use of "
+ "supported storage format"), domdisk->dst);
+ return -1;
+ }
+
+ return 0;
+}
+
+
static int
qemuDomainSnapshotPrepareDiskExternalInactive(virDomainSnapshotDiskDefPtr snapdisk,
virDomainDiskDefPtr domdisk)
@@ -13853,6 +13871,9 @@ qemuDomainSnapshotPrepareDiskExternalInactive(virDomainSnapshotDiskDefPtr snapdi
return -1;
}
+ if (qemuDomainSnapshotPrepareDiskShared(snapdisk, domdisk) < 0)
+ return -1;
+
return 0;
}
@@ -13911,6 +13932,9 @@ qemuDomainSnapshotPrepareDiskExternalActive(virDomainSnapshotDiskDefPtr snapdisk
return -1;
}
+ if (qemuDomainSnapshotPrepareDiskShared(snapdisk, domdisk) < 0)
+ return -1;
+
return 0;
}
@@ -1,34 +0,0 @@
From: Peter Krempa <pkrempa@redhat.com>
Date: Wed, 15 Nov 2017 14:33:11 +0100
Subject: [PATCH] qemu: Disallow pivot of shared disks to unsupported storage
Pivoting to a unsupported storage type might break the assumption that
shared disks will not corrupt metadata.
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1511480
(cherry picked from commit 2b41c86294786c07f53afa633fe3dce703debc3c)
---
src/qemu/qemu_driver.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 91119a494..208ccc9bc 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -16325,6 +16325,16 @@ qemuDomainBlockPivot(virQEMUDriverPtr driver,
goto cleanup;
}
+ /* When pivoting to a shareable disk we need to make sure that the disk can
+ * be safely shared, since block copy might have changed the format. */
+ if (disk->src->shared && !disk->src->readonly &&
+ !qemuBlockStorageSourceSupportsConcurrentAccess(disk->mirror)) {
+ virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
+ _("can't pivot a shared disk to a storage volume not "
+ "supporting sharing"));
+ goto cleanup;
+ }
+
/* For active commit, the mirror is part of the already labeled
* chain. For blockcopy, we previously labeled only the top-level
* image; but if the user is reusing an external image that
@@ -1,126 +0,0 @@
From: Peter Krempa <pkrempa@redhat.com>
Date: Wed, 15 Nov 2017 15:02:58 +0100
Subject: [PATCH] qemu: caps: Add capability for 'share-rw' disk option
'share-rw' for the disk device configures qemu to allow concurrent
access to the backing storage.
The capability is checked in various supported disk frontend buses since
it does not make sense to partially backport it.
(cherry picked from commit 860a3c4bea1d24773d8a495f213d5de3ac48a462)
---
src/qemu/qemu_capabilities.c | 14 ++++++++++++++
src/qemu/qemu_capabilities.h | 10 ++++++++++
tests/qemucapabilitiesdata/caps_2.9.0.ppc64le.xml | 1 +
tests/qemucapabilitiesdata/caps_2.9.0.s390x.xml | 1 +
tests/qemucapabilitiesdata/caps_2.9.0.x86_64.xml | 1 +
5 files changed, 27 insertions(+)
diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c
index e7ea6f47c..2de84715e 100644
--- a/src/qemu/qemu_capabilities.c
+++ b/src/qemu/qemu_capabilities.c
@@ -439,6 +439,16 @@ VIR_ENUM_IMPL(virQEMUCaps, QEMU_CAPS_LAST,
"virtio-net.tx_queue_size",
"chardev-reconnect",
"virtio-gpu.max_outputs",
+
+ /* 270 */
+ "vxhs",
+ "virtio-blk.num-queues",
+ "machine.pseries.resize-hpt",
+ "vmcoreinfo",
+ "spapr-vty",
+
+ /* 275 */
+ "disk-share-rw",
);
@@ -1702,6 +1712,7 @@ static struct virQEMUCapsStringFlags virQEMUCapsObjectPropsVirtioBlk[] = {
{ "event_idx", QEMU_CAPS_VIRTIO_BLK_EVENT_IDX },
{ "scsi", QEMU_CAPS_VIRTIO_BLK_SCSI },
{ "logical_block_size", QEMU_CAPS_BLOCKIO },
+ { "share-rw", QEMU_CAPS_DISK_SHARE_RW },
};
static struct virQEMUCapsStringFlags virQEMUCapsObjectPropsVirtioNet[] = {
@@ -1732,10 +1743,12 @@ static struct virQEMUCapsStringFlags virQEMUCapsObjectPropsVfioPCI[] = {
static struct virQEMUCapsStringFlags virQEMUCapsObjectPropsSCSIDisk[] = {
{ "channel", QEMU_CAPS_SCSI_DISK_CHANNEL },
{ "wwn", QEMU_CAPS_SCSI_DISK_WWN },
+ { "share-rw", QEMU_CAPS_DISK_SHARE_RW },
};
static struct virQEMUCapsStringFlags virQEMUCapsObjectPropsIDEDrive[] = {
{ "wwn", QEMU_CAPS_IDE_DRIVE_WWN },
+ { "share-rw", QEMU_CAPS_DISK_SHARE_RW },
};
static struct virQEMUCapsStringFlags virQEMUCapsObjectPropsPiix4PM[] = {
@@ -1766,6 +1779,7 @@ static struct virQEMUCapsStringFlags virQEMUCapsObjectPropsQ35PCIHost[] = {
static struct virQEMUCapsStringFlags virQEMUCapsObjectPropsUSBStorage[] = {
{ "removable", QEMU_CAPS_USB_STORAGE_REMOVABLE },
+ { "share-rw", QEMU_CAPS_DISK_SHARE_RW },
};
static struct virQEMUCapsStringFlags virQEMUCapsObjectPropsKVMPit[] = {
diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h
index f32687d4a..9c92d6b46 100644
--- a/src/qemu/qemu_capabilities.h
+++ b/src/qemu/qemu_capabilities.h
@@ -426,6 +426,16 @@ typedef enum {
QEMU_CAPS_CHARDEV_RECONNECT, /* -chardev reconnect */
QEMU_CAPS_VIRTIO_GPU_MAX_OUTPUTS, /* -device virtio-(vga|gpu-*),max-outputs= */
+ /* 270 */
+ QEMU_CAPS_VXHS, /* -drive file.driver=vxhs via query-qmp-schema */
+ QEMU_CAPS_VIRTIO_BLK_NUM_QUEUES, /* virtio-blk-*.num-queues */
+ QEMU_CAPS_MACHINE_PSERIES_RESIZE_HPT, /* -machine pseries,resize-hpt */
+ QEMU_CAPS_DEVICE_VMCOREINFO, /* -device vmcoreinfo */
+ QEMU_CAPS_DEVICE_SPAPR_VTY, /* -device spapr-vty */
+
+ /* 275 */
+ QEMU_CAPS_DISK_SHARE_RW, /* share-rw=on for concurrent disk access */
+
QEMU_CAPS_LAST /* this must always be the last item */
} virQEMUCapsFlags;
diff --git a/tests/qemucapabilitiesdata/caps_2.9.0.ppc64le.xml b/tests/qemucapabilitiesdata/caps_2.9.0.ppc64le.xml
index a373a6db6..9551907c6 100644
--- a/tests/qemucapabilitiesdata/caps_2.9.0.ppc64le.xml
+++ b/tests/qemucapabilitiesdata/caps_2.9.0.ppc64le.xml
@@ -172,6 +172,7 @@
<flag name='vnc-multi-servers'/>
<flag name='chardev-reconnect'/>
<flag name='virtio-gpu.max_outputs'/>
+ <flag name='disk-share-rw'/>
<version>2009000</version>
<kvmVersion>0</kvmVersion>
<package> (v2.9.0)</package>
diff --git a/tests/qemucapabilitiesdata/caps_2.9.0.s390x.xml b/tests/qemucapabilitiesdata/caps_2.9.0.s390x.xml
index e80782cfb..0a6fbd077 100644
--- a/tests/qemucapabilitiesdata/caps_2.9.0.s390x.xml
+++ b/tests/qemucapabilitiesdata/caps_2.9.0.s390x.xml
@@ -137,6 +137,7 @@
<flag name='vnc-multi-servers'/>
<flag name='chardev-reconnect'/>
<flag name='virtio-gpu.max_outputs'/>
+ <flag name='disk-share-rw'/>
<version>2009000</version>
<kvmVersion>0</kvmVersion>
<package></package>
diff --git a/tests/qemucapabilitiesdata/caps_2.9.0.x86_64.xml b/tests/qemucapabilitiesdata/caps_2.9.0.x86_64.xml
index 3641d0332..1294ebdb3 100644
--- a/tests/qemucapabilitiesdata/caps_2.9.0.x86_64.xml
+++ b/tests/qemucapabilitiesdata/caps_2.9.0.x86_64.xml
@@ -220,6 +220,7 @@
<flag name='vnc-multi-servers'/>
<flag name='chardev-reconnect'/>
<flag name='virtio-gpu.max_outputs'/>
+ <flag name='disk-share-rw'/>
<version>2009000</version>
<kvmVersion>0</kvmVersion>
<package> (v2.9.0)</package>
@@ -1,133 +0,0 @@
From: Peter Krempa <pkrempa@redhat.com>
Date: Wed, 15 Nov 2017 15:21:14 +0100
Subject: [PATCH] qemu: command: Mark <shared/> disks as such in qemu
Qemu has now an internal mechanism for locking images to fix specific
cases of disk corruption. This requires libvirt to mark the image as
shared so that qemu lifts certain restrictions.
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1378242
(cherry picked from commit 28907b0043fbf71085a798372ab9c816ba043b93)
---
src/qemu/qemu_command.c | 4 +++
.../qemuxml2argv-disk-drive-shared-locking.args | 32 +++++++++++++++++
.../qemuxml2argv-disk-drive-shared-locking.xml | 42 ++++++++++++++++++++++
tests/qemuxml2argvtest.c | 2 ++
4 files changed, 80 insertions(+)
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-disk-drive-shared-locking.args
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-disk-drive-shared-locking.xml
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index ae78cd17e..883525752 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -2075,6 +2075,10 @@ qemuBuildDriveDevStr(const virDomainDef *def,
goto error;
}
+ if (disk->src->shared &&
+ virQEMUCapsGet(qemuCaps, QEMU_CAPS_DISK_SHARE_RW))
+ virBufferAddLit(&opt, ",share-rw=on");
+
if (!(drivealias = qemuAliasFromDisk(disk)))
goto error;
virBufferAsprintf(&opt, ",drive=%s,id=%s", drivealias, disk->info.alias);
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-shared-locking.args b/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-shared-locking.args
new file mode 100644
index 000000000..cdf17f26d
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-shared-locking.args
@@ -0,0 +1,32 @@
+LC_ALL=C \
+PATH=/bin \
+HOME=/home/test \
+USER=test \
+LOGNAME=test \
+QEMU_AUDIO_DRV=none \
+/usr/bin/qemu-system-i686 \
+-name QEMUGuest1 \
+-S \
+-M pc \
+-m 214 \
+-smp 1,sockets=1,cores=1,threads=1 \
+-uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 \
+-nographic \
+-nodefaults \
+-chardev socket,id=charmonitor,path=/tmp/lib/domain--1-QEMUGuest1/monitor.sock,\
+server,nowait \
+-mon chardev=charmonitor,id=monitor,mode=readline \
+-no-acpi \
+-boot c \
+-device virtio-scsi-pci,id=scsi0,bus=pci.0,addr=0x3 \
+-usb \
+-drive file=/dev/ide,format=raw,if=none,id=drive-ide0-0-0,cache=none \
+-device ide-drive,bus=ide.0,unit=0,share-rw=on,drive=drive-ide0-0-0,\
+id=ide0-0-0 \
+-drive file=/dev/scsi,format=raw,if=none,id=drive-scsi0-0-0-0,cache=none \
+-device scsi-disk,bus=scsi0.0,channel=0,scsi-id=0,lun=0,share-rw=on,\
+drive=drive-scsi0-0-0-0,id=scsi0-0-0-0 \
+-drive file=/dev/virtio,format=raw,if=none,id=drive-virtio-disk0,cache=none \
+-device virtio-blk-pci,bus=pci.0,addr=0x4,share-rw=on,drive=drive-virtio-disk0,\
+id=virtio-disk0 \
+-device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x5
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-shared-locking.xml b/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-shared-locking.xml
new file mode 100644
index 000000000..dd48857a3
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-shared-locking.xml
@@ -0,0 +1,42 @@
+<domain type='qemu'>
+ <name>QEMUGuest1</name>
+ <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+ <memory unit='KiB'>219136</memory>
+ <currentMemory unit='KiB'>219136</currentMemory>
+ <vcpu placement='static'>1</vcpu>
+ <os>
+ <type arch='i686' machine='pc'>hvm</type>
+ <boot dev='hd'/>
+ </os>
+ <clock offset='utc'/>
+ <on_poweroff>destroy</on_poweroff>
+ <on_reboot>restart</on_reboot>
+ <on_crash>destroy</on_crash>
+ <devices>
+ <emulator>/usr/bin/qemu-system-i686</emulator>
+ <disk type='block' device='disk'>
+ <driver name='qemu' type='raw'/>
+ <source dev='/dev/ide'/>
+ <target dev='hda' bus='ide'/>
+ <shareable/>
+ <address type='drive' controller='0' bus='0' target='0' unit='0'/>
+ </disk>
+ <disk type='block' device='disk'>
+ <driver name='qemu' type='raw'/>
+ <source dev='/dev/scsi'/>
+ <target dev='sda' bus='scsi'/>
+ <shareable/>
+ <address type='drive' controller='0' bus='0' target='0' unit='0'/>
+ </disk>
+ <disk type='block' device='disk'>
+ <driver name='qemu' type='raw'/>
+ <source dev='/dev/virtio'/>
+ <target dev='vda' bus='virtio'/>
+ <shareable/>
+ </disk>
+ <controller type='usb' index='0'/>
+ <controller type='ide' index='0'/>
+ <controller type='scsi' index='0' model='virtio-scsi'/>
+ <memballoon model='virtio'/>
+ </devices>
+</domain>
diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c
index 93f892229..9585fdb70 100644
--- a/tests/qemuxml2argvtest.c
+++ b/tests/qemuxml2argvtest.c
@@ -896,6 +896,8 @@ mymain(void)
DO_TEST("disk-drive-shared",
QEMU_CAPS_DRIVE_SERIAL);
DO_TEST_PARSE_ERROR("disk-drive-shared-qcow", NONE);
+ DO_TEST("disk-drive-shared-locking",
+ QEMU_CAPS_VIRTIO_SCSI, QEMU_CAPS_DISK_SHARE_RW);
DO_TEST("disk-drive-error-policy-stop",
QEMU_CAPS_MONITOR_JSON);
DO_TEST("disk-drive-error-policy-enospace",
@@ -1,36 +0,0 @@
From: Peter Krempa <pkrempa@redhat.com>
Date: Wed, 20 Dec 2017 12:58:36 +0100
Subject: [PATCH] util: probe: Add quiet versions of the "PROBE" macro
PROBE macro adds a logging entry, when used in places seeing a lot of
traffic this can cause a significant slowdown.
(cherry picked from commit f06e488d5484031a76e7ed231c8fef8fa1181d2c)
---
src/util/virprobe.h | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/src/util/virprobe.h b/src/util/virprobe.h
index 7565954af..bd8c32964 100644
--- a/src/util/virprobe.h
+++ b/src/util/virprobe.h
@@ -90,11 +90,19 @@
PROBE_EXPAND(LIBVIRT_ ## NAME, \
VIR_ADD_CASTS(__VA_ARGS__)); \
}
+
+# define PROBE_QUIET(NAME, FMT, ...) \
+ if (LIBVIRT_ ## NAME ## _ENABLED()) { \
+ PROBE_EXPAND(LIBVIRT_ ## NAME, \
+ VIR_ADD_CASTS(__VA_ARGS__)); \
+ }
# else
# define PROBE(NAME, FMT, ...) \
VIR_INFO_INT(&virLogSelf, \
__FILE__, __LINE__, __func__, \
#NAME ": " FMT, __VA_ARGS__);
+
+# define PROBE_QUIET(NAME, FMT, ...)
# endif
#endif /* __VIR_PROBE_H__ */
@@ -1,49 +0,0 @@
From: Peter Krempa <pkrempa@redhat.com>
Date: Wed, 20 Dec 2017 13:09:07 +0100
Subject: [PATCH] qemu: monitor: Decrease logging verbosity
The PROBE macro used in qemuMonitorIOProcess and the VIR_DEBUG message
in qemuMonitorJSONIOProcess create a lot of logging churn when debug
logging is enabled during monitor communication.
The messages logged from the PROBE macro are rather useless since they
are reporting the partial state of receiving the reply from qemu. The
actual full reply is still logged in qemuMonitorJSONIOProcessLine once
the full message is received.
(cherry picked from commit f10bb3347b43d900ff361cda5fe1996782284991)
---
src/qemu/qemu_monitor.c | 4 ++--
src/qemu/qemu_monitor_json.c | 3 +++
2 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index 19082d8bf..3def28852 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -434,8 +434,8 @@ qemuMonitorIOProcess(qemuMonitorPtr mon)
# endif
#endif
- PROBE(QEMU_MONITOR_IO_PROCESS,
- "mon=%p buf=%s len=%zu", mon, mon->buffer, mon->bufferOffset);
+ PROBE_QUIET(QEMU_MONITOR_IO_PROCESS, "mon=%p buf=%s len=%zu",
+ mon, mon->buffer, mon->bufferOffset);
if (mon->json)
len = qemuMonitorJSONIOProcess(mon,
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index df5fb7c8f..461aae089 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -259,7 +259,10 @@ int qemuMonitorJSONIOProcess(qemuMonitorPtr mon,
}
}
+#if DEBUG_IO
VIR_DEBUG("Total used %d bytes out of %zd available in buffer", used, len);
+#endif
+
return used;
}
@@ -1,63 +0,0 @@
From: Lubomir Rintel <lkundrak@v3.sk>
Date: Sat, 27 Jan 2018 23:43:58 +0100
Subject: [PATCH] virlog: determine the hostname on startup CVE-2018-6764
At later point it might not be possible or even safe to use getaddrinfo(). It
can in turn result in a load of NSS module.
Notably, on a LXC container startup we may find ourselves with the guest
filesystem already having replaced the host one. Loading a NSS module
from the guest tree would allow a malicous guest to escape the
confinement of its container environment because libvirt will not yet
have locked it down.
(cherry picked from commit 759b4d1b0fe5f4d84d98b99153dfa7ac289dd167)
---
src/util/virlog.c | 14 +++++++++-----
1 file changed, 9 insertions(+), 5 deletions(-)
diff --git a/src/util/virlog.c b/src/util/virlog.c
index d45a451a7..05e0e199e 100644
--- a/src/util/virlog.c
+++ b/src/util/virlog.c
@@ -64,6 +64,7 @@
VIR_LOG_INIT("util.log");
static regex_t *virLogRegex;
+static char *virLogHostname;
#define VIR_LOG_DATE_REGEX "[0-9]{4}-[0-9]{2}-[0-9]{2}"
@@ -271,6 +272,12 @@ virLogOnceInit(void)
VIR_FREE(virLogRegex);
}
+ /* We get and remember the hostname early, because at later time
+ * it might not be possible to load NSS modules via getaddrinfo()
+ * (e.g. at container startup the host filesystem will not be
+ * accessible anymore. */
+ virLogHostname = virGetHostnameQuiet();
+
virLogUnlock();
return 0;
}
@@ -466,17 +473,14 @@ static int
virLogHostnameString(char **rawmsg,
char **msg)
{
- char *hostname = virGetHostnameQuiet();
char *hoststr;
- if (!hostname)
+ if (!virLogHostname)
return -1;
- if (virAsprintfQuiet(&hoststr, "hostname: %s", hostname) < 0) {
- VIR_FREE(hostname);
+ if (virAsprintfQuiet(&hoststr, "hostname: %s", virLogHostname) < 0) {
return -1;
}
- VIR_FREE(hostname);
if (virLogFormatString(msg, 0, NULL, VIR_LOG_INFO, hoststr) < 0) {
VIR_FREE(hoststr);
-27
View File
@@ -1,27 +0,0 @@
From: Andrea Bolognani <abologna@redhat.com>
Date: Wed, 7 Feb 2018 14:39:18 +0100
Subject: [PATCH] util: Fix syntax-check
Broken by 759b4d1b0fe5f4d84d98b99153dfa7ac289dd167.
Signed-off-by: Andrea Bolognani <abologna@redhat.com>
(cherry picked from commit 6ce3acc129bfdbe7fd02bcb8bbe8af6d13903684)
---
src/util/virlog.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/src/util/virlog.c b/src/util/virlog.c
index 05e0e199e..056b53cda 100644
--- a/src/util/virlog.c
+++ b/src/util/virlog.c
@@ -478,9 +478,8 @@ virLogHostnameString(char **rawmsg,
if (!virLogHostname)
return -1;
- if (virAsprintfQuiet(&hoststr, "hostname: %s", virLogHostname) < 0) {
+ if (virAsprintfQuiet(&hoststr, "hostname: %s", virLogHostname) < 0)
return -1;
- }
if (virLogFormatString(msg, 0, NULL, VIR_LOG_INFO, hoststr) < 0) {
VIR_FREE(hoststr);
@@ -1,121 +0,0 @@
From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= <berrange@redhat.com>
Date: Mon, 12 Feb 2018 10:03:08 +0000
Subject: [PATCH] log: fix deadlock obtaining hostname (related CVE-2018-6764)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The fix for CVE-2018-6764 introduced a potential deadlock scenario
that gets triggered by the NSS module when virGetHostname() calls
getaddrinfo to resolve the hostname:
#0 0x00007f6e714b57e7 in futex_wait
#1 futex_wait_simple
#2 __pthread_once_slow
#3 0x00007f6e71d16e7d in virOnce
#4 0x00007f6e71d0997c in virLogInitialize
#5 0x00007f6e71d0a09a in virLogVMessage
#6 0x00007f6e71d09ffd in virLogMessage
#7 0x00007f6e71d0db22 in virObjectNew
#8 0x00007f6e71d0dbf1 in virObjectLockableNew
#9 0x00007f6e71d0d3e5 in virMacMapNew
#10 0x00007f6e71cdc50a in findLease
#11 0x00007f6e71cdcc56 in _nss_libvirt_gethostbyname4_r
#12 0x00007f6e724631fc in gaih_inet
#13 0x00007f6e72464697 in __GI_getaddrinfo
#14 0x00007f6e71d19e81 in virGetHostnameImpl
#15 0x00007f6e71d1a057 in virGetHostnameQuiet
#16 0x00007f6e71d09936 in virLogOnceInit
#17 0x00007f6e71d09952 in virLogOnce
#18 0x00007f6e714b5829 in __pthread_once_slow
#19 0x00007f6e71d16e7d in virOnce
#20 0x00007f6e71d0997c in virLogInitialize
#21 0x00007f6e71d0a09a in virLogVMessage
#22 0x00007f6e71d09ffd in virLogMessage
#23 0x00007f6e71d0db22 in virObjectNew
#24 0x00007f6e71d0dbf1 in virObjectLockableNew
#25 0x00007f6e71d0d3e5 in virMacMapNew
#26 0x00007f6e71cdc50a in findLease
#27 0x00007f6e71cdc839 in _nss_libvirt_gethostbyname3_r
#28 0x00007f6e71cdc724 in _nss_libvirt_gethostbyname2_r
#29 0x00007f6e7248f72f in __gethostbyname2_r
#30 0x00007f6e7248f494 in gethostbyname2
#31 0x000056348c30c36d in hosts_keys
#32 0x000056348c30b7d2 in main
Fortunately the extra stuff virGetHostname does is totally irrelevant to
the needs of the logging code, so we can just inline a call to the
native hostname() syscall directly.
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
(cherry picked from commit c2dc6698c88fb591639e542c8ecb0076c54f3dfb)
---
cfg.mk | 2 +-
src/util/virlog.c | 20 ++++++++++++++------
2 files changed, 15 insertions(+), 7 deletions(-)
diff --git a/cfg.mk b/cfg.mk
index 56cb14bd9..a4131592c 100644
--- a/cfg.mk
+++ b/cfg.mk
@@ -1158,7 +1158,7 @@ _src2=src/(util/vircommand|libvirt|lxc/lxc_controller|locking/lock_daemon|loggin
exclude_file_name_regexp--sc_prohibit_fork_wrappers = \
(^($(_src2)|tests/testutils|daemon/libvirtd)\.c$$)
-exclude_file_name_regexp--sc_prohibit_gethostname = ^src/util/virutil\.c$$
+exclude_file_name_regexp--sc_prohibit_gethostname = ^src/util/vir(util|log)\.c$$
exclude_file_name_regexp--sc_prohibit_internal_functions = \
^src/(util/(viralloc|virutil|virfile)\.[hc]|esx/esx_vi\.c)$$
diff --git a/src/util/virlog.c b/src/util/virlog.c
index 056b53cda..f76fc2caf 100644
--- a/src/util/virlog.c
+++ b/src/util/virlog.c
@@ -64,7 +64,7 @@
VIR_LOG_INIT("util.log");
static regex_t *virLogRegex;
-static char *virLogHostname;
+static char virLogHostname[HOST_NAME_MAX+1];
#define VIR_LOG_DATE_REGEX "[0-9]{4}-[0-9]{2}-[0-9]{2}"
@@ -261,6 +261,8 @@ virLogPriorityString(virLogPriority lvl)
static int
virLogOnceInit(void)
{
+ int r;
+
if (virMutexInit(&virLogMutex) < 0)
return -1;
@@ -275,8 +277,17 @@ virLogOnceInit(void)
/* We get and remember the hostname early, because at later time
* it might not be possible to load NSS modules via getaddrinfo()
* (e.g. at container startup the host filesystem will not be
- * accessible anymore. */
- virLogHostname = virGetHostnameQuiet();
+ * accessible anymore.
+ * Must not use virGetHostname though as that causes re-entrancy
+ * problems if it triggers logging codepaths
+ */
+ r = gethostname(virLogHostname, sizeof(virLogHostname));
+ if (r == -1) {
+ ignore_value(virStrcpy(virLogHostname,
+ "(unknown)", sizeof(virLogHostname)));
+ } else {
+ NUL_TERMINATE(virLogHostname);
+ }
virLogUnlock();
return 0;
@@ -475,9 +486,6 @@ virLogHostnameString(char **rawmsg,
{
char *hoststr;
- if (!virLogHostname)
- return -1;
-
if (virAsprintfQuiet(&hoststr, "hostname: %s", virLogHostname) < 0)
return -1;
@@ -1,59 +0,0 @@
From: Michal Privoznik <mprivozn@redhat.com>
Date: Thu, 4 Jan 2018 11:11:53 +0100
Subject: [PATCH] qemuDomainAttachDeviceMknodHelper: Remove symlink before
creating it
https://bugzilla.redhat.com/show_bug.cgi?id=1528502
So imagine you have /dev/blah symlink which points to /dev/sda.
You attach /dev/blah as disk to your domain. Libvirt correctly
creates the /dev/blah -> /dev/sda symlink in the qemu namespace.
However, then you detach the disk, change the symlink so that it
points to /dev/sdb and tries to attach the disk again. This time,
however, the attach fails (well, qemu attaches wrong disk)
because the code assumes that symlinks don't change. Well they
do.
This is inspired by test fix written by Eduardo Habkost.
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
Reviewed-by: Andrea Bolognani <abologna@redhat.com>
(cherry picked from commit db98e7f67ea0d7699410f514f01947cef5128a6c)
---
src/qemu/qemu_domain.c | 22 ++++++++++++++++------
1 file changed, 16 insertions(+), 6 deletions(-)
diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
index 42d17c1b0..e0f4aaafa 100644
--- a/src/qemu/qemu_domain.c
+++ b/src/qemu/qemu_domain.c
@@ -8864,13 +8864,23 @@ qemuDomainAttachDeviceMknodHelper(pid_t pid ATTRIBUTE_UNUSED,
if (isLink) {
VIR_DEBUG("Creating symlink %s -> %s", data->file, data->target);
+
+ /* First, unlink the symlink target. Symlinks change and
+ * therefore we have no guarantees that pre-existing
+ * symlink is still valid. */
+ if (unlink(data->file) < 0 &&
+ errno != ENOENT) {
+ virReportSystemError(errno,
+ _("Unable to remove symlink %s"),
+ data->file);
+ goto cleanup;
+ }
+
if (symlink(data->target, data->file) < 0) {
- if (errno != EEXIST) {
- virReportSystemError(errno,
- _("Unable to create symlink %s"),
- data->target);
- goto cleanup;
- }
+ virReportSystemError(errno,
+ _("Unable to create symlink %s (pointing to %s)"),
+ data->file, data->target);
+ goto cleanup;
} else {
delDevice = true;
}
@@ -1,110 +0,0 @@
From ce5aebeacd10a1c15cb3ee46a59c8b5ff235589e Mon Sep 17 00:00:00 2001
Message-Id: <ce5aebeacd10a1c15cb3ee46a59c8b5ff235589e.1530632895.git.crobinso@redhat.com>
From: Laine Stump <laine@laine.org>
Date: Wed, 25 Apr 2018 17:12:03 -0400
Subject: [PATCH] nwfilter: increase pcap buffer size to be compatible with
TPACKET_V3
When an nwfilter rule sets the parameter CTRL_IP_LEARNING to "dhcp",
this turns on the "dhcpsnoop" thread, which uses libpcap to monitor
traffic on the domain's tap device and extract the IP address from the
DHCP response.
If libpcap on the host is built with HAVE_TPACKET3 defined (to enable
support for TPACKET_V3), the dhcpsnoop code's initialization of the
libpcap socket would fail with the following error:
virNWFilterSnoopDHCPOpen:1134 : internal error: pcap_setfilter: can't remove kernel filter: Bad file descriptor
It turns out that this was because TPACKET_V3 requires a larger buffer
size than libvirt was setting (we were setting it to 128k). Changing
the buffer size to 256k eliminates the error, and the dhcpsnoop thread
once again works properly.
A fuller explanation of why TPACKET_V3 requires such a large buffer,
for future git spelunkers:
libpcap calls setsockopt(... SOL_PACKET, PACKET_RX_RING...) to setup a
ring buffer for receiving packets; two of the attributes sent to this
API are called tp_frame_size, and tp_frame_nr. If libpcap was built
with HAVE_TPACKET3 defined, tp_trame_size is set to MAXIMUM_SNAPLEN
(defined in libpcap sources as 262144) and tp_frame_nr is set to:
[the buffer size we set, i.e. PCAP_BUFFERSIZE i.e. 262144] / tp_frame_size.
So if PCAP_BUFFERSIZE < MAXIMUM_SNAPLEN, then tp_frame_nr (the number
of frames in the ring buffer) is 0, which is nonsensical. This same
value is later used as a multiplier to determine the size for a call
to malloc() (which would also fail).
(NB: if HAVE_TPACKET3 is *not* defined, then tp_frame_size is set to
the snaplen set by the user (in our case 576) plus a small amount to
account for ethernet headers, so 256k is far more than adequate)
Since the TPACKET_V3 code in libpcap actually reads multiple packets
into each frame, it's not a problem to have only a single frame
(especially when we are monitoring such infrequent traffic), so it's
okay to set this relatively small buffer size (in comparison to the
default, which is 2MB), which is important since every guest using
dhcp snooping in a nwfilter rule will hold 2 of these buffers for the
entire life of the guest.
Thanks to Christian Ehrhardt for discovering that buffer size was the
problem (this was not at all obvious from the error that was logged!)
Resolves: https://bugzilla.redhat.com/1547237
Fixes: https://bugs.launchpad.net/libvirt/+bug/1758037
Signed-off-by: Laine Stump <laine@laine.org>
Reviewed-by: Christian Ehrhardt <christian.ehrhardt@canonical.com> (V1)
Reviewed-by: John Ferlan <jferlan@redhat.com>
Tested-by: Christian Ehrhardt <christian.ehrhardt@canonical.com>
Signed-off-by: Cole Robinson <crobinso@redhat.com>
---
src/nwfilter/nwfilter_dhcpsnoop.c | 22 +++++++++++++++++++---
1 file changed, 19 insertions(+), 3 deletions(-)
diff --git a/src/nwfilter/nwfilter_dhcpsnoop.c b/src/nwfilter/nwfilter_dhcpsnoop.c
index 6069e70460..50cfb944a2 100644
--- a/src/nwfilter/nwfilter_dhcpsnoop.c
+++ b/src/nwfilter/nwfilter_dhcpsnoop.c
@@ -256,10 +256,21 @@ struct _virNWFilterDHCPDecodeJob {
# define DHCP_BURST_INTERVAL_S 10 /* sec */
/*
- * libpcap 1.5 requires a 128kb buffer
- * 128 kb is bigger than (DHCP_PKT_BURST * PCAP_PBUFSIZE / 2)
+ * NB: Any libpcap built with HAVE_TPACKET3 will require
+ * PCAP_BUFFERSIZE to be at least 262144 (although
+ * pcap_set_buffer_size() with a lower value will succeed, and the
+ * error will only show up later when pcap_setfilter() is called).
+ *
+ * It is possible that in the future libpcap could increase the
+ * minimum size even further, but due to the fact that each guest
+ * using dhcp snooping keeps 2 pcap sockets open (and thus 2 buffers
+ * allocated) for the life of the guest, we want to minimize the
+ * length of the buffer, so instead of leaving it at the default size
+ * (2MB), we are setting it to the minimum viable size and including
+ * this clue in the source to help quickly resolve the problem when/if
+ * it reoccurs.
*/
-# define PCAP_BUFFERSIZE (128 * 1024)
+# define PCAP_BUFFERSIZE (256 * 1024)
# define MAX_QUEUED_JOBS (DHCP_PKT_BURST + 2 * DHCP_PKT_RATE)
@@ -1114,6 +1125,11 @@ virNWFilterSnoopDHCPOpen(const char *ifname, virMacAddr *mac,
goto cleanup_nohandle;
}
+ /* IMPORTANT: If there is any failure of *any* pcap_* function
+ * during setup of the socket, look to the comment where
+ * PCAP_BUFFERSIZE is defined. It may be too small, even if the
+ * generated error doesn't imply that.
+ */
if (pcap_set_snaplen(handle, PCAP_PBUFSIZE) < 0 ||
pcap_set_buffer_size(handle, PCAP_BUFFERSIZE) < 0 ||
pcap_activate(handle) < 0) {
--
2.17.1
@@ -1,74 +0,0 @@
From e18672ce9a5fff383992fd6e842d1cbe85c141ea Mon Sep 17 00:00:00 2001
From: Paolo Bonzini <pbonzini@redhat.com>
Date: Tue, 12 Dec 2017 16:23:40 +0100
Subject: [PATCH 10/19] util: add virFileReadHeaderQuiet wrapper around
virFileReadHeaderFD
CVE-2017-5715
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
---
src/libvirt_private.syms | 1 +
src/util/virfile.c | 19 +++++++++++++++++++
src/util/virfile.h | 2 ++
3 files changed, 22 insertions(+)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index f30a04b145..29b73fa046 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1703,6 +1703,7 @@ virFileReadAll;
virFileReadAllQuiet;
virFileReadBufQuiet;
virFileReadHeaderFD;
+virFileReadHeaderQuiet;
virFileReadLimFD;
virFileReadLink;
virFileReadValueBitmap;
diff --git a/src/util/virfile.c b/src/util/virfile.c
index 2f28e83f44..269db995ff 100644
--- a/src/util/virfile.c
+++ b/src/util/virfile.c
@@ -1356,6 +1356,25 @@ virFileReadHeaderFD(int fd, int maxlen, char **buf)
}
+int
+virFileReadHeaderQuiet(const char *path,
+ int maxlen,
+ char **buf)
+{
+ int fd;
+ int len;
+
+ fd = open(path, O_RDONLY);
+ if (fd < 0)
+ return -1;
+
+ len = virFileReadHeaderFD(fd, maxlen, buf);
+ VIR_FORCE_CLOSE(fd);
+
+ return len;
+}
+
+
/* A wrapper around saferead_lim that maps a failure due to
exceeding the maximum size limitation to EOVERFLOW. */
int
diff --git a/src/util/virfile.h b/src/util/virfile.h
index 57ceb80721..657e7216fb 100644
--- a/src/util/virfile.h
+++ b/src/util/virfile.h
@@ -129,6 +129,8 @@ int virFileDeleteTree(const char *dir);
int virFileReadHeaderFD(int fd, int maxlen, char **buf)
ATTRIBUTE_RETURN_CHECK ATTRIBUTE_NONNULL(3);
+int virFileReadHeaderQuiet(const char *path, int maxlen, char **buf)
+ ATTRIBUTE_RETURN_CHECK ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(3);
int virFileReadLimFD(int fd, int maxlen, char **buf)
ATTRIBUTE_RETURN_CHECK ATTRIBUTE_NONNULL(3);
int virFileReadAll(const char *path, int maxlen, char **buf)
--
2.17.0
@@ -1,36 +0,0 @@
From a84e70ad247da5d3ad13615efd70b91951392aa1 Mon Sep 17 00:00:00 2001
From: Jiri Denemark <jdenemar@redhat.com>
Date: Fri, 5 Jan 2018 17:43:03 +0100
Subject: [PATCH 12/19] cpu_x86: Copy CPU signature from ancestor
When specifying a new CPU model in cpu_map.xml as an extension to an
existing model, we forgot to copy the signature (family + model) from
the original CPU model.
We don't use this way of specifying CPU models, but it's still supported
and it becomes useful when someone wants to quickly hack up a CPU model
for testing or when creating additional variants of existing models to
help with fixing some spectral issues.
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
Reviewed-by: Pavel Hrdina <phrdina@redhat.com>
(cherry picked from commit b427cf4831d0ea7aac9dd1a3aa7682478356a483)
---
src/cpu/cpu_x86.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/cpu/cpu_x86.c b/src/cpu/cpu_x86.c
index 2864454211..3b7a6f95fe 100644
--- a/src/cpu/cpu_x86.c
+++ b/src/cpu/cpu_x86.c
@@ -1206,6 +1206,7 @@ x86ModelParse(xmlXPathContextPtr ctxt,
VIR_FREE(name);
model->vendor = ancestor->vendor;
+ model->signature = ancestor->signature;
if (x86DataCopy(&model->data, &ancestor->data) < 0)
goto error;
}
--
2.17.0
@@ -1,97 +0,0 @@
From de12d97c029d6644bb42afaa38410c4263bef41f Mon Sep 17 00:00:00 2001
From: Paolo Bonzini <pbonzini@redhat.com>
Date: Tue, 12 Dec 2017 16:23:41 +0100
Subject: [PATCH 13/19] util: introduce virHostCPUGetMicrocodeVersion
This new API reads host's CPU microcode version from /proc/cpuinfo.
Unfortunately, there is no other way of reading microcode version which
would be usable from both system and session daemon.
CVE-2017-5715
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
---
src/libvirt_private.syms | 1 +
src/util/virhostcpu.c | 43 ++++++++++++++++++++++++++++++++++++++++
src/util/virhostcpu.h | 2 ++
3 files changed, 46 insertions(+)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 29b73fa046..0ecd58a12c 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1811,6 +1811,7 @@ virHostCPUGetCount;
virHostCPUGetInfo;
virHostCPUGetKVMMaxVCPUs;
virHostCPUGetMap;
+virHostCPUGetMicrocodeVersion;
virHostCPUGetOnline;
virHostCPUGetOnlineBitmap;
virHostCPUGetPresentBitmap;
diff --git a/src/util/virhostcpu.c b/src/util/virhostcpu.c
index c485a97211..713fdec553 100644
--- a/src/util/virhostcpu.c
+++ b/src/util/virhostcpu.c
@@ -1206,3 +1206,46 @@ virHostCPUGetKVMMaxVCPUs(void)
return -1;
}
#endif /* HAVE_LINUX_KVM_H */
+
+
+#ifdef __linux__
+
+unsigned int
+virHostCPUGetMicrocodeVersion(void)
+{
+ char *outbuf = NULL;
+ char *cur;
+ unsigned int version = 0;
+
+ if (virFileReadHeaderQuiet(CPUINFO_PATH, 4096, &outbuf) < 0) {
+ char ebuf[1024];
+ VIR_DEBUG("Failed to read microcode version from %s: %s",
+ CPUINFO_PATH, virStrerror(errno, ebuf, sizeof(ebuf)));
+ return 0;
+ }
+
+ /* Account for format 'microcode : XXXX'*/
+ if (!(cur = strstr(outbuf, "microcode")) ||
+ !(cur = strchr(cur, ':')))
+ goto cleanup;
+ cur++;
+
+ /* Linux places the microcode revision in a 32-bit integer, so
+ * ui is fine for us too. */
+ if (virStrToLong_ui(cur, &cur, 0, &version) < 0)
+ goto cleanup;
+
+ cleanup:
+ VIR_FREE(outbuf);
+ return version;
+}
+
+#else
+
+unsigned int
+virHostCPUGetMicrocodeVersion(void)
+{
+ return 0;
+}
+
+#endif
diff --git a/src/util/virhostcpu.h b/src/util/virhostcpu.h
index 67033de842..f9f3359288 100644
--- a/src/util/virhostcpu.h
+++ b/src/util/virhostcpu.h
@@ -66,4 +66,6 @@ virBitmapPtr virHostCPUGetSiblingsList(unsigned int cpu);
int virHostCPUGetOnline(unsigned int cpu, bool *online);
+unsigned int virHostCPUGetMicrocodeVersion(void);
+
#endif /* __VIR_HOSTCPU_H__*/
--
2.17.0
@@ -1,51 +0,0 @@
From a0ad8c160ed81417e4d5b46adf3118df1b6b1b77 Mon Sep 17 00:00:00 2001
From: Jiri Denemark <jdenemar@redhat.com>
Date: Wed, 13 Dec 2017 22:30:31 +0100
Subject: [PATCH 14/19] cpu_x86: Rename virCPUx86MapInitialize
The function will be used to initialize internal data of the x86 CPU
driver (including the CPU map).
CVE-2017-5715
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
---
src/cpu/cpu_x86.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/cpu/cpu_x86.c b/src/cpu/cpu_x86.c
index 3b7a6f95fe..0cb0dcacb3 100644
--- a/src/cpu/cpu_x86.c
+++ b/src/cpu/cpu_x86.c
@@ -153,8 +153,8 @@ struct _virCPUx86Map {
};
static virCPUx86MapPtr cpuMap;
-int virCPUx86MapOnceInit(void);
-VIR_ONCE_GLOBAL_INIT(virCPUx86Map);
+int virCPUx86DriverOnceInit(void);
+VIR_ONCE_GLOBAL_INIT(virCPUx86Driver);
typedef enum {
@@ -1387,7 +1387,7 @@ virCPUx86LoadMap(void)
int
-virCPUx86MapOnceInit(void)
+virCPUx86DriverOnceInit(void)
{
if (!(cpuMap = virCPUx86LoadMap()))
return -1;
@@ -1399,7 +1399,7 @@ virCPUx86MapOnceInit(void)
static virCPUx86MapPtr
virCPUx86GetMap(void)
{
- if (virCPUx86MapInitialize() < 0)
+ if (virCPUx86DriverInitialize() < 0)
return NULL;
return cpuMap;
--
2.17.0
@@ -1,133 +0,0 @@
From c628c42493170bfd70f30d9fb56d0067e6e4828a Mon Sep 17 00:00:00 2001
From: Paolo Bonzini <pbonzini@redhat.com>
Date: Tue, 19 Jun 2018 16:47:20 +0100
Subject: [PATCH 15/19] conf: include x86 microcode version in virsh
capabiltiies
A microcode update can cause the CPUID bits to change; an example
from the past was the update that disabled TSX on several Haswell and
Broadwell machines.
In order to track the x86 microcode version in the QEMU capabilities,
we have to fetch it and store it in the host CPU. This also makes the
version visible in "virsh capabilities", which is a nice side effect.
CVE-2017-5715
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
---
src/conf/cpu_conf.c | 14 ++++++++++++++
src/conf/cpu_conf.h | 1 +
src/cpu/cpu_x86.c | 9 +++++++++
3 files changed, 24 insertions(+)
diff --git a/src/conf/cpu_conf.c b/src/conf/cpu_conf.c
index c21d11d244..3f3c25320e 100644
--- a/src/conf/cpu_conf.c
+++ b/src/conf/cpu_conf.c
@@ -127,6 +127,7 @@ virCPUDefCopyModelFilter(virCPUDefPtr dst,
VIR_STRDUP(dst->vendor_id, src->vendor_id) < 0 ||
VIR_ALLOC_N(dst->features, src->nfeatures) < 0)
return -1;
+ dst->microcodeVersion = src->microcodeVersion;
dst->nfeatures_max = src->nfeatures;
dst->nfeatures = 0;
@@ -178,6 +179,7 @@ virCPUDefStealModel(virCPUDefPtr dst,
VIR_STEAL_PTR(dst->model, src->model);
VIR_STEAL_PTR(dst->features, src->features);
+ dst->microcodeVersion = src->microcodeVersion;
dst->nfeatures_max = src->nfeatures_max;
src->nfeatures_max = 0;
dst->nfeatures = src->nfeatures;
@@ -379,6 +381,14 @@ virCPUDefParseXML(xmlXPathContextPtr ctxt,
goto cleanup;
}
VIR_FREE(arch);
+
+ if (virXPathBoolean("boolean(./microcode[1]/@version)", ctxt) > 0 &&
+ virXPathUInt("string(./microcode[1]/@version)", ctxt,
+ &def->microcodeVersion) < 0) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("invalid microcode version"));
+ goto cleanup;
+ }
}
if (!(def->model = virXPathString("string(./model[1])", ctxt)) &&
@@ -723,6 +733,10 @@ virCPUDefFormatBuf(virBufferPtr buf,
if (formatModel && def->vendor)
virBufferEscapeString(buf, "<vendor>%s</vendor>\n", def->vendor);
+ if (def->type == VIR_CPU_TYPE_HOST && def->microcodeVersion)
+ virBufferAsprintf(buf, "<microcode version='%u'/>\n",
+ def->microcodeVersion);
+
if (def->sockets && def->cores && def->threads) {
virBufferAddLit(buf, "<topology");
virBufferAsprintf(buf, " sockets='%u'", def->sockets);
diff --git a/src/conf/cpu_conf.h b/src/conf/cpu_conf.h
index b44974f47e..a30ecf8681 100644
--- a/src/conf/cpu_conf.h
+++ b/src/conf/cpu_conf.h
@@ -133,6 +133,7 @@ struct _virCPUDef {
char *vendor_id; /* vendor id returned by CPUID in the guest */
int fallback; /* enum virCPUFallback */
char *vendor;
+ unsigned int microcodeVersion;
unsigned int sockets;
unsigned int cores;
unsigned int threads;
diff --git a/src/cpu/cpu_x86.c b/src/cpu/cpu_x86.c
index 0cb0dcacb3..41aaa61c35 100644
--- a/src/cpu/cpu_x86.c
+++ b/src/cpu/cpu_x86.c
@@ -33,6 +33,7 @@
#include "virbuffer.h"
#include "virendian.h"
#include "virstring.h"
+#include "virhostcpu.h"
#define VIR_FROM_THIS VIR_FROM_CPU
@@ -153,6 +154,8 @@ struct _virCPUx86Map {
};
static virCPUx86MapPtr cpuMap;
+static unsigned int microcodeVersion;
+
int virCPUx86DriverOnceInit(void);
VIR_ONCE_GLOBAL_INIT(virCPUx86Driver);
@@ -1392,6 +1395,8 @@ virCPUx86DriverOnceInit(void)
if (!(cpuMap = virCPUx86LoadMap()))
return -1;
+ microcodeVersion = virHostCPUGetMicrocodeVersion();
+
return 0;
}
@@ -2409,6 +2414,9 @@ virCPUx86GetHost(virCPUDefPtr cpu,
virCPUDataPtr cpuData = NULL;
int ret = -1;
+ if (virCPUx86DriverInitialize() < 0)
+ goto cleanup;
+
if (!(cpuData = virCPUDataNew(archs[0])))
goto cleanup;
@@ -2417,6 +2425,7 @@ virCPUx86GetHost(virCPUDefPtr cpu,
goto cleanup;
ret = x86DecodeCPUData(cpu, cpuData, models, nmodels, NULL);
+ cpu->microcodeVersion = microcodeVersion;
cleanup:
virCPUx86DataFree(cpuData);
--
2.17.0
@@ -1,535 +0,0 @@
From a31edb693bb79f1ad8931db284f1dbceae178f27 Mon Sep 17 00:00:00 2001
From: Paolo Bonzini <pbonzini@redhat.com>
Date: Tue, 19 Jun 2018 16:50:02 +0100
Subject: [PATCH 16/19] qemu: capabilities: force update if the microcode
version does not match
A microcode update can cause the CPUID bits to change; an example
from the past was the update that disabled TSX on several Haswell
and Broadwell machines.
Therefore, place microcode version in the virQEMUCaps struct and
XML, and rebuild the cache if the versions do not match.
CVE-2017-5715
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
---
src/qemu/qemu_capabilities.c | 40 ++++++++++++++++++-
src/qemu/qemu_capabilities.h | 6 ++-
src/qemu/qemu_capspriv.h | 6 +++
src/qemu/qemu_driver.c | 9 ++++-
.../caps_1.2.2.x86_64.xml | 1 +
.../caps_1.3.1.x86_64.xml | 1 +
.../caps_1.4.2.x86_64.xml | 1 +
.../caps_1.5.3.x86_64.xml | 1 +
.../caps_1.6.0.x86_64.xml | 1 +
.../caps_1.7.0.x86_64.xml | 1 +
.../caps_2.1.1.x86_64.xml | 1 +
.../caps_2.4.0.x86_64.xml | 1 +
.../caps_2.5.0.x86_64.xml | 1 +
.../caps_2.6.0-gicv2.aarch64.xml | 1 +
.../caps_2.6.0-gicv3.aarch64.xml | 1 +
.../caps_2.6.0.ppc64le.xml | 1 +
.../caps_2.6.0.x86_64.xml | 1 +
.../qemucapabilitiesdata/caps_2.7.0.s390x.xml | 1 +
.../caps_2.7.0.x86_64.xml | 1 +
.../qemucapabilitiesdata/caps_2.8.0.s390x.xml | 1 +
.../caps_2.8.0.x86_64.xml | 1 +
.../caps_2.9.0.ppc64le.xml | 1 +
.../qemucapabilitiesdata/caps_2.9.0.s390x.xml | 1 +
.../caps_2.9.0.x86_64.xml | 1 +
tests/qemucapabilitiestest.c | 14 +++++--
tests/qemucapsprobe.c | 2 +-
tests/testutilsqemu.c | 2 +-
27 files changed, 89 insertions(+), 10 deletions(-)
diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c
index 2de84715ea..72b70ce750 100644
--- a/src/qemu/qemu_capabilities.c
+++ b/src/qemu/qemu_capabilities.c
@@ -500,6 +500,7 @@ struct _virQEMUCaps {
unsigned int version;
unsigned int kvmVersion;
unsigned int libvirtVersion;
+ unsigned int microcodeVersion;
char *package;
virArch arch;
@@ -2304,6 +2305,7 @@ virQEMUCapsPtr virQEMUCapsNewCopy(virQEMUCapsPtr qemuCaps)
ret->version = qemuCaps->version;
ret->kvmVersion = qemuCaps->kvmVersion;
+ ret->microcodeVersion = qemuCaps->microcodeVersion;
if (VIR_STRDUP(ret->package, qemuCaps->package) < 0)
goto error;
@@ -3809,6 +3811,7 @@ struct _virQEMUCapsCachePriv {
uid_t runUid;
gid_t runGid;
virArch hostArch;
+ unsigned int microcodeVersion;
};
typedef struct _virQEMUCapsCachePriv virQEMUCapsCachePriv;
typedef virQEMUCapsCachePriv *virQEMUCapsCachePrivPtr;
@@ -3931,6 +3934,13 @@ virQEMUCapsLoadCache(virArch hostArch,
goto cleanup;
}
+ if (virXPathUInt("string(./microcodeVersion)", ctxt,
+ &qemuCaps->microcodeVersion) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("missing microcode version in QEMU capabilities cache"));
+ goto cleanup;
+ }
+
if (virXPathBoolean("boolean(./package)", ctxt) > 0) {
qemuCaps->package = virXPathString("string(./package)", ctxt);
if (!qemuCaps->package &&
@@ -4195,6 +4205,9 @@ virQEMUCapsFormatCache(virQEMUCapsPtr qemuCaps)
virBufferAsprintf(&buf, "<kvmVersion>%d</kvmVersion>\n",
qemuCaps->kvmVersion);
+ virBufferAsprintf(&buf, "<microcodeVersion>%u</microcodeVersion>\n",
+ qemuCaps->microcodeVersion);
+
if (qemuCaps->package)
virBufferAsprintf(&buf, "<package>%s</package>\n",
qemuCaps->package);
@@ -4336,6 +4349,16 @@ virQEMUCapsIsValid(void *data,
return false;
}
+ if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_KVM) &&
+ priv->microcodeVersion != qemuCaps->microcodeVersion) {
+ VIR_DEBUG("Outdated capabilities for '%s': microcode version changed "
+ "(%u vs %u)",
+ qemuCaps->binary,
+ priv->microcodeVersion,
+ qemuCaps->microcodeVersion);
+ return false;
+ }
+
return true;
}
@@ -5151,6 +5174,7 @@ virQEMUCapsNewForBinaryInternal(virArch hostArch,
const char *libDir,
uid_t runUid,
gid_t runGid,
+ unsigned int microcodeVersion,
bool qmpOnly)
{
virQEMUCapsPtr qemuCaps;
@@ -5207,6 +5231,9 @@ virQEMUCapsNewForBinaryInternal(virArch hostArch,
virQEMUCapsInitHostCPUModel(qemuCaps, hostArch, VIR_DOMAIN_VIRT_KVM);
virQEMUCapsInitHostCPUModel(qemuCaps, hostArch, VIR_DOMAIN_VIRT_QEMU);
+ if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_KVM))
+ qemuCaps->microcodeVersion = microcodeVersion;
+
cleanup:
VIR_FREE(qmperr);
return qemuCaps;
@@ -5228,6 +5255,7 @@ virQEMUCapsNewData(const char *binary,
priv->libDir,
priv->runUid,
priv->runGid,
+ priv->microcodeVersion,
false);
}
@@ -5310,7 +5338,8 @@ virFileCachePtr
virQEMUCapsCacheNew(const char *libDir,
const char *cacheDir,
uid_t runUid,
- gid_t runGid)
+ gid_t runGid,
+ unsigned int microcodeVersion)
{
char *capsCacheDir = NULL;
virFileCachePtr cache = NULL;
@@ -5333,6 +5362,7 @@ virQEMUCapsCacheNew(const char *libDir,
priv->runUid = runUid;
priv->runGid = runGid;
+ priv->microcodeVersion = microcodeVersion;
cleanup:
VIR_FREE(capsCacheDir);
@@ -5810,3 +5840,11 @@ virQEMUCapsFillDomainCaps(virCapsPtr caps,
return -1;
return 0;
}
+
+
+void
+virQEMUCapsSetMicrocodeVersion(virQEMUCapsPtr qemuCaps,
+ unsigned int microcodeVersion)
+{
+ qemuCaps->microcodeVersion = microcodeVersion;
+}
diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h
index 9c92d6b469..eea296c9c3 100644
--- a/src/qemu/qemu_capabilities.h
+++ b/src/qemu/qemu_capabilities.h
@@ -514,8 +514,10 @@ void virQEMUCapsFilterByMachineType(virQEMUCapsPtr qemuCaps,
const char *machineType);
virFileCachePtr virQEMUCapsCacheNew(const char *libDir,
- const char *cacheDir,
- uid_t uid, gid_t gid);
+ const char *cacheDir,
+ uid_t uid,
+ gid_t gid,
+ unsigned int microcodeVersion);
virQEMUCapsPtr virQEMUCapsCacheLookup(virFileCachePtr cache,
const char *binary);
virQEMUCapsPtr virQEMUCapsCacheLookupCopy(virFileCachePtr cache,
diff --git a/src/qemu/qemu_capspriv.h b/src/qemu/qemu_capspriv.h
index d05256bd35..38c14ffa01 100644
--- a/src/qemu/qemu_capspriv.h
+++ b/src/qemu/qemu_capspriv.h
@@ -36,6 +36,7 @@ virQEMUCapsNewForBinaryInternal(virArch hostArch,
const char *libDir,
uid_t runUid,
gid_t runGid,
+ unsigned int microcodeVersion,
bool qmpOnly);
int virQEMUCapsLoadCache(virArch hostArch,
@@ -101,4 +102,9 @@ virQEMUCapsParseHelpStr(const char *qemu,
int
virQEMUCapsParseDeviceStr(virQEMUCapsPtr qemuCaps,
const char *str);
+
+void
+virQEMUCapsSetMicrocodeVersion(virQEMUCapsPtr qemuCaps,
+ unsigned int microcodeVersion);
+
#endif
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 208ccc9bc3..d8dc5388ea 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -631,6 +631,8 @@ qemuStateInitialize(bool privileged,
gid_t run_gid = -1;
char *hugepagePath = NULL;
size_t i;
+ virCPUDefPtr hostCPU = NULL;
+ unsigned int microcodeVersion = 0;
if (VIR_ALLOC(qemu_driver) < 0)
return -1;
@@ -853,10 +855,15 @@ qemuStateInitialize(bool privileged,
run_gid = cfg->group;
}
+ if ((hostCPU = virCPUProbeHost(virArchFromHost())))
+ microcodeVersion = hostCPU->microcodeVersion;
+ virCPUDefFree(hostCPU);
+
qemu_driver->qemuCapsCache = virQEMUCapsCacheNew(cfg->libDir,
cfg->cacheDir,
run_uid,
- run_gid);
+ run_gid,
+ microcodeVersion);
if (!qemu_driver->qemuCapsCache)
goto error;
diff --git a/tests/qemucapabilitiesdata/caps_1.2.2.x86_64.xml b/tests/qemucapabilitiesdata/caps_1.2.2.x86_64.xml
index 956284d5d3..f3f66cd8f5 100644
--- a/tests/qemucapabilitiesdata/caps_1.2.2.x86_64.xml
+++ b/tests/qemucapabilitiesdata/caps_1.2.2.x86_64.xml
@@ -111,6 +111,7 @@
<flag name='query-cpu-definitions'/>
<version>1002002</version>
<kvmVersion>0</kvmVersion>
+ <microcodeVersion>26900</microcodeVersion>
<package></package>
<arch>x86_64</arch>
<cpu type='kvm' name='qemu64'/>
diff --git a/tests/qemucapabilitiesdata/caps_1.3.1.x86_64.xml b/tests/qemucapabilitiesdata/caps_1.3.1.x86_64.xml
index 99384ce5e6..1c4d5ff4a4 100644
--- a/tests/qemucapabilitiesdata/caps_1.3.1.x86_64.xml
+++ b/tests/qemucapabilitiesdata/caps_1.3.1.x86_64.xml
@@ -129,6 +129,7 @@
<flag name='query-cpu-definitions'/>
<version>1003001</version>
<kvmVersion>0</kvmVersion>
+ <microcodeVersion>30198</microcodeVersion>
<package></package>
<arch>x86_64</arch>
<cpu type='kvm' name='qemu64'/>
diff --git a/tests/qemucapabilitiesdata/caps_1.4.2.x86_64.xml b/tests/qemucapabilitiesdata/caps_1.4.2.x86_64.xml
index aea043c57d..a50383c259 100644
--- a/tests/qemucapabilitiesdata/caps_1.4.2.x86_64.xml
+++ b/tests/qemucapabilitiesdata/caps_1.4.2.x86_64.xml
@@ -130,6 +130,7 @@
<flag name='query-cpu-definitions'/>
<version>1004002</version>
<kvmVersion>0</kvmVersion>
+ <microcodeVersion>30915</microcodeVersion>
<package></package>
<arch>x86_64</arch>
<cpu type='kvm' name='Opteron_G5'/>
diff --git a/tests/qemucapabilitiesdata/caps_1.5.3.x86_64.xml b/tests/qemucapabilitiesdata/caps_1.5.3.x86_64.xml
index 6f860e4f25..ad3e122775 100644
--- a/tests/qemucapabilitiesdata/caps_1.5.3.x86_64.xml
+++ b/tests/qemucapabilitiesdata/caps_1.5.3.x86_64.xml
@@ -142,6 +142,7 @@
<flag name='kernel-irqchip'/>
<version>1005003</version>
<kvmVersion>0</kvmVersion>
+ <microcodeVersion>47019</microcodeVersion>
<package></package>
<arch>x86_64</arch>
<cpu type='kvm' name='Opteron_G5'/>
diff --git a/tests/qemucapabilitiesdata/caps_1.6.0.x86_64.xml b/tests/qemucapabilitiesdata/caps_1.6.0.x86_64.xml
index e5dc8360de..7b2324d697 100644
--- a/tests/qemucapabilitiesdata/caps_1.6.0.x86_64.xml
+++ b/tests/qemucapabilitiesdata/caps_1.6.0.x86_64.xml
@@ -147,6 +147,7 @@
<flag name='kernel-irqchip'/>
<version>1006000</version>
<kvmVersion>0</kvmVersion>
+ <microcodeVersion>45248</microcodeVersion>
<package></package>
<arch>x86_64</arch>
<cpu type='kvm' name='Opteron_G5'/>
diff --git a/tests/qemucapabilitiesdata/caps_1.7.0.x86_64.xml b/tests/qemucapabilitiesdata/caps_1.7.0.x86_64.xml
index 86d87eaf0c..4ba509a753 100644
--- a/tests/qemucapabilitiesdata/caps_1.7.0.x86_64.xml
+++ b/tests/qemucapabilitiesdata/caps_1.7.0.x86_64.xml
@@ -149,6 +149,7 @@
<flag name='kernel-irqchip'/>
<version>1007000</version>
<kvmVersion>0</kvmVersion>
+ <microcodeVersion>50692</microcodeVersion>
<package></package>
<arch>x86_64</arch>
<cpu type='kvm' name='Opteron_G5'/>
diff --git a/tests/qemucapabilitiesdata/caps_2.1.1.x86_64.xml b/tests/qemucapabilitiesdata/caps_2.1.1.x86_64.xml
index 2fa551b1a0..416703ac89 100644
--- a/tests/qemucapabilitiesdata/caps_2.1.1.x86_64.xml
+++ b/tests/qemucapabilitiesdata/caps_2.1.1.x86_64.xml
@@ -165,6 +165,7 @@
<flag name='kernel-irqchip'/>
<version>2001001</version>
<kvmVersion>0</kvmVersion>
+ <microcodeVersion>59488</microcodeVersion>
<package></package>
<arch>x86_64</arch>
<cpu type='kvm' name='Opteron_G5'/>
diff --git a/tests/qemucapabilitiesdata/caps_2.4.0.x86_64.xml b/tests/qemucapabilitiesdata/caps_2.4.0.x86_64.xml
index f97e4cb813..4550139e0c 100644
--- a/tests/qemucapabilitiesdata/caps_2.4.0.x86_64.xml
+++ b/tests/qemucapabilitiesdata/caps_2.4.0.x86_64.xml
@@ -190,6 +190,7 @@
<flag name='virtio-gpu.max_outputs'/>
<version>2004000</version>
<kvmVersion>0</kvmVersion>
+ <microcodeVersion>75653</microcodeVersion>
<package></package>
<arch>x86_64</arch>
<cpu type='kvm' name='Opteron_G5'/>
diff --git a/tests/qemucapabilitiesdata/caps_2.5.0.x86_64.xml b/tests/qemucapabilitiesdata/caps_2.5.0.x86_64.xml
index 2ba40fc494..6072438688 100644
--- a/tests/qemucapabilitiesdata/caps_2.5.0.x86_64.xml
+++ b/tests/qemucapabilitiesdata/caps_2.5.0.x86_64.xml
@@ -196,6 +196,7 @@
<flag name='virtio-gpu.max_outputs'/>
<version>2005000</version>
<kvmVersion>0</kvmVersion>
+ <microcodeVersion>216775</microcodeVersion>
<package></package>
<arch>x86_64</arch>
<cpu type='kvm' name='Opteron_G5'/>
diff --git a/tests/qemucapabilitiesdata/caps_2.6.0-gicv2.aarch64.xml b/tests/qemucapabilitiesdata/caps_2.6.0-gicv2.aarch64.xml
index 0b34fa30d4..6fc0ab25e0 100644
--- a/tests/qemucapabilitiesdata/caps_2.6.0-gicv2.aarch64.xml
+++ b/tests/qemucapabilitiesdata/caps_2.6.0-gicv2.aarch64.xml
@@ -174,6 +174,7 @@
<flag name='virtio-gpu.max_outputs'/>
<version>2006000</version>
<kvmVersion>0</kvmVersion>
+ <microcodeVersion>228838</microcodeVersion>
<package></package>
<arch>aarch64</arch>
<cpu type='kvm' name='pxa262'/>
diff --git a/tests/qemucapabilitiesdata/caps_2.6.0-gicv3.aarch64.xml b/tests/qemucapabilitiesdata/caps_2.6.0-gicv3.aarch64.xml
index d41d578c7e..1846bf6a7c 100644
--- a/tests/qemucapabilitiesdata/caps_2.6.0-gicv3.aarch64.xml
+++ b/tests/qemucapabilitiesdata/caps_2.6.0-gicv3.aarch64.xml
@@ -174,6 +174,7 @@
<flag name='virtio-gpu.max_outputs'/>
<version>2006000</version>
<kvmVersion>0</kvmVersion>
+ <microcodeVersion>228838</microcodeVersion>
<package></package>
<arch>aarch64</arch>
<cpu type='kvm' name='pxa262'/>
diff --git a/tests/qemucapabilitiesdata/caps_2.6.0.ppc64le.xml b/tests/qemucapabilitiesdata/caps_2.6.0.ppc64le.xml
index f1c9fc98a4..199fc2cd22 100644
--- a/tests/qemucapabilitiesdata/caps_2.6.0.ppc64le.xml
+++ b/tests/qemucapabilitiesdata/caps_2.6.0.ppc64le.xml
@@ -169,6 +169,7 @@
<flag name='virtio-gpu.max_outputs'/>
<version>2006000</version>
<kvmVersion>0</kvmVersion>
+ <microcodeVersion>263602</microcodeVersion>
<package></package>
<arch>ppc64</arch>
<cpu type='kvm' name='default'/>
diff --git a/tests/qemucapabilitiesdata/caps_2.6.0.x86_64.xml b/tests/qemucapabilitiesdata/caps_2.6.0.x86_64.xml
index bdf006f6be..5897fbc0c9 100644
--- a/tests/qemucapabilitiesdata/caps_2.6.0.x86_64.xml
+++ b/tests/qemucapabilitiesdata/caps_2.6.0.x86_64.xml
@@ -206,6 +206,7 @@
<flag name='virtio-gpu.max_outputs'/>
<version>2006000</version>
<kvmVersion>0</kvmVersion>
+ <microcodeVersion>227579</microcodeVersion>
<package></package>
<arch>x86_64</arch>
<cpu type='kvm' name='Opteron_G5'/>
diff --git a/tests/qemucapabilitiesdata/caps_2.7.0.s390x.xml b/tests/qemucapabilitiesdata/caps_2.7.0.s390x.xml
index fe7bca93b9..4c208008be 100644
--- a/tests/qemucapabilitiesdata/caps_2.7.0.s390x.xml
+++ b/tests/qemucapabilitiesdata/caps_2.7.0.s390x.xml
@@ -136,6 +136,7 @@
<flag name='virtio-gpu.max_outputs'/>
<version>2007000</version>
<kvmVersion>0</kvmVersion>
+ <microcodeVersion>217559</microcodeVersion>
<package></package>
<arch>s390x</arch>
<cpu type='kvm' name='host'/>
diff --git a/tests/qemucapabilitiesdata/caps_2.7.0.x86_64.xml b/tests/qemucapabilitiesdata/caps_2.7.0.x86_64.xml
index 3fd28f09fe..e3a154806c 100644
--- a/tests/qemucapabilitiesdata/caps_2.7.0.x86_64.xml
+++ b/tests/qemucapabilitiesdata/caps_2.7.0.x86_64.xml
@@ -209,6 +209,7 @@
<flag name='virtio-gpu.max_outputs'/>
<version>2007000</version>
<kvmVersion>0</kvmVersion>
+ <microcodeVersion>239276</microcodeVersion>
<package> (v2.7.0)</package>
<arch>x86_64</arch>
<cpu type='kvm' name='Opteron_G5'/>
diff --git a/tests/qemucapabilitiesdata/caps_2.8.0.s390x.xml b/tests/qemucapabilitiesdata/caps_2.8.0.s390x.xml
index 21bbb820d0..f13c783d44 100644
--- a/tests/qemucapabilitiesdata/caps_2.8.0.s390x.xml
+++ b/tests/qemucapabilitiesdata/caps_2.8.0.s390x.xml
@@ -138,6 +138,7 @@
<flag name='virtio-gpu.max_outputs'/>
<version>2007093</version>
<kvmVersion>0</kvmVersion>
+ <microcodeVersion>242460</microcodeVersion>
<package></package>
<arch>s390x</arch>
<hostCPU type='kvm' model='zEC12.2-base' migratability='no'>
diff --git a/tests/qemucapabilitiesdata/caps_2.8.0.x86_64.xml b/tests/qemucapabilitiesdata/caps_2.8.0.x86_64.xml
index 761f9d1415..f5bd1d7272 100644
--- a/tests/qemucapabilitiesdata/caps_2.8.0.x86_64.xml
+++ b/tests/qemucapabilitiesdata/caps_2.8.0.x86_64.xml
@@ -211,6 +211,7 @@
<flag name='virtio-gpu.max_outputs'/>
<version>2008000</version>
<kvmVersion>0</kvmVersion>
+ <microcodeVersion>255931</microcodeVersion>
<package> (v2.8.0)</package>
<arch>x86_64</arch>
<cpu type='kvm' name='host' usable='yes'/>
diff --git a/tests/qemucapabilitiesdata/caps_2.9.0.ppc64le.xml b/tests/qemucapabilitiesdata/caps_2.9.0.ppc64le.xml
index 9551907c66..2d1d0f9a89 100644
--- a/tests/qemucapabilitiesdata/caps_2.9.0.ppc64le.xml
+++ b/tests/qemucapabilitiesdata/caps_2.9.0.ppc64le.xml
@@ -175,6 +175,7 @@
<flag name='disk-share-rw'/>
<version>2009000</version>
<kvmVersion>0</kvmVersion>
+ <microcodeVersion>347135</microcodeVersion>
<package> (v2.9.0)</package>
<arch>ppc64</arch>
<cpu type='kvm' name='default'/>
diff --git a/tests/qemucapabilitiesdata/caps_2.9.0.s390x.xml b/tests/qemucapabilitiesdata/caps_2.9.0.s390x.xml
index 0a6fbd0776..3b733801f8 100644
--- a/tests/qemucapabilitiesdata/caps_2.9.0.s390x.xml
+++ b/tests/qemucapabilitiesdata/caps_2.9.0.s390x.xml
@@ -140,6 +140,7 @@
<flag name='disk-share-rw'/>
<version>2009000</version>
<kvmVersion>0</kvmVersion>
+ <microcodeVersion>265878</microcodeVersion>
<package></package>
<arch>s390x</arch>
<hostCPU type='kvm' model='z13.2-base' migratability='no'>
diff --git a/tests/qemucapabilitiesdata/caps_2.9.0.x86_64.xml b/tests/qemucapabilitiesdata/caps_2.9.0.x86_64.xml
index 1294ebdb31..086594def5 100644
--- a/tests/qemucapabilitiesdata/caps_2.9.0.x86_64.xml
+++ b/tests/qemucapabilitiesdata/caps_2.9.0.x86_64.xml
@@ -223,6 +223,7 @@
<flag name='disk-share-rw'/>
<version>2009000</version>
<kvmVersion>0</kvmVersion>
+ <microcodeVersion>321194</microcodeVersion>
<package> (v2.9.0)</package>
<arch>x86_64</arch>
<hostCPU type='kvm' model='base' migratability='yes'>
diff --git a/tests/qemucapabilitiestest.c b/tests/qemucapabilitiestest.c
index 3ae55fc62f..4608fffbb2 100644
--- a/tests/qemucapabilitiestest.c
+++ b/tests/qemucapabilitiestest.c
@@ -61,10 +61,16 @@ testQemuCaps(const void *opaque)
qemuMonitorTestGetMonitor(mon)) < 0)
goto cleanup;
- if (virQEMUCapsGet(capsActual, QEMU_CAPS_KVM) &&
- virQEMUCapsInitQMPMonitorTCG(capsActual,
- qemuMonitorTestGetMonitor(mon)) < 0)
- goto cleanup;
+ if (virQEMUCapsGet(capsActual, QEMU_CAPS_KVM)) {
+ if (virQEMUCapsInitQMPMonitorTCG(capsActual,
+ qemuMonitorTestGetMonitor(mon)) < 0)
+ goto cleanup;
+
+ /* Fill microcodeVersion with a "random" value which is the file
+ * length to provide a reproducible number for testing.
+ */
+ virQEMUCapsSetMicrocodeVersion(capsActual, virFileLength(repliesFile, -1));
+ }
if (!(actual = virQEMUCapsFormatCache(capsActual)))
goto cleanup;
diff --git a/tests/qemucapsprobe.c b/tests/qemucapsprobe.c
index 4b8d6229b4..a5f5a38b16 100644
--- a/tests/qemucapsprobe.c
+++ b/tests/qemucapsprobe.c
@@ -72,7 +72,7 @@ main(int argc, char **argv)
return EXIT_FAILURE;
if (!(caps = virQEMUCapsNewForBinaryInternal(VIR_ARCH_NONE, argv[1], "/tmp",
- -1, -1, true)))
+ -1, -1, 0, true)))
return EXIT_FAILURE;
virObjectUnref(caps);
diff --git a/tests/testutilsqemu.c b/tests/testutilsqemu.c
index 2c7124bf26..f8182033fc 100644
--- a/tests/testutilsqemu.c
+++ b/tests/testutilsqemu.c
@@ -603,7 +603,7 @@ int qemuTestDriverInit(virQEMUDriver *driver)
/* Using /dev/null for libDir and cacheDir automatically produces errors
* upon attempt to use any of them */
- driver->qemuCapsCache = virQEMUCapsCacheNew("/dev/null", "/dev/null", 0, 0);
+ driver->qemuCapsCache = virQEMUCapsCacheNew("/dev/null", "/dev/null", 0, 0, 0);
if (!driver->qemuCapsCache)
goto error;
--
2.17.0
@@ -1,142 +0,0 @@
From ac0e85360cd8f25160b67ee9fb45663d20f82c1d Mon Sep 17 00:00:00 2001
From: Paolo Bonzini <pbonzini@redhat.com>
Date: Tue, 19 Jun 2018 16:51:13 +0100
Subject: [PATCH 17/19] cpu: add CPU features and model for indirect branch
prediction protection
CVE-2017-5715
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
---
src/cpu/cpu_map.xml | 44 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 44 insertions(+)
diff --git a/src/cpu/cpu_map.xml b/src/cpu/cpu_map.xml
index 8e7ac4973d..c31e7ce36a 100644
--- a/src/cpu/cpu_map.xml
+++ b/src/cpu/cpu_map.xml
@@ -283,6 +283,9 @@
<feature name='avx512-4fmaps'>
<cpuid eax_in='0x07' ecx_in='0x00' edx='0x00000008'/>
</feature>
+ <feature name='spec-ctrl'>
+ <cpuid eax_in='0x07' ecx_in='0x00' edx='0x04000000'/>
+ </feature>
<!-- Processor Extended State Enumeration sub leaf 1 -->
<feature name='xsaveopt'>
@@ -411,6 +414,11 @@
<cpuid eax_in='0x80000007' edx='0x00000100'/>
</feature>
+ <!-- More AMD-specific features -->
+ <feature name='ibpb'>
+ <cpuid eax_in='0x80000008' ebx='0x00001000'/>
+ </feature>
+
<!-- models -->
<model name='486'>
<feature name='fpu'/>
@@ -857,6 +865,10 @@
<feature name='syscall'/>
<feature name='tsc'/>
</model>
+ <model name='Nehalem-IBRS'>
+ <model name='Nehalem'/>
+ <feature name='spec-ctrl'/>
+ </model>
<model name='Westmere'>
<signature family='6' model='44'/>
@@ -894,6 +906,10 @@
<feature name='syscall'/>
<feature name='tsc'/>
</model>
+ <model name='Westmere-IBRS'>
+ <model name='Westmere'/>
+ <feature name='spec-ctrl'/>
+ </model>
<model name='SandyBridge'>
<signature family='6' model='42'/>
@@ -937,6 +953,10 @@
<feature name='x2apic'/>
<feature name='xsave'/>
</model>
+ <model name='SandyBridge-IBRS'>
+ <model name='SandyBridge'/>
+ <feature name='spec-ctrl'/>
+ </model>
<model name='IvyBridge'>
<signature family='6' model='58'/>
@@ -986,6 +1006,10 @@
<feature name='x2apic'/>
<feature name='xsave'/>
</model>
+ <model name='IvyBridge-IBRS'>
+ <model name='IvyBridge'/>
+ <feature name='spec-ctrl'/>
+ </model>
<model name='Haswell-noTSX'>
<signature family='6' model='60'/>
@@ -1039,6 +1063,10 @@
<feature name='x2apic'/>
<feature name='xsave'/>
</model>
+ <model name='Haswell-noTSX-IBRS'>
+ <model name='Haswell-noTSX'/>
+ <feature name='spec-ctrl'/>
+ </model>
<model name='Haswell'>
<signature family='6' model='60'/>
@@ -1094,6 +1122,10 @@
<feature name='x2apic'/>
<feature name='xsave'/>
</model>
+ <model name='Haswell-IBRS'>
+ <model name='Haswell'/>
+ <feature name='spec-ctrl'/>
+ </model>
<model name='Broadwell-noTSX'>
<signature family='6' model='61'/>
@@ -1151,6 +1183,10 @@
<feature name='x2apic'/>
<feature name='xsave'/>
</model>
+ <model name='Broadwell-noTSX-IBRS'>
+ <model name='Broadwell-noTSX'/>
+ <feature name='spec-ctrl'/>
+ </model>
<model name='Broadwell'>
<signature family='6' model='61'/>
@@ -1210,6 +1246,10 @@
<feature name='x2apic'/>
<feature name='xsave'/>
</model>
+ <model name='Broadwell-IBRS'>
+ <model name='Broadwell'/>
+ <feature name='spec-ctrl'/>
+ </model>
<model name='Skylake-Client'>
<signature family='6' model='94'/>
@@ -1278,6 +1318,10 @@
<feature name='xsavec'/>
<feature name='xsaveopt'/>
</model>
+ <model name='Skylake-Client-IBRS'>
+ <model name='Skylake-Client'/>
+ <feature name='spec-ctrl'/>
+ </model>
<!-- AMD CPUs -->
<model name='athlon'>
--
2.17.0
@@ -1,37 +0,0 @@
From 9a252992aa81b4873b22f174de9d345f4289051c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= <berrange@redhat.com>
Date: Mon, 21 May 2018 23:05:07 +0100
Subject: [PATCH 18/19] cpu: define the 'ssbd' CPUID feature bit
(CVE-2018-3639)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
New microcode introduces the "Speculative Store Bypass Disable"
CPUID feature bit. This needs to be exposed to guest OS to allow
them to protect against CVE-2018-3639.
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
Reviewed-by: Jiri Denemark <jdenemar@redhat.com>
(cherry picked from commit 1dbca2eccad58d91a5fd33962854f1a653638182)
---
src/cpu/cpu_map.xml | 3 +++
1 file changed, 3 insertions(+)
diff --git a/src/cpu/cpu_map.xml b/src/cpu/cpu_map.xml
index c31e7ce36a..87301dc0ef 100644
--- a/src/cpu/cpu_map.xml
+++ b/src/cpu/cpu_map.xml
@@ -286,6 +286,9 @@
<feature name='spec-ctrl'>
<cpuid eax_in='0x07' ecx_in='0x00' edx='0x04000000'/>
</feature>
+ <feature name='ssbd'>
+ <cpuid eax_in='0x07' ecx_in='0x00' edx='0x80000000'/>
+ </feature>
<!-- Processor Extended State Enumeration sub leaf 1 -->
<feature name='xsaveopt'>
--
2.17.0
@@ -1,46 +0,0 @@
From 7774fbbda1c886633eaf0015d6211fc0ad703bc7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= <berrange@redhat.com>
Date: Mon, 21 May 2018 23:05:08 +0100
Subject: [PATCH 19/19] cpu: define the 'virt-ssbd' CPUID feature bit
(CVE-2018-3639)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Some AMD processors only support a non-architectural means of
enabling Speculative Store Bypass Disable. To allow simplified
handling in virtual environments, hypervisors will expose an
architectural definition through CPUID bit 0x80000008_EBX[25].
This needs to be exposed to guest OS running on AMD x86 hosts to
allow them to protect against CVE-2018-3639.
Note that since this CPUID bit won't be present in the host CPUID
results on physical hosts, it will not be enabled automatically
in guests configured with "host-model" CPU unless using QEMU
version >= 2.9.0. Thus for older versions of QEMU, this feature
must be manually enabled using policy=force. Guests using the
"host-passthrough" CPU mode do not need special handling.
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
Reviewed-by: Jiri Denemark <jdenemar@redhat.com>
---
src/cpu/cpu_map.xml | 3 +++
1 file changed, 3 insertions(+)
diff --git a/src/cpu/cpu_map.xml b/src/cpu/cpu_map.xml
index 87301dc0ef..e31c9ae86c 100644
--- a/src/cpu/cpu_map.xml
+++ b/src/cpu/cpu_map.xml
@@ -421,6 +421,9 @@
<feature name='ibpb'>
<cpuid eax_in='0x80000008' ebx='0x00001000'/>
</feature>
+ <feature name='virt-ssbd'>
+ <cpuid eax_in='0x80000008' ebx='0x02000000'/>
+ </feature>
<!-- models -->
<model name='486'>
--
2.17.0
+1
View File
@@ -0,0 +1 @@
F-12
@@ -0,0 +1,356 @@
From 953440bd12608a20007ee5da5ab69fbbe910bd28 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/11] 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 | 206 +++++++++++++++++++++++++++++++++++++++++------
src/util/storage_file.h | 2 +
2 files changed, 183 insertions(+), 25 deletions(-)
diff --git a/src/util/storage_file.c b/src/util/storage_file.c
index 0adea40..80f743e 100644
--- a/src/util/storage_file.c
+++ b/src/util/storage_file.c
@@ -78,12 +78,33 @@ struct FileTypeInfo {
int qcowCryptOffset; /* Byte offset from start of file
* where to find encryption mode,
* -1 if encryption is not used */
- int (*getBackingStore)(char **res, const unsigned char *buf, size_t buf_size);
+ int (*getBackingStore)(char **res, int *format,
+ const unsigned char *buf, size_t buf_size);
};
-static int cowGetBackingStore(char **, const unsigned char *, size_t);
-static int qcowXGetBackingStore(char **, const unsigned char *, size_t);
-static int vmdk4GetBackingStore(char **, const unsigned char *, size_t);
+static int cowGetBackingStore(char **, int *,
+ const unsigned char *, size_t);
+static int qcow1GetBackingStore(char **, int *,
+ const unsigned char *, size_t);
+static int qcow2GetBackingStore(char **, int *,
+ const unsigned char *, size_t);
+static int vmdk4GetBackingStore(char **, int *,
+ const unsigned char *, size_t);
+
+#define QCOWX_HDR_VERSION (4)
+#define QCOWX_HDR_BACKING_FILE_OFFSET (QCOWX_HDR_VERSION+4)
+#define QCOWX_HDR_BACKING_FILE_SIZE (QCOWX_HDR_BACKING_FILE_OFFSET+8)
+#define QCOWX_HDR_IMAGE_SIZE (QCOWX_HDR_BACKING_FILE_SIZE+4+4)
+
+#define QCOW1_HDR_CRYPT (QCOWX_HDR_IMAGE_SIZE+8+1+1)
+#define QCOW2_HDR_CRYPT (QCOWX_HDR_IMAGE_SIZE+8)
+
+#define QCOW1_HDR_TOTAL_SIZE (QCOW1_HDR_CRYPT+4+8)
+#define QCOW2_HDR_TOTAL_SIZE (QCOW2_HDR_CRYPT+4+4+8+8+4+4+8)
+
+#define QCOW2_HDR_EXTENSION_END 0
+#define QCOW2_HDR_EXTENSION_BACKING_FORMAT 0xE2792ACA
+
static struct FileTypeInfo const fileTypeInfo[] = {
@@ -119,11 +140,11 @@ static struct FileTypeInfo const fileTypeInfo[] = {
/* QCow */
{ VIR_STORAGE_FILE_QCOW, "QFI", NULL,
LV_BIG_ENDIAN, 4, 1,
- 4+4+8+4+4, 8, 1, 4+4+8+4+4+8+1+1+2, qcowXGetBackingStore },
+ QCOWX_HDR_IMAGE_SIZE, 8, 1, QCOW1_HDR_CRYPT, qcow1GetBackingStore },
/* QCow 2 */
{ VIR_STORAGE_FILE_QCOW2, "QFI", NULL,
LV_BIG_ENDIAN, 4, 2,
- 4+4+8+4+4, 8, 1, 4+4+8+4+4+8, qcowXGetBackingStore },
+ QCOWX_HDR_IMAGE_SIZE, 8, 1, QCOW2_HDR_CRYPT, qcow2GetBackingStore },
/* VMDK 3 */
/* XXX Untested
{ VIR_STORAGE_FILE_VMDK, "COWD", NULL,
@@ -142,11 +163,14 @@ static struct FileTypeInfo const fileTypeInfo[] = {
static int
cowGetBackingStore(char **res,
+ int *format,
const unsigned char *buf,
size_t buf_size)
{
#define COW_FILENAME_MAXLEN 1024
*res = NULL;
+ *format = VIR_STORAGE_FILE_AUTO;
+
if (buf_size < 4+4+ COW_FILENAME_MAXLEN)
return BACKING_STORE_INVALID;
if (buf[4+4] == '\0') /* cow_header_v2.backing_file[0] */
@@ -160,31 +184,98 @@ cowGetBackingStore(char **res,
return BACKING_STORE_OK;
}
+
+static int
+qcow2GetBackingStoreFormat(int *format,
+ const unsigned char *buf,
+ size_t buf_size,
+ size_t extension_start,
+ size_t extension_end)
+{
+ size_t offset = extension_start;
+
+ /*
+ * The extensions take format of
+ *
+ * int32: magic
+ * int32: length
+ * byte[length]: payload
+ *
+ * Unknown extensions can be ignored by skipping
+ * over "length" bytes in the data stream.
+ */
+ while (offset < (buf_size-8) &&
+ offset < (extension_end-8)) {
+ unsigned int magic =
+ (buf[offset] << 24) +
+ (buf[offset+1] << 16) +
+ (buf[offset+2] << 8) +
+ (buf[offset+3]);
+ unsigned int len =
+ (buf[offset+4] << 24) +
+ (buf[offset+5] << 16) +
+ (buf[offset+6] << 8) +
+ (buf[offset+7]);
+
+ offset += 8;
+
+ if ((offset + len) < offset)
+ break;
+
+ if ((offset + len) > buf_size)
+ break;
+
+ switch (magic) {
+ case QCOW2_HDR_EXTENSION_END:
+ goto done;
+
+ case QCOW2_HDR_EXTENSION_BACKING_FORMAT:
+ if (buf[offset+len] != '\0')
+ break;
+ *format = virStorageFileFormatTypeFromString(
+ ((const char *)buf)+offset);
+ break;
+ }
+
+ offset += len;
+ }
+
+done:
+
+ return 0;
+}
+
+
static int
qcowXGetBackingStore(char **res,
+ int *format,
const unsigned char *buf,
- size_t buf_size)
+ size_t buf_size,
+ bool isQCow2)
{
unsigned long long offset;
unsigned long size;
*res = NULL;
- if (buf_size < 4+4+8+4)
+ if (format)
+ *format = VIR_STORAGE_FILE_AUTO;
+
+ if (buf_size < QCOWX_HDR_BACKING_FILE_OFFSET+8+4)
return BACKING_STORE_INVALID;
- offset = (((unsigned long long)buf[4+4] << 56)
- | ((unsigned long long)buf[4+4+1] << 48)
- | ((unsigned long long)buf[4+4+2] << 40)
- | ((unsigned long long)buf[4+4+3] << 32)
- | ((unsigned long long)buf[4+4+4] << 24)
- | ((unsigned long long)buf[4+4+5] << 16)
- | ((unsigned long long)buf[4+4+6] << 8)
- | buf[4+4+7]); /* QCowHeader.backing_file_offset */
+ offset = (((unsigned long long)buf[QCOWX_HDR_BACKING_FILE_OFFSET] << 56)
+ | ((unsigned long long)buf[QCOWX_HDR_BACKING_FILE_OFFSET+1] << 48)
+ | ((unsigned long long)buf[QCOWX_HDR_BACKING_FILE_OFFSET+2] << 40)
+ | ((unsigned long long)buf[QCOWX_HDR_BACKING_FILE_OFFSET+3] << 32)
+ | ((unsigned long long)buf[QCOWX_HDR_BACKING_FILE_OFFSET+4] << 24)
+ | ((unsigned long long)buf[QCOWX_HDR_BACKING_FILE_OFFSET+5] << 16)
+ | ((unsigned long long)buf[QCOWX_HDR_BACKING_FILE_OFFSET+6] << 8)
+ | buf[QCOWX_HDR_BACKING_FILE_OFFSET+7]); /* QCowHeader.backing_file_offset */
if (offset > buf_size)
return BACKING_STORE_INVALID;
- size = ((buf[4+4+8] << 24)
- | (buf[4+4+8+1] << 16)
- | (buf[4+4+8+2] << 8)
- | buf[4+4+8+3]); /* QCowHeader.backing_file_size */
+ size = ((buf[QCOWX_HDR_BACKING_FILE_SIZE] << 24)
+ | (buf[QCOWX_HDR_BACKING_FILE_SIZE+1] << 16)
+ | (buf[QCOWX_HDR_BACKING_FILE_SIZE+2] << 8)
+ | buf[QCOWX_HDR_BACKING_FILE_SIZE+3]); /* QCowHeader.backing_file_size */
if (size == 0)
return BACKING_STORE_OK;
if (offset + size > buf_size || offset + size < offset)
@@ -197,12 +288,63 @@ qcowXGetBackingStore(char **res,
}
memcpy(*res, buf + offset, size);
(*res)[size] = '\0';
+
+ /*
+ * Traditionally QCow2 files had a layout of
+ *
+ * [header]
+ * [backingStoreName]
+ *
+ * Although the backingStoreName typically followed
+ * the header immediately, this was not required by
+ * the format. By specifying a higher byte offset for
+ * the backing file offset in the header, it was
+ * possible to leave space between the header and
+ * start of backingStore.
+ *
+ * This hack is now used to store extensions to the
+ * qcow2 format:
+ *
+ * [header]
+ * [extensions]
+ * [backingStoreName]
+ *
+ * Thus the file region to search for extensions is
+ * between the end of the header (QCOW2_HDR_TOTAL_SIZE)
+ * and the start of the backingStoreName (offset)
+ */
+ if (isQCow2)
+ qcow2GetBackingStoreFormat(format, buf, buf_size, QCOW2_HDR_TOTAL_SIZE, offset);
+
return BACKING_STORE_OK;
}
static int
+qcow1GetBackingStore(char **res,
+ int *format,
+ const unsigned char *buf,
+ size_t buf_size)
+{
+ /* QCow1 doesn't have the extensions capability
+ * used to store backing format */
+ *format = VIR_STORAGE_FILE_AUTO;
+ return qcowXGetBackingStore(res, NULL, buf, buf_size, false);
+}
+
+static int
+qcow2GetBackingStore(char **res,
+ int *format,
+ const unsigned char *buf,
+ size_t buf_size)
+{
+ return qcowXGetBackingStore(res, format, buf, buf_size, true);
+}
+
+
+static int
vmdk4GetBackingStore(char **res,
+ int *format,
const unsigned char *buf,
size_t buf_size)
{
@@ -212,6 +354,14 @@ vmdk4GetBackingStore(char **res,
size_t len;
*res = NULL;
+ /*
+ * Technically this should have been VMDK, since
+ * VMDK spec / VMWare impl only support VMDK backed
+ * by VMDK. QEMU isn't following this though and
+ * does probing on VMDK backing files, hence we set
+ * AUTO
+ */
+ *format = VIR_STORAGE_FILE_AUTO;
if (buf_size <= 0x200)
return BACKING_STORE_INVALID;
@@ -358,9 +508,12 @@ virStorageFileGetMetadataFromFD(const char *path,
/* Validation passed, we know the file format now */
meta->format = fileTypeInfo[i].type;
if (fileTypeInfo[i].getBackingStore != NULL) {
- char *base;
+ char *backing;
+ int backingFormat;
- switch (fileTypeInfo[i].getBackingStore(&base, head, len)) {
+ switch (fileTypeInfo[i].getBackingStore(&backing,
+ &backingFormat,
+ head, len)) {
case BACKING_STORE_OK:
break;
@@ -370,13 +523,16 @@ virStorageFileGetMetadataFromFD(const char *path,
case BACKING_STORE_ERROR:
return -1;
}
- if (base != NULL) {
- meta->backingStore = absolutePathFromBaseFile(path, base);
- VIR_FREE(base);
+ if (backing != NULL) {
+ meta->backingStore = absolutePathFromBaseFile(path, backing);
+ VIR_FREE(backing);
if (meta->backingStore == NULL) {
virReportOOMError();
return -1;
}
+ meta->backingStoreFormat = backingFormat;
+ } else {
+ meta->backingStoreFormat = VIR_STORAGE_FILE_AUTO;
}
}
return 0;
diff --git a/src/util/storage_file.h b/src/util/storage_file.h
index 58533ee..6328ba7 100644
--- a/src/util/storage_file.h
+++ b/src/util/storage_file.h
@@ -28,6 +28,7 @@
# include <stdbool.h>
enum virStorageFileFormat {
+ VIR_STORAGE_FILE_AUTO = -1,
VIR_STORAGE_FILE_RAW = 0,
VIR_STORAGE_FILE_DIR,
VIR_STORAGE_FILE_BOCHS,
@@ -47,6 +48,7 @@ VIR_ENUM_DECL(virStorageFileFormat);
typedef struct _virStorageFileMetadata {
int format;
char *backingStore;
+ int backingStoreFormat;
unsigned long long capacity;
bool encrypted;
} virStorageFileMetadata;
--
1.7.1.1
+159
View File
@@ -0,0 +1,159 @@
From cab428b1d4d432965cee6f5afb67265557706715 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/11] 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(-)
diff --git a/src/util/storage_file.c b/src/util/storage_file.c
index 80f743e..df0e3a1 100644
--- a/src/util/storage_file.c
+++ b/src/util/storage_file.c
@@ -58,7 +58,6 @@ enum {
/* Either 'magic' or 'extension' *must* be provided */
struct FileTypeInfo {
- int type; /* One of the constants above */
const char *magic; /* Optional string of file magic
* to check at head of file */
const char *extension; /* Optional file extension to check */
@@ -108,58 +107,59 @@ static int vmdk4GetBackingStore(char **, int *,
static struct FileTypeInfo const fileTypeInfo[] = {
- /* Bochs */
- /* XXX Untested
- { VIR_STORAGE_FILE_BOCHS, "Bochs Virtual HD Image", NULL,
- LV_LITTLE_ENDIAN, 64, 0x20000,
- 32+16+16+4+4+4+4+4, 8, 1, -1, NULL },*/
- /* CLoop */
- /* XXX Untested
- { VIR_STORAGE_VOL_CLOOP, "#!/bin/sh\n#V2.0 Format\nmodprobe cloop file=$0 && mount -r -t iso9660 /dev/cloop $1\n", NULL,
- LV_LITTLE_ENDIAN, -1, 0,
- -1, 0, 0, -1, NULL }, */
- /* Cow */
- { VIR_STORAGE_FILE_COW, "OOOM", NULL,
- LV_BIG_ENDIAN, 4, 2,
- 4+4+1024+4, 8, 1, -1, cowGetBackingStore },
- /* DMG */
- /* XXX QEMU says there's no magic for dmg, but we should check... */
- { VIR_STORAGE_FILE_DMG, NULL, ".dmg",
- 0, -1, 0,
- -1, 0, 0, -1, NULL },
- /* XXX there's probably some magic for iso we can validate too... */
- { VIR_STORAGE_FILE_ISO, NULL, ".iso",
- 0, -1, 0,
- -1, 0, 0, -1, NULL },
- /* Parallels */
- /* XXX Untested
- { VIR_STORAGE_FILE_PARALLELS, "WithoutFreeSpace", NULL,
- LV_LITTLE_ENDIAN, 16, 2,
- 16+4+4+4+4, 4, 512, -1, NULL },
- */
- /* QCow */
- { VIR_STORAGE_FILE_QCOW, "QFI", NULL,
- LV_BIG_ENDIAN, 4, 1,
- QCOWX_HDR_IMAGE_SIZE, 8, 1, QCOW1_HDR_CRYPT, qcow1GetBackingStore },
- /* QCow 2 */
- { VIR_STORAGE_FILE_QCOW2, "QFI", NULL,
- LV_BIG_ENDIAN, 4, 2,
- QCOWX_HDR_IMAGE_SIZE, 8, 1, QCOW2_HDR_CRYPT, qcow2GetBackingStore },
- /* VMDK 3 */
- /* XXX Untested
- { VIR_STORAGE_FILE_VMDK, "COWD", NULL,
- LV_LITTLE_ENDIAN, 4, 1,
- 4+4+4, 4, 512, -1, NULL },
- */
- /* VMDK 4 */
- { VIR_STORAGE_FILE_VMDK, "KDMV", NULL,
- LV_LITTLE_ENDIAN, 4, 1,
- 4+4+4, 8, 512, -1, vmdk4GetBackingStore },
- /* Connectix / VirtualPC */
- { VIR_STORAGE_FILE_VPC, "conectix", NULL,
- LV_BIG_ENDIAN, 12, 0x10000,
- 8 + 4 + 4 + 8 + 4 + 4 + 2 + 2 + 4, 8, 1, -1, NULL},
+ [VIR_STORAGE_FILE_RAW] = { NULL, NULL, LV_LITTLE_ENDIAN, -1, 0, 0, 0, 0, 0, NULL },
+ [VIR_STORAGE_FILE_DIR] = { NULL, NULL, LV_LITTLE_ENDIAN, -1, 0, 0, 0, 0, 0, NULL },
+ [VIR_STORAGE_FILE_BOCHS] = {
+ /*"Bochs Virtual HD Image", */ /* Untested */ NULL,
+ NULL,
+ LV_LITTLE_ENDIAN, 64, 0x20000,
+ 32+16+16+4+4+4+4+4, 8, 1, -1, NULL
+ },
+ [VIR_STORAGE_FILE_CLOOP] = {
+ /*"#!/bin/sh\n#V2.0 Format\nmodprobe cloop file=$0 && mount -r -t iso9660 /dev/cloop $1\n", */ /* Untested */ NULL,
+ NULL,
+ LV_LITTLE_ENDIAN, -1, 0,
+ -1, 0, 0, -1, NULL
+ },
+ [VIR_STORAGE_FILE_COW] = {
+ "OOOM", NULL,
+ LV_BIG_ENDIAN, 4, 2,
+ 4+4+1024+4, 8, 1, -1, cowGetBackingStore
+ },
+ [VIR_STORAGE_FILE_DMG] = {
+ NULL, /* XXX QEMU says there's no magic for dmg, but we should check... */
+ ".dmg",
+ 0, -1, 0,
+ -1, 0, 0, -1, NULL
+ },
+ [VIR_STORAGE_FILE_ISO] = {
+ NULL, /* XXX there's probably some magic for iso we can validate too... */
+ ".iso",
+ 0, -1, 0,
+ -1, 0, 0, -1, NULL
+ },
+ [VIR_STORAGE_FILE_QCOW] = {
+ "QFI", NULL,
+ LV_BIG_ENDIAN, 4, 1,
+ QCOWX_HDR_IMAGE_SIZE, 8, 1, QCOW1_HDR_CRYPT, qcow1GetBackingStore,
+ },
+ [VIR_STORAGE_FILE_QCOW2] = {
+ "QFI", NULL,
+ LV_BIG_ENDIAN, 4, 2,
+ QCOWX_HDR_IMAGE_SIZE, 8, 1, QCOW2_HDR_CRYPT, qcow2GetBackingStore,
+ },
+ [VIR_STORAGE_FILE_VMDK] = {
+ "KDMV", NULL,
+ LV_LITTLE_ENDIAN, 4, 1,
+ 4+4+4, 8, 512, -1, vmdk4GetBackingStore
+ },
+ [VIR_STORAGE_FILE_VPC] = {
+ "conectix", NULL,
+ LV_BIG_ENDIAN, 12, 0x10000,
+ 8 + 4 + 4 + 8 + 4 + 4 + 2 + 2 + 4, 8, 1, -1, NULL
+ },
};
+verify(ARRAY_CARDINALITY(fileTypeInfo) == VIR_STORAGE_FILE_LAST);
static int
cowGetBackingStore(char **res,
@@ -506,7 +506,7 @@ virStorageFileGetMetadataFromFD(const char *path,
}
/* Validation passed, we know the file format now */
- meta->format = fileTypeInfo[i].type;
+ meta->format = i;
if (fileTypeInfo[i].getBackingStore != NULL) {
char *backing;
int backingFormat;
@@ -546,7 +546,7 @@ virStorageFileGetMetadataFromFD(const char *path,
if (!virFileHasSuffix(path, fileTypeInfo[i].extension))
continue;
- meta->format = fileTypeInfo[i].type;
+ meta->format = i;
return 0;
}
--
1.7.1.1
@@ -0,0 +1,585 @@
From 57482ca0be29e9e92e242c9acb577e0b770c01d1 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/11] 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 | 460 +++++++++++++++++++++++++++++++++-------------
src/util/storage_file.h | 4 +
3 files changed, 335 insertions(+), 131 deletions(-)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 778ceb1..4607f49 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -628,6 +628,8 @@ virStorageGenerateQcowPassphrase;
# storage_file.h
virStorageFileFormatTypeToString;
virStorageFileFormatTypeFromString;
+virStorageFileProbeFormat;
+virStorageFileProbeFormatFromFD;
virStorageFileGetMetadata;
virStorageFileGetMetadataFromFD;
virStorageFileIsSharedFS;
diff --git a/src/util/storage_file.c b/src/util/storage_file.c
index df0e3a1..221268b 100644
--- a/src/util/storage_file.c
+++ b/src/util/storage_file.c
@@ -104,6 +104,9 @@ static int vmdk4GetBackingStore(char **, int *,
#define QCOW2_HDR_EXTENSION_END 0
#define QCOW2_HDR_EXTENSION_BACKING_FORMAT 0xE2792ACA
+/* VMDK needs at least this to find backing store,
+ * other formats are less */
+#define STORAGE_MAX_HEAD (20*512)
static struct FileTypeInfo const fileTypeInfo[] = {
@@ -349,9 +352,14 @@ vmdk4GetBackingStore(char **res,
size_t buf_size)
{
static const char prefix[] = "parentFileNameHint=\"";
-
- char desc[20*512 + 1], *start, *end;
+ char *desc, *start, *end;
size_t len;
+ int ret = BACKING_STORE_ERROR;
+
+ if (VIR_ALLOC_N(desc, STORAGE_MAX_HEAD + 1) < 0) {
+ virReportOOMError();
+ goto cleanup;
+ }
*res = NULL;
/*
@@ -363,29 +371,42 @@ vmdk4GetBackingStore(char **res,
*/
*format = VIR_STORAGE_FILE_AUTO;
- if (buf_size <= 0x200)
- return BACKING_STORE_INVALID;
+ if (buf_size <= 0x200) {
+ ret = BACKING_STORE_INVALID;
+ goto cleanup;
+ }
len = buf_size - 0x200;
- if (len > sizeof(desc) - 1)
- len = sizeof(desc) - 1;
+ if (len > STORAGE_MAX_HEAD)
+ len = STORAGE_MAX_HEAD;
memcpy(desc, buf + 0x200, len);
desc[len] = '\0';
start = strstr(desc, prefix);
- if (start == NULL)
- return BACKING_STORE_OK;
+ if (start == NULL) {
+ ret = BACKING_STORE_OK;
+ goto cleanup;
+ }
start += strlen(prefix);
end = strchr(start, '"');
- if (end == NULL)
- return BACKING_STORE_INVALID;
- if (end == start)
- return BACKING_STORE_OK;
+ if (end == NULL) {
+ ret = BACKING_STORE_INVALID;
+ goto cleanup;
+ }
+ if (end == start) {
+ ret = BACKING_STORE_OK;
+ goto cleanup;
+ }
*end = '\0';
*res = strdup(start);
if (*res == NULL) {
virReportOOMError();
- return BACKING_STORE_ERROR;
+ goto cleanup;
}
- return BACKING_STORE_OK;
+
+ ret = BACKING_STORE_OK;
+
+cleanup:
+ VIR_FREE(desc);
+ return ret;
}
/**
@@ -411,148 +432,325 @@ absolutePathFromBaseFile(const char *base_file, const char *path)
return res;
}
-/**
- * Probe the header of a file to determine what type of disk image
- * it is, and info about its capacity if available.
- */
-int
-virStorageFileGetMetadataFromFD(const char *path,
- int fd,
- virStorageFileMetadata *meta)
+
+static bool
+virStorageFileMatchesMagic(int format,
+ unsigned char *buf,
+ size_t buflen)
{
- unsigned char head[20*512]; /* vmdk4GetBackingStore needs this much. */
- int len, i;
+ int mlen;
- memset(meta, 0, sizeof (*meta));
+ if (fileTypeInfo[format].magic == NULL)
+ return false;
- /* If all else fails, call it a raw file */
- meta->format = VIR_STORAGE_FILE_RAW;
+ /* Validate magic data */
+ mlen = strlen(fileTypeInfo[format].magic);
+ if (mlen > buflen)
+ return false;
- if ((len = read(fd, head, sizeof(head))) < 0) {
- virReportSystemError(errno, _("cannot read header '%s'"), path);
- return -1;
+ if (memcmp(buf, fileTypeInfo[format].magic, mlen) != 0)
+ return false;
+
+ return true;
+}
+
+
+static bool
+virStorageFileMatchesExtension(int format,
+ const char *path)
+{
+ if (fileTypeInfo[format].extension == NULL)
+ return false;
+
+ if (virFileHasSuffix(path, fileTypeInfo[format].extension))
+ return true;
+
+ return false;
+}
+
+
+static bool
+virStorageFileMatchesVersion(int format,
+ unsigned char *buf,
+ size_t buflen)
+{
+ int version;
+
+ /* Validate version number info */
+ if (fileTypeInfo[format].versionOffset == -1)
+ return false;
+
+ if ((fileTypeInfo[format].versionOffset + 4) > buflen)
+ return false;
+
+ if (fileTypeInfo[format].endian == LV_LITTLE_ENDIAN) {
+ version =
+ (buf[fileTypeInfo[format].versionOffset+3] << 24) |
+ (buf[fileTypeInfo[format].versionOffset+2] << 16) |
+ (buf[fileTypeInfo[format].versionOffset+1] << 8) |
+ (buf[fileTypeInfo[format].versionOffset]);
+ } else {
+ version =
+ (buf[fileTypeInfo[format].versionOffset] << 24) |
+ (buf[fileTypeInfo[format].versionOffset+1] << 16) |
+ (buf[fileTypeInfo[format].versionOffset+2] << 8) |
+ (buf[fileTypeInfo[format].versionOffset+3]);
}
+ if (version != fileTypeInfo[format].versionNumber)
+ return false;
- /* First check file magic */
- for (i = 0 ; i < ARRAY_CARDINALITY(fileTypeInfo) ; i++) {
- int mlen;
-
- if (fileTypeInfo[i].magic == NULL)
- continue;
-
- /* Validate magic data */
- mlen = strlen(fileTypeInfo[i].magic);
- if (mlen > len)
- continue;
- if (memcmp(head, fileTypeInfo[i].magic, mlen) != 0)
- continue;
-
- /* Validate version number info */
- if (fileTypeInfo[i].versionNumber != -1) {
- int version;
-
- if (fileTypeInfo[i].endian == LV_LITTLE_ENDIAN) {
- version = (head[fileTypeInfo[i].versionOffset+3] << 24) |
- (head[fileTypeInfo[i].versionOffset+2] << 16) |
- (head[fileTypeInfo[i].versionOffset+1] << 8) |
- head[fileTypeInfo[i].versionOffset];
- } else {
- version = (head[fileTypeInfo[i].versionOffset] << 24) |
- (head[fileTypeInfo[i].versionOffset+1] << 16) |
- (head[fileTypeInfo[i].versionOffset+2] << 8) |
- head[fileTypeInfo[i].versionOffset+3];
- }
- if (version != fileTypeInfo[i].versionNumber)
- continue;
- }
+ return true;
+}
- /* Optionally extract capacity from file */
- if (fileTypeInfo[i].sizeOffset != -1) {
- if (fileTypeInfo[i].endian == LV_LITTLE_ENDIAN) {
- meta->capacity =
- ((unsigned long long)head[fileTypeInfo[i].sizeOffset+7] << 56) |
- ((unsigned long long)head[fileTypeInfo[i].sizeOffset+6] << 48) |
- ((unsigned long long)head[fileTypeInfo[i].sizeOffset+5] << 40) |
- ((unsigned long long)head[fileTypeInfo[i].sizeOffset+4] << 32) |
- ((unsigned long long)head[fileTypeInfo[i].sizeOffset+3] << 24) |
- ((unsigned long long)head[fileTypeInfo[i].sizeOffset+2] << 16) |
- ((unsigned long long)head[fileTypeInfo[i].sizeOffset+1] << 8) |
- ((unsigned long long)head[fileTypeInfo[i].sizeOffset]);
- } else {
- meta->capacity =
- ((unsigned long long)head[fileTypeInfo[i].sizeOffset] << 56) |
- ((unsigned long long)head[fileTypeInfo[i].sizeOffset+1] << 48) |
- ((unsigned long long)head[fileTypeInfo[i].sizeOffset+2] << 40) |
- ((unsigned long long)head[fileTypeInfo[i].sizeOffset+3] << 32) |
- ((unsigned long long)head[fileTypeInfo[i].sizeOffset+4] << 24) |
- ((unsigned long long)head[fileTypeInfo[i].sizeOffset+5] << 16) |
- ((unsigned long long)head[fileTypeInfo[i].sizeOffset+6] << 8) |
- ((unsigned long long)head[fileTypeInfo[i].sizeOffset+7]);
- }
- /* Avoid unlikely, but theoretically possible overflow */
- if (meta->capacity > (ULLONG_MAX / fileTypeInfo[i].sizeMultiplier))
- continue;
- meta->capacity *= fileTypeInfo[i].sizeMultiplier;
- }
- if (fileTypeInfo[i].qcowCryptOffset != -1) {
- int crypt_format;
+static int
+virStorageFileGetMetadataFromBuf(int format,
+ const char *path,
+ unsigned char *buf,
+ size_t buflen,
+ virStorageFileMetadata *meta)
+{
+ /* XXX we should consider moving virStorageBackendUpdateVolInfo
+ * code into this method, for non-magic files
+ */
+ if (!fileTypeInfo[format].magic) {
+ return 0;
+ }
- crypt_format = (head[fileTypeInfo[i].qcowCryptOffset] << 24) |
- (head[fileTypeInfo[i].qcowCryptOffset+1] << 16) |
- (head[fileTypeInfo[i].qcowCryptOffset+2] << 8) |
- head[fileTypeInfo[i].qcowCryptOffset+3];
- meta->encrypted = crypt_format != 0;
+ /* Optionally extract capacity from file */
+ if (fileTypeInfo[format].sizeOffset != -1) {
+ if ((fileTypeInfo[format].sizeOffset + 8) > buflen)
+ return 1;
+
+ if (fileTypeInfo[format].endian == LV_LITTLE_ENDIAN) {
+ meta->capacity =
+ ((unsigned long long)buf[fileTypeInfo[format].sizeOffset+7] << 56) |
+ ((unsigned long long)buf[fileTypeInfo[format].sizeOffset+6] << 48) |
+ ((unsigned long long)buf[fileTypeInfo[format].sizeOffset+5] << 40) |
+ ((unsigned long long)buf[fileTypeInfo[format].sizeOffset+4] << 32) |
+ ((unsigned long long)buf[fileTypeInfo[format].sizeOffset+3] << 24) |
+ ((unsigned long long)buf[fileTypeInfo[format].sizeOffset+2] << 16) |
+ ((unsigned long long)buf[fileTypeInfo[format].sizeOffset+1] << 8) |
+ ((unsigned long long)buf[fileTypeInfo[format].sizeOffset]);
+ } else {
+ meta->capacity =
+ ((unsigned long long)buf[fileTypeInfo[format].sizeOffset] << 56) |
+ ((unsigned long long)buf[fileTypeInfo[format].sizeOffset+1] << 48) |
+ ((unsigned long long)buf[fileTypeInfo[format].sizeOffset+2] << 40) |
+ ((unsigned long long)buf[fileTypeInfo[format].sizeOffset+3] << 32) |
+ ((unsigned long long)buf[fileTypeInfo[format].sizeOffset+4] << 24) |
+ ((unsigned long long)buf[fileTypeInfo[format].sizeOffset+5] << 16) |
+ ((unsigned long long)buf[fileTypeInfo[format].sizeOffset+6] << 8) |
+ ((unsigned long long)buf[fileTypeInfo[format].sizeOffset+7]);
}
+ /* Avoid unlikely, but theoretically possible overflow */
+ if (meta->capacity > (ULLONG_MAX / fileTypeInfo[format].sizeMultiplier))
+ return 1;
+ meta->capacity *= fileTypeInfo[format].sizeMultiplier;
+ }
- /* Validation passed, we know the file format now */
- meta->format = i;
- if (fileTypeInfo[i].getBackingStore != NULL) {
- char *backing;
- int backingFormat;
+ if (fileTypeInfo[format].qcowCryptOffset != -1) {
+ int crypt_format;
- switch (fileTypeInfo[i].getBackingStore(&backing,
- &backingFormat,
- head, len)) {
- case BACKING_STORE_OK:
- break;
+ crypt_format =
+ (buf[fileTypeInfo[format].qcowCryptOffset] << 24) |
+ (buf[fileTypeInfo[format].qcowCryptOffset+1] << 16) |
+ (buf[fileTypeInfo[format].qcowCryptOffset+2] << 8) |
+ (buf[fileTypeInfo[format].qcowCryptOffset+3]);
+ meta->encrypted = crypt_format != 0;
+ }
- case BACKING_STORE_INVALID:
- continue;
+ if (fileTypeInfo[format].getBackingStore != NULL) {
+ char *backing;
+ int backingFormat;
+ int ret = fileTypeInfo[format].getBackingStore(&backing,
+ &backingFormat,
+ buf, buflen);
+ if (ret == BACKING_STORE_INVALID)
+ return 1;
+
+ if (ret == BACKING_STORE_ERROR)
+ return -1;
- case BACKING_STORE_ERROR:
+ if (backing != NULL) {
+ meta->backingStore = absolutePathFromBaseFile(path, backing);
+ VIR_FREE(backing);
+ if (meta->backingStore == NULL) {
+ virReportOOMError();
return -1;
}
- if (backing != NULL) {
- meta->backingStore = absolutePathFromBaseFile(path, backing);
- VIR_FREE(backing);
- if (meta->backingStore == NULL) {
- virReportOOMError();
- return -1;
- }
- meta->backingStoreFormat = backingFormat;
- } else {
- meta->backingStoreFormat = VIR_STORAGE_FILE_AUTO;
- }
+ meta->backingStoreFormat = backingFormat;
+ } else {
+ meta->backingStore = NULL;
+ meta->backingStoreFormat = VIR_STORAGE_FILE_AUTO;
+ }
+ }
+
+ return 0;
+}
+
+
+static int
+virStorageFileProbeFormatFromBuf(const char *path,
+ unsigned char *buf,
+ size_t buflen)
+{
+ int format = VIR_STORAGE_FILE_RAW;
+ int i;
+
+ /* First check file magic */
+ for (i = 0 ; i < VIR_STORAGE_FILE_LAST ; i++) {
+ if (virStorageFileMatchesMagic(i, buf, buflen) &&
+ virStorageFileMatchesVersion(i, buf, buflen)) {
+ format = i;
+ goto cleanup;
}
- return 0;
}
/* No magic, so check file extension */
- for (i = 0 ; i < ARRAY_CARDINALITY(fileTypeInfo) ; i++) {
- if (fileTypeInfo[i].extension == NULL)
- continue;
+ for (i = 0 ; i < VIR_STORAGE_FILE_LAST ; i++) {
+ if (virStorageFileMatchesExtension(i, path)) {
+ format = i;
+ goto cleanup;
+ }
+ }
- if (!virFileHasSuffix(path, fileTypeInfo[i].extension))
- continue;
+cleanup:
+ return format;
+}
- meta->format = i;
- return 0;
+
+/**
+ * virStorageFileProbeFormatFromFD:
+ *
+ * Probe for the format of 'fd' (which is an open file descriptor
+ * pointing to 'path'), returning the detected disk format.
+ *
+ * Callers are advised never to trust the returned 'format'
+ * unless it is listed as VIR_STORAGE_FILE_RAW, since a
+ * malicious guest can turn a file into any other non-raw
+ * format at will.
+ *
+ * Best option: Don't use this function
+ */
+int
+virStorageFileProbeFormatFromFD(const char *path, int fd)
+{
+ unsigned char *head;
+ ssize_t len = STORAGE_MAX_HEAD;
+ int ret = -1;
+
+ if (VIR_ALLOC_N(head, len) < 0) {
+ virReportOOMError();
+ return -1;
}
- return 0;
+ if (lseek(fd, 0, SEEK_SET) == (off_t)-1) {
+ virReportSystemError(errno, _("cannot set to start of '%s'"), path);
+ goto cleanup;
+ }
+
+ if ((len = read(fd, head, len)) < 0) {
+ virReportSystemError(errno, _("cannot read header '%s'"), path);
+ goto cleanup;
+ }
+
+ ret = virStorageFileProbeFormatFromBuf(path, head, len);
+
+cleanup:
+ VIR_FREE(head);
+ return ret;
+}
+
+
+/**
+ * virStorageFileProbeFormat:
+ *
+ * Probe for the format of 'path', returning the detected
+ * disk format.
+ *
+ * Callers are advised never to trust the returned 'format'
+ * unless it is listed as VIR_STORAGE_FILE_RAW, since a
+ * malicious guest can turn a raw file into any other non-raw
+ * format at will.
+ *
+ * Best option: Don't use this function
+ */
+int
+virStorageFileProbeFormat(const char *path)
+{
+ int fd, ret;
+
+ if ((fd = open(path, O_RDONLY)) < 0) {
+ virReportSystemError(errno, _("cannot open file '%s'"), path);
+ return -1;
+ }
+
+ ret = virStorageFileProbeFormatFromFD(path, fd);
+
+ close(fd);
+
+ return ret;
}
+/**
+ * virStorageFileGetMetadataFromFD:
+ *
+ * Probe for the format of 'fd' (which is an open file descriptor
+ * for the file 'path'), filling 'meta' with the detected
+ * format and other associated metadata.
+ *
+ * Callers are advised never to trust the returned 'meta->format'
+ * unless it is listed as VIR_STORAGE_FILE_RAW, since a
+ * malicious guest can turn a raw file into any other non-raw
+ * format at will.
+ */
+int
+virStorageFileGetMetadataFromFD(const char *path,
+ int fd,
+ virStorageFileMetadata *meta)
+{
+ unsigned char *head;
+ ssize_t len = STORAGE_MAX_HEAD;
+ int ret = -1;
+
+ if (VIR_ALLOC_N(head, len) < 0) {
+ virReportOOMError();
+ return -1;
+ }
+
+ memset(meta, 0, sizeof (*meta));
+
+ if (lseek(fd, 0, SEEK_SET) == (off_t)-1) {
+ virReportSystemError(errno, _("cannot set to start of '%s'"), path);
+ goto cleanup;
+ }
+
+ if ((len = read(fd, head, len)) < 0) {
+ virReportSystemError(errno, _("cannot read header '%s'"), path);
+ goto cleanup;
+ }
+
+ meta->format = virStorageFileProbeFormatFromBuf(path, head, len);
+
+ ret = virStorageFileGetMetadataFromBuf(meta->format, path, head, len, meta);
+
+cleanup:
+ VIR_FREE(head);
+ return ret;
+}
+
+/**
+ * virStorageFileGetMetadata:
+ *
+ * Probe for the format of 'path', filling 'meta' with the detected
+ * format and other associated metadata.
+ *
+ * Callers are advised never to trust the returned 'meta->format'
+ * unless it is listed as VIR_STORAGE_FILE_RAW, since a
+ * malicious guest can turn a raw file into any other non-raw
+ * format at will.
+ */
int
virStorageFileGetMetadata(const char *path,
virStorageFileMetadata *meta)
diff --git a/src/util/storage_file.h b/src/util/storage_file.h
index 6328ba7..3420d44 100644
--- a/src/util/storage_file.h
+++ b/src/util/storage_file.h
@@ -57,6 +57,10 @@ typedef struct _virStorageFileMetadata {
# define DEV_BSIZE 512
# endif
+int virStorageFileProbeFormat(const char *path);
+int virStorageFileProbeFormatFromFD(const char *path,
+ int fd);
+
int virStorageFileGetMetadata(const char *path,
virStorageFileMetadata *meta);
int virStorageFileGetMetadataFromFD(const char *path,
--
1.7.1.1
@@ -0,0 +1,285 @@
From 726a63a437efd96510ce316bf30d16f213d4db27 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/11] 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
calling virStorageFileGetMetadata.
* src/util/storage_file.h, src/util/storage_file.c: Remove format
from virStorageFileMeta struct & require it to be passed into
method.
---
src/qemu/qemu_driver.c | 27 +++++++++++++++++---
src/qemu/qemu_security_dac.c | 4 ++-
src/security/security_selinux.c | 4 ++-
src/security/virt-aa-helper.c | 4 ++-
src/storage/storage_backend_fs.c | 11 ++++++--
src/util/storage_file.c | 50 +++++++++++++++++++++++++------------
src/util/storage_file.h | 3 +-
7 files changed, 76 insertions(+), 27 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 487bfa3..97f2990 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -3069,7 +3069,9 @@ static int qemuSetupDiskCgroup(virCgroupPtr cgroup,
}
}
- rc = virStorageFileGetMetadata(path, &meta);
+ rc = virStorageFileGetMetadata(path,
+ VIR_STORAGE_FILE_AUTO,
+ &meta);
if (rc < 0)
VIR_WARN("Unable to lookup parent image for %s", path);
@@ -3119,7 +3121,9 @@ static int qemuTeardownDiskCgroup(virCgroupPtr cgroup,
}
}
- rc = virStorageFileGetMetadata(path, &meta);
+ rc = virStorageFileGetMetadata(path,
+ VIR_STORAGE_FILE_AUTO,
+ &meta);
if (rc < 0)
VIR_WARN("Unable to lookup parent image for %s", path);
@@ -9614,6 +9618,7 @@ static int qemuDomainGetBlockInfo(virDomainPtr dom,
virDomainDiskDefPtr disk = NULL;
struct stat sb;
int i;
+ int format;
virCheckFlags(0, -1);
@@ -9658,7 +9663,21 @@ static int qemuDomainGetBlockInfo(virDomainPtr dom,
}
/* Probe for magic formats */
- if (virStorageFileGetMetadataFromFD(path, fd, &meta) < 0)
+ if (disk->driverType) {
+ if ((format = virStorageFileFormatTypeFromString(disk->driverType)) < 0) {
+ qemuReportError(VIR_ERR_INTERNAL_ERROR,
+ _("unknown disk format %s for %s"),
+ disk->driverType, disk->src);
+ goto cleanup;
+ }
+ } else {
+ if ((format = virStorageFileProbeFormat(disk->src)) < 0)
+ goto cleanup;
+ }
+
+ if (virStorageFileGetMetadataFromFD(path, fd,
+ format,
+ &meta) < 0)
goto cleanup;
/* Get info for normal formats */
@@ -9706,7 +9725,7 @@ static int qemuDomainGetBlockInfo(virDomainPtr dom,
highest allocated extent from QEMU */
if (virDomainObjIsActive(vm) &&
disk->type == VIR_DOMAIN_DISK_TYPE_BLOCK &&
- meta.format != VIR_STORAGE_FILE_RAW &&
+ format != VIR_STORAGE_FILE_RAW &&
S_ISBLK(sb.st_mode)) {
qemuDomainObjPrivatePtr priv = vm->privateData;
if (qemuDomainObjBeginJob(vm) < 0)
diff --git a/src/qemu/qemu_security_dac.c b/src/qemu/qemu_security_dac.c
index 95015b0..acfe48e 100644
--- a/src/qemu/qemu_security_dac.c
+++ b/src/qemu/qemu_security_dac.c
@@ -115,7 +115,9 @@ qemuSecurityDACSetSecurityImageLabel(virDomainObjPtr vm ATTRIBUTE_UNUSED,
virStorageFileMetadata meta;
int ret;
- ret = virStorageFileGetMetadata(path, &meta);
+ ret = virStorageFileGetMetadata(path,
+ VIR_STORAGE_FILE_AUTO,
+ &meta);
if (path != disk->src)
VIR_FREE(path);
diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c
index e5eef19..5c0f002 100644
--- a/src/security/security_selinux.c
+++ b/src/security/security_selinux.c
@@ -457,7 +457,9 @@ SELinuxSetSecurityImageLabel(virDomainObjPtr vm,
virStorageFileMetadata meta;
int ret;
- ret = virStorageFileGetMetadata(path, &meta);
+ ret = virStorageFileGetMetadata(path,
+ VIR_STORAGE_FILE_AUTO,
+ &meta);
if (path != disk->src)
VIR_FREE(path);
diff --git a/src/security/virt-aa-helper.c b/src/security/virt-aa-helper.c
index c66f107..2c045e6 100644
--- a/src/security/virt-aa-helper.c
+++ b/src/security/virt-aa-helper.c
@@ -830,7 +830,9 @@ get_files(vahControl * ctl)
do {
virStorageFileMetadata meta;
- ret = virStorageFileGetMetadata(path, &meta);
+ ret = virStorageFileGetMetadata(path,
+ VIR_STORAGE_FILE_AUTO,
+ &meta);
if (path != ctl->def->disks[i]->src)
VIR_FREE(path);
diff --git a/src/storage/storage_backend_fs.c b/src/storage/storage_backend_fs.c
index f0cd770..d3ac0fe 100644
--- a/src/storage/storage_backend_fs.c
+++ b/src/storage/storage_backend_fs.c
@@ -75,14 +75,19 @@ virStorageBackendProbeTarget(virStorageVolTargetPtr target,
memset(&meta, 0, sizeof(meta));
- if (virStorageFileGetMetadataFromFD(target->path, fd, &meta) < 0) {
+ if ((target->format = virStorageFileProbeFormatFromFD(target->path, fd)) < 0) {
close(fd);
return -1;
}
- close(fd);
+ if (virStorageFileGetMetadataFromFD(target->path, fd,
+ target->format,
+ &meta) < 0) {
+ close(fd);
+ return -1;
+ }
- target->format = meta.format;
+ close(fd);
if (backingStore) {
*backingStore = meta.backingStore;
diff --git a/src/util/storage_file.c b/src/util/storage_file.c
index 221268b..9712d92 100644
--- a/src/util/storage_file.c
+++ b/src/util/storage_file.c
@@ -696,18 +696,23 @@ virStorageFileProbeFormat(const char *path)
/**
* virStorageFileGetMetadataFromFD:
*
- * Probe for the format of 'fd' (which is an open file descriptor
- * for the file 'path'), filling 'meta' with the detected
- * format and other associated metadata.
+ * Extract metadata about the storage volume with the specified
+ * image format. If image format is VIR_STORAGE_FILE_AUTO, it
+ * will probe to automatically identify the format.
*
- * Callers are advised never to trust the returned 'meta->format'
- * unless it is listed as VIR_STORAGE_FILE_RAW, since a
- * malicious guest can turn a raw file into any other non-raw
- * format at will.
+ * Callers are advised never to use VIR_STORAGE_FILE_AUTO as a
+ * format, since a malicious guest can turn a raw file into any
+ * other non-raw format at will.
+ *
+ * If the returned meta.backingStoreFormat is VIR_STORAGE_FILE_AUTO
+ * it indicates the image didn't specify an explicit format for its
+ * backing store. Callers are advised against probing for the
+ * backing store format in this case.
*/
int
virStorageFileGetMetadataFromFD(const char *path,
int fd,
+ int format,
virStorageFileMetadata *meta)
{
unsigned char *head;
@@ -731,9 +736,16 @@ virStorageFileGetMetadataFromFD(const char *path,
goto cleanup;
}
- meta->format = virStorageFileProbeFormatFromBuf(path, head, len);
+ if (format == VIR_STORAGE_FILE_AUTO)
+ format = virStorageFileProbeFormatFromBuf(path, head, len);
+
+ if (format < 0 ||
+ format >= VIR_STORAGE_FILE_LAST) {
+ virReportSystemError(EINVAL, _("unknown storage file format %d"), format);
+ return -1;
+ }
- ret = virStorageFileGetMetadataFromBuf(meta->format, path, head, len, meta);
+ ret = virStorageFileGetMetadataFromBuf(format, path, head, len, meta);
cleanup:
VIR_FREE(head);
@@ -743,16 +755,22 @@ cleanup:
/**
* virStorageFileGetMetadata:
*
- * Probe for the format of 'path', filling 'meta' with the detected
- * format and other associated metadata.
+ * Extract metadata about the storage volume with the specified
+ * image format. If image format is VIR_STORAGE_FILE_AUTO, it
+ * will probe to automatically identify the format.
*
- * Callers are advised never to trust the returned 'meta->format'
- * unless it is listed as VIR_STORAGE_FILE_RAW, since a
- * malicious guest can turn a raw file into any other non-raw
- * format at will.
+ * Callers are advised never to use VIR_STORAGE_FILE_AUTO as a
+ * format, since a malicious guest can turn a raw file into any
+ * other non-raw format at will.
+ *
+ * If the returned meta.backingStoreFormat is VIR_STORAGE_FILE_AUTO
+ * it indicates the image didn't specify an explicit format for its
+ * backing store. Callers are advised against probing for the
+ * backing store format in this case.
*/
int
virStorageFileGetMetadata(const char *path,
+ int format,
virStorageFileMetadata *meta)
{
int fd, ret;
@@ -762,7 +780,7 @@ virStorageFileGetMetadata(const char *path,
return -1;
}
- ret = virStorageFileGetMetadataFromFD(path, fd, meta);
+ ret = virStorageFileGetMetadataFromFD(path, fd, format, meta);
close(fd);
diff --git a/src/util/storage_file.h b/src/util/storage_file.h
index 3420d44..6853182 100644
--- a/src/util/storage_file.h
+++ b/src/util/storage_file.h
@@ -46,7 +46,6 @@ enum virStorageFileFormat {
VIR_ENUM_DECL(virStorageFileFormat);
typedef struct _virStorageFileMetadata {
- int format;
char *backingStore;
int backingStoreFormat;
unsigned long long capacity;
@@ -62,9 +61,11 @@ int virStorageFileProbeFormatFromFD(const char *path,
int fd);
int virStorageFileGetMetadata(const char *path,
+ int format,
virStorageFileMetadata *meta);
int virStorageFileGetMetadataFromFD(const char *path,
int fd,
+ int format,
virStorageFileMetadata *meta);
int virStorageFileIsSharedFS(const char *path);
--
1.7.1.1
+170
View File
@@ -0,0 +1,170 @@
From ac5067f1e2e98181ee0e9230f756697f50d853eb 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/11] 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(-)
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 378c06e..b20ca97 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -45,6 +45,7 @@
#include "macvtap.h"
#include "nwfilter_conf.h"
#include "ignore-value.h"
+#include "storage_file.h"
#define VIR_FROM_THIS VIR_FROM_DOMAIN
@@ -7273,4 +7274,102 @@ done:
}
+int virDomainDiskDefForeachPath(virDomainDiskDefPtr disk,
+ bool allowProbing,
+ bool ignoreOpenFailure,
+ virDomainDiskDefPathIterator iter,
+ void *opaque)
+{
+ virHashTablePtr paths;
+ int format;
+ int ret = -1;
+ size_t depth = 0;
+ char *nextpath = NULL;
+
+ if (!disk->src)
+ return 0;
+
+ if (disk->driverType) {
+ const char *formatStr = disk->driverType;
+ if (STREQ(formatStr, "aio"))
+ formatStr = "raw"; /* Xen compat */
+
+ if ((format = virStorageFileFormatTypeFromString(formatStr)) < 0) {
+ virDomainReportError(VIR_ERR_INTERNAL_ERROR,
+ _("unknown disk format '%s' for %s"),
+ disk->driverType, disk->src);
+ return -1;
+ }
+ } else {
+ if (allowProbing) {
+ format = VIR_STORAGE_FILE_AUTO;
+ } else {
+ virDomainReportError(VIR_ERR_INTERNAL_ERROR,
+ _("no disk format for %s and probing is disabled"),
+ disk->src);
+ return -1;
+ }
+ }
+
+ paths = virHashCreate(5);
+
+ do {
+ virStorageFileMetadata meta;
+ const char *path = nextpath ? nextpath : disk->src;
+ int fd;
+
+ if (iter(disk, path, depth, opaque) < 0)
+ goto cleanup;
+
+ if (virHashLookup(paths, path)) {
+ virDomainReportError(VIR_ERR_INTERNAL_ERROR,
+ _("backing store for %s is self-referential"),
+ disk->src);
+ goto cleanup;
+ }
+
+ if ((fd = open(path, O_RDONLY)) < 0) {
+ if (ignoreOpenFailure) {
+ char ebuf[1024];
+ VIR_WARN("Ignoring open failure on %s: %s", path,
+ virStrerror(errno, ebuf, sizeof(ebuf)));
+ break;
+ } else {
+ virReportSystemError(errno,
+ _("unable to open disk path %s"),
+ path);
+ goto cleanup;
+ }
+ }
+
+ if (virStorageFileGetMetadataFromFD(path, fd, format, &meta) < 0) {
+ close(fd);
+ goto cleanup;
+ }
+ close(fd);
+
+ if (virHashAddEntry(paths, path, (void*)0x1) < 0) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ depth++;
+ nextpath = meta.backingStore;
+
+ format = meta.backingStoreFormat;
+
+ if (format == VIR_STORAGE_FILE_AUTO &&
+ !allowProbing)
+ format = VIR_STORAGE_FILE_RAW; /* Stops further recursion */
+ } while (nextpath);
+
+ ret = 0;
+
+cleanup:
+ virHashFree(paths, NULL);
+ VIR_FREE(nextpath);
+
+ return ret;
+}
+
#endif /* ! PROXY */
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 01da17e..d46869e 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -1079,6 +1079,17 @@ int virDomainChrDefForeach(virDomainDefPtr def,
void *opaque);
+typedef int (*virDomainDiskDefPathIterator)(virDomainDiskDefPtr disk,
+ const char *path,
+ size_t depth,
+ void *opaque);
+
+int virDomainDiskDefForeachPath(virDomainDiskDefPtr disk,
+ bool allowProbing,
+ bool ignoreOpenFailure,
+ virDomainDiskDefPathIterator iter,
+ void *opaque);
+
VIR_ENUM_DECL(virDomainVirt)
VIR_ENUM_DECL(virDomainBoot)
VIR_ENUM_DECL(virDomainFeature)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 4607f49..b5f3695 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -225,6 +225,7 @@ virDomainSnapshotDefFormat;
virDomainSnapshotAssignDef;
virDomainObjAssignDef;
virDomainChrDefForeach;
+virDomainDiskDefForeachPath;
# domain_event.h
--
1.7.1.1
+506
View File
@@ -0,0 +1,506 @@
From 54c1bb731d2b19a46a594cf9682c022f1e1114d2 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/11] 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(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 97f2990..99aeffa 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -3040,107 +3040,82 @@ static const char *const defaultDeviceACL[] = {
#define DEVICE_PTY_MAJOR 136
#define DEVICE_SND_MAJOR 116
-static int qemuSetupDiskCgroup(virCgroupPtr cgroup,
- virDomainObjPtr vm,
- virDomainDiskDefPtr disk)
-{
- char *path = disk->src;
- int ret = -1;
- while (path != NULL) {
- virStorageFileMetadata meta;
- int rc;
+static int qemuSetupDiskPathAllow(virDomainDiskDefPtr disk ATTRIBUTE_UNUSED,
+ const char *path,
+ size_t depth ATTRIBUTE_UNUSED,
+ void *opaque)
+{
+ virCgroupPtr cgroup = opaque;
+ int rc;
- VIR_DEBUG("Process path '%s' for disk", path);
- rc = virCgroupAllowDevicePath(cgroup, path);
- if (rc != 0) {
- /* Get this for non-block devices */
- if (rc == -EINVAL) {
- VIR_DEBUG("Ignoring EINVAL for %s", path);
- } else if (rc == -EACCES) { /* Get this for root squash NFS */
- VIR_DEBUG("Ignoring EACCES for %s", path);
- } else {
- virReportSystemError(-rc,
- _("Unable to allow device %s for %s"),
- path, vm->def->name);
- if (path != disk->src)
- VIR_FREE(path);
- goto cleanup;
- }
+ VIR_DEBUG("Process path %s for disk", path);
+ /* XXX RO vs RW */
+ rc = virCgroupAllowDevicePath(cgroup, path);
+ if (rc != 0) {
+ /* Get this for non-block devices */
+ if (rc == -EINVAL) {
+ VIR_DEBUG("Ignoring EINVAL for %s", path);
+ } else if (rc == -EACCES) { /* Get this for root squash NFS */
+ VIR_DEBUG("Ignoring EACCES for %s", path);
+ } else {
+ virReportSystemError(-rc,
+ _("Unable to allow access for disk path %s"),
+ path);
+ return -1;
}
-
- rc = virStorageFileGetMetadata(path,
- VIR_STORAGE_FILE_AUTO,
- &meta);
- if (rc < 0)
- VIR_WARN("Unable to lookup parent image for %s", path);
-
- if (path != disk->src)
- VIR_FREE(path);
- path = NULL;
-
- if (rc < 0)
- break; /* Treating as non fatal */
-
- path = meta.backingStore;
}
+ return 0;
+}
- ret = 0;
-cleanup:
- return ret;
+static int qemuSetupDiskCgroup(virCgroupPtr cgroup,
+ virDomainDiskDefPtr disk)
+{
+ return virDomainDiskDefForeachPath(disk,
+ true,
+ true,
+ qemuSetupDiskPathAllow,
+ cgroup);
}
-static int qemuTeardownDiskCgroup(virCgroupPtr cgroup,
- virDomainObjPtr vm,
- virDomainDiskDefPtr disk)
+static int qemuTeardownDiskPathDeny(virDomainDiskDefPtr disk ATTRIBUTE_UNUSED,
+ const char *path,
+ size_t depth ATTRIBUTE_UNUSED,
+ void *opaque)
{
- char *path = disk->src;
- int ret = -1;
-
- while (path != NULL) {
- virStorageFileMetadata meta;
- int rc;
+ virCgroupPtr cgroup = opaque;
+ int rc;
- VIR_DEBUG("Process path '%s' for disk", path);
- rc = virCgroupDenyDevicePath(cgroup, path);
- if (rc != 0) {
- /* Get this for non-block devices */
- if (rc == -EINVAL) {
- VIR_DEBUG("Ignoring EINVAL for %s", path);
- } else if (rc == -EACCES) { /* Get this for root squash NFS */
- VIR_DEBUG("Ignoring EACCES for %s", path);
- } else {
- virReportSystemError(-rc,
- _("Unable to deny device %s for %s"),
- path, vm->def->name);
- if (path != disk->src)
- VIR_FREE(path);
- goto cleanup;
- }
+ VIR_DEBUG("Process path %s for disk", path);
+ /* XXX RO vs RW */
+ rc = virCgroupDenyDevicePath(cgroup, path);
+ if (rc != 0) {
+ /* Get this for non-block devices */
+ if (rc == -EINVAL) {
+ VIR_DEBUG("Ignoring EINVAL for %s", path);
+ } else if (rc == -EACCES) { /* Get this for root squash NFS */
+ VIR_DEBUG("Ignoring EACCES for %s", path);
+ } else {
+ virReportSystemError(-rc,
+ _("Unable to allow access for disk path %s"),
+ path);
+ return -1;
}
-
- rc = virStorageFileGetMetadata(path,
- VIR_STORAGE_FILE_AUTO,
- &meta);
- if (rc < 0)
- VIR_WARN("Unable to lookup parent image for %s", path);
-
- if (path != disk->src)
- VIR_FREE(path);
- path = NULL;
-
- if (rc < 0)
- break; /* Treating as non fatal */
-
- path = meta.backingStore;
}
+ return 0;
+}
- ret = 0;
-cleanup:
- return ret;
+static int qemuTeardownDiskCgroup(virCgroupPtr cgroup,
+ virDomainDiskDefPtr disk)
+{
+ return virDomainDiskDefForeachPath(disk,
+ true,
+ true,
+ qemuTeardownDiskPathDeny,
+ cgroup);
}
@@ -3204,7 +3179,7 @@ static int qemuSetupCgroup(struct qemud_driver *driver,
}
for (i = 0; i < vm->def->ndisks ; i++) {
- if (qemuSetupDiskCgroup(cgroup, vm, vm->def->disks[i]) < 0)
+ if (qemuSetupDiskCgroup(cgroup, vm->def->disks[i]) < 0)
goto cleanup;
}
@@ -8035,7 +8010,7 @@ static int qemudDomainAttachDevice(virDomainPtr dom,
vm->def->name);
goto endjob;
}
- if (qemuSetupDiskCgroup(cgroup, vm, dev->data.disk) < 0)
+ if (qemuSetupDiskCgroup(cgroup, dev->data.disk) < 0)
goto endjob;
}
@@ -8080,7 +8055,7 @@ static int qemudDomainAttachDevice(virDomainPtr dom,
/* Fallthrough */
}
if (ret != 0 && cgroup) {
- if (qemuTeardownDiskCgroup(cgroup, vm, dev->data.disk) < 0)
+ if (qemuTeardownDiskCgroup(cgroup, dev->data.disk) < 0)
VIR_WARN("Failed to teardown cgroup for disk path %s",
NULLSTR(dev->data.disk->src));
}
@@ -8280,7 +8255,7 @@ static int qemuDomainUpdateDeviceFlags(virDomainPtr dom,
vm->def->name);
goto endjob;
}
- if (qemuSetupDiskCgroup(cgroup, vm, dev->data.disk) < 0)
+ if (qemuSetupDiskCgroup(cgroup, dev->data.disk) < 0)
goto endjob;
}
@@ -8303,7 +8278,7 @@ static int qemuDomainUpdateDeviceFlags(virDomainPtr dom,
}
if (ret != 0 && cgroup) {
- if (qemuTeardownDiskCgroup(cgroup, vm, dev->data.disk) < 0)
+ if (qemuTeardownDiskCgroup(cgroup, dev->data.disk) < 0)
VIR_WARN("Failed to teardown cgroup for disk path %s",
NULLSTR(dev->data.disk->src));
}
@@ -8430,7 +8405,7 @@ static int qemudDomainDetachPciDiskDevice(struct qemud_driver *driver,
VIR_WARN("Unable to restore security label on %s", dev->data.disk->src);
if (cgroup != NULL) {
- if (qemuTeardownDiskCgroup(cgroup, vm, dev->data.disk) < 0)
+ if (qemuTeardownDiskCgroup(cgroup, dev->data.disk) < 0)
VIR_WARN("Failed to teardown cgroup for disk path %s",
NULLSTR(dev->data.disk->src));
}
@@ -8493,7 +8468,7 @@ static int qemudDomainDetachSCSIDiskDevice(struct qemud_driver *driver,
VIR_WARN("Unable to restore security label on %s", dev->data.disk->src);
if (cgroup != NULL) {
- if (qemuTeardownDiskCgroup(cgroup, vm, dev->data.disk) < 0)
+ if (qemuTeardownDiskCgroup(cgroup, dev->data.disk) < 0)
VIR_WARN("Failed to teardown cgroup for disk path %s",
NULLSTR(dev->data.disk->src));
}
diff --git a/src/qemu/qemu_security_dac.c b/src/qemu/qemu_security_dac.c
index acfe48e..770010d 100644
--- a/src/qemu/qemu_security_dac.c
+++ b/src/qemu/qemu_security_dac.c
@@ -98,45 +98,28 @@ err:
static int
+qemuSecurityDACSetSecurityFileLabel(virDomainDiskDefPtr disk ATTRIBUTE_UNUSED,
+ const char *path,
+ size_t depth ATTRIBUTE_UNUSED,
+ void *opaque ATTRIBUTE_UNUSED)
+{
+ return qemuSecurityDACSetOwnership(path, driver->user, driver->group);
+}
+
+
+static int
qemuSecurityDACSetSecurityImageLabel(virDomainObjPtr vm ATTRIBUTE_UNUSED,
virDomainDiskDefPtr disk)
{
- const char *path;
-
if (!driver->privileged || !driver->dynamicOwnership)
return 0;
- if (!disk->src)
- return 0;
-
- path = disk->src;
- do {
- virStorageFileMetadata meta;
- int ret;
-
- ret = virStorageFileGetMetadata(path,
- VIR_STORAGE_FILE_AUTO,
- &meta);
-
- if (path != disk->src)
- VIR_FREE(path);
- path = NULL;
-
- if (ret < 0)
- return -1;
-
- if (meta.backingStore != NULL &&
- qemuSecurityDACSetOwnership(meta.backingStore,
- driver->user, driver->group) < 0) {
- VIR_FREE(meta.backingStore);
- return -1;
- }
-
- path = meta.backingStore;
- } while (path != NULL);
-
- return qemuSecurityDACSetOwnership(disk->src, driver->user, driver->group);
+ return virDomainDiskDefForeachPath(disk,
+ true,
+ false,
+ qemuSecurityDACSetSecurityFileLabel,
+ NULL);
}
diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c
index 5c0f002..d191118 100644
--- a/src/security/security_selinux.c
+++ b/src/security/security_selinux.c
@@ -439,54 +439,43 @@ SELinuxRestoreSecurityImageLabel(virDomainObjPtr vm,
static int
+SELinuxSetSecurityFileLabel(virDomainDiskDefPtr disk,
+ const char *path,
+ size_t depth,
+ void *opaque)
+{
+ const virSecurityLabelDefPtr secdef = opaque;
+
+ if (depth == 0) {
+ if (disk->shared) {
+ return SELinuxSetFilecon(path, default_image_context);
+ } else if (disk->readonly) {
+ return SELinuxSetFilecon(path, default_content_context);
+ } else if (secdef->imagelabel) {
+ return SELinuxSetFilecon(path, secdef->imagelabel);
+ } else {
+ return 0;
+ }
+ } else {
+ return SELinuxSetFilecon(path, default_content_context);
+ }
+}
+
+static int
SELinuxSetSecurityImageLabel(virDomainObjPtr vm,
virDomainDiskDefPtr disk)
{
const virSecurityLabelDefPtr secdef = &vm->def->seclabel;
- const char *path;
if (secdef->type == VIR_DOMAIN_SECLABEL_STATIC)
return 0;
- if (!disk->src)
- return 0;
-
- path = disk->src;
- do {
- virStorageFileMetadata meta;
- int ret;
-
- ret = virStorageFileGetMetadata(path,
- VIR_STORAGE_FILE_AUTO,
- &meta);
-
- if (path != disk->src)
- VIR_FREE(path);
- path = NULL;
-
- if (ret < 0)
- break;
-
- if (meta.backingStore != NULL &&
- SELinuxSetFilecon(meta.backingStore,
- default_content_context) < 0) {
- VIR_FREE(meta.backingStore);
- return -1;
- }
-
- path = meta.backingStore;
- } while (path != NULL);
-
- if (disk->shared) {
- return SELinuxSetFilecon(disk->src, default_image_context);
- } else if (disk->readonly) {
- return SELinuxSetFilecon(disk->src, default_content_context);
- } else if (secdef->imagelabel) {
- return SELinuxSetFilecon(disk->src, secdef->imagelabel);
- }
-
- return 0;
+ return virDomainDiskDefForeachPath(disk,
+ true,
+ false,
+ SELinuxSetSecurityFileLabel,
+ secdef);
}
diff --git a/src/security/virt-aa-helper.c b/src/security/virt-aa-helper.c
index 2c045e6..9ed0cd3 100644
--- a/src/security/virt-aa-helper.c
+++ b/src/security/virt-aa-helper.c
@@ -36,7 +36,6 @@
#include "uuid.h"
#include "hostusb.h"
#include "pci.h"
-#include "storage_file.h"
static char *progname;
@@ -801,6 +800,28 @@ file_iterate_pci_cb(pciDevice *dev ATTRIBUTE_UNUSED,
}
static int
+add_file_path(virDomainDiskDefPtr disk,
+ const char *path,
+ size_t depth,
+ void *opaque)
+{
+ virBufferPtr buf = opaque;
+ int ret;
+
+ if (depth == 0) {
+ if (disk->readonly)
+ ret = vah_add_file(buf, path, "r");
+ else
+ ret = vah_add_file(buf, path, "rw");
+ } else {
+ ret = vah_add_file(buf, path, "r");
+ }
+
+ return ret;
+}
+
+
+static int
get_files(vahControl * ctl)
{
virBuffer buf = VIR_BUFFER_INITIALIZER;
@@ -821,45 +842,15 @@ get_files(vahControl * ctl)
goto clean;
}
- for (i = 0; i < ctl->def->ndisks; i++)
- if (ctl->def->disks[i] && ctl->def->disks[i]->src) {
- int ret;
- const char *path;
-
- path = ctl->def->disks[i]->src;
- do {
- virStorageFileMetadata meta;
-
- ret = virStorageFileGetMetadata(path,
- VIR_STORAGE_FILE_AUTO,
- &meta);
-
- if (path != ctl->def->disks[i]->src)
- VIR_FREE(path);
- path = NULL;
-
- if (ret < 0) {
- vah_warning("could not open path, skipping");
- continue;
- }
-
- if (meta.backingStore != NULL &&
- (ret = vah_add_file(&buf, meta.backingStore, "rw")) != 0) {
- VIR_FREE(meta.backingStore);
- goto clean;
- }
-
- path = meta.backingStore;
- } while (path != NULL);
-
- if (ctl->def->disks[i]->readonly)
- ret = vah_add_file(&buf, ctl->def->disks[i]->src, "r");
- else
- ret = vah_add_file(&buf, ctl->def->disks[i]->src, "rw");
-
- if (ret != 0)
- goto clean;
- }
+ for (i = 0; i < ctl->def->ndisks; i++) {
+ int ret = virDomainDiskDefForeachPath(ctl->def->disks[i],
+ true,
+ false,
+ add_file_path,
+ &buf);
+ if (ret != 0)
+ goto clean;
+ }
for (i = 0; i < ctl->def->nserials; i++)
if (ctl->def->serials[i] && ctl->def->serials[i]->data.file.path)
--
1.7.1.1
File diff suppressed because it is too large Load Diff
+468
View File
@@ -0,0 +1,468 @@
From dac2b936e77f6c76c11f162e4b175492e4803acb 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/11] 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(-)
diff --git a/src/qemu/libvirtd_qemu.aug b/src/qemu/libvirtd_qemu.aug
index 7c9f271..47d0525 100644
--- a/src/qemu/libvirtd_qemu.aug
+++ b/src/qemu/libvirtd_qemu.aug
@@ -40,6 +40,7 @@ module Libvirtd_qemu =
| bool_entry "relaxed_acs_check"
| bool_entry "vnc_allow_host_audio"
| bool_entry "clear_emulator_capabilities"
+ | bool_entry "allow_disk_format_probing"
(* Each enty in the config is one of the following three ... *)
let entry = vnc_entry
diff --git a/src/qemu/qemu.conf b/src/qemu/qemu.conf
index 93934f3..dc8eb83 100644
--- a/src/qemu/qemu.conf
+++ b/src/qemu/qemu.conf
@@ -187,3 +187,15 @@
# exploit the privileges and possibly do damage to the host.
#
# clear_emulator_capabilities = 1
+
+
+
+# If allow_disk_format_probing is enabled, libvirt will probe disk
+# images to attempt to identify their format, when not otherwise
+# specified in the XML. This is disabled by default.
+#
+# WARNING: Enabling probing is a security hole in almost all
+# deployments. It is strongly recommended that users update their
+# guest XML <disk> elements to include <driver type='XXXX'/>
+# elements instead of enabling this option.
+# allow_disk_format_probing = 1
diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c
index 988220b..3ba48bf 100644
--- a/src/qemu/qemu_conf.c
+++ b/src/qemu/qemu_conf.c
@@ -365,6 +365,10 @@ int qemudLoadDriverConfig(struct qemud_driver *driver,
CHECK_TYPE ("clear_emulator_capabilities", VIR_CONF_LONG);
if (p) driver->clearEmulatorCapabilities = p->l;
+ p = virConfGetValue (conf, "allow_disk_format_probing");
+ CHECK_TYPE ("allow_disk_format_probing", VIR_CONF_LONG);
+ if (p) driver->allowDiskFormatProbing = p->l;
+
virConfFree (conf);
return 0;
}
diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h
index ab5f158..30e9f20 100644
--- a/src/qemu/qemu_conf.h
+++ b/src/qemu/qemu_conf.h
@@ -141,6 +141,7 @@ struct qemud_driver {
unsigned int relaxedACS : 1;
unsigned int vncAllowHostAudio : 1;
unsigned int clearEmulatorCapabilities : 1;
+ unsigned int allowDiskFormatProbing : 1;
virCapsPtr caps;
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 616547c..3c479c5 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -1322,7 +1322,8 @@ qemudSecurityInit(struct qemud_driver *qemud_drv)
qemuSecurityDACSetDriver(qemud_drv);
ret = virSecurityDriverStartup(&security_drv,
- qemud_drv->securityDriverName);
+ qemud_drv->securityDriverName,
+ qemud_drv->allowDiskFormatProbing);
if (ret == -1) {
VIR_ERROR0(_("Failed to start security driver"));
return -1;
@@ -3070,11 +3071,12 @@ static int qemuSetupDiskPathAllow(virDomainDiskDefPtr disk ATTRIBUTE_UNUSED,
}
-static int qemuSetupDiskCgroup(virCgroupPtr cgroup,
+static int qemuSetupDiskCgroup(struct qemud_driver *driver,
+ virCgroupPtr cgroup,
virDomainDiskDefPtr disk)
{
return virDomainDiskDefForeachPath(disk,
- true,
+ driver->allowDiskFormatProbing,
true,
qemuSetupDiskPathAllow,
cgroup);
@@ -3109,11 +3111,12 @@ static int qemuTeardownDiskPathDeny(virDomainDiskDefPtr disk ATTRIBUTE_UNUSED,
}
-static int qemuTeardownDiskCgroup(virCgroupPtr cgroup,
+static int qemuTeardownDiskCgroup(struct qemud_driver *driver,
+ virCgroupPtr cgroup,
virDomainDiskDefPtr disk)
{
return virDomainDiskDefForeachPath(disk,
- true,
+ driver->allowDiskFormatProbing,
true,
qemuTeardownDiskPathDeny,
cgroup);
@@ -3180,7 +3183,7 @@ static int qemuSetupCgroup(struct qemud_driver *driver,
}
for (i = 0; i < vm->def->ndisks ; i++) {
- if (qemuSetupDiskCgroup(cgroup, vm->def->disks[i]) < 0)
+ if (qemuSetupDiskCgroup(driver, cgroup, vm->def->disks[i]) < 0)
goto cleanup;
}
@@ -8033,7 +8036,7 @@ static int qemudDomainAttachDevice(virDomainPtr dom,
vm->def->name);
goto endjob;
}
- if (qemuSetupDiskCgroup(cgroup, dev->data.disk) < 0)
+ if (qemuSetupDiskCgroup(driver, cgroup, dev->data.disk) < 0)
goto endjob;
}
@@ -8078,7 +8081,7 @@ static int qemudDomainAttachDevice(virDomainPtr dom,
/* Fallthrough */
}
if (ret != 0 && cgroup) {
- if (qemuTeardownDiskCgroup(cgroup, dev->data.disk) < 0)
+ if (qemuTeardownDiskCgroup(driver, cgroup, dev->data.disk) < 0)
VIR_WARN("Failed to teardown cgroup for disk path %s",
NULLSTR(dev->data.disk->src));
}
@@ -8278,7 +8281,7 @@ static int qemuDomainUpdateDeviceFlags(virDomainPtr dom,
vm->def->name);
goto endjob;
}
- if (qemuSetupDiskCgroup(cgroup, dev->data.disk) < 0)
+ if (qemuSetupDiskCgroup(driver, cgroup, dev->data.disk) < 0)
goto endjob;
}
@@ -8301,7 +8304,7 @@ static int qemuDomainUpdateDeviceFlags(virDomainPtr dom,
}
if (ret != 0 && cgroup) {
- if (qemuTeardownDiskCgroup(cgroup, dev->data.disk) < 0)
+ if (qemuTeardownDiskCgroup(driver, cgroup, dev->data.disk) < 0)
VIR_WARN("Failed to teardown cgroup for disk path %s",
NULLSTR(dev->data.disk->src));
}
@@ -8429,7 +8432,7 @@ static int qemudDomainDetachPciDiskDevice(struct qemud_driver *driver,
VIR_WARN("Unable to restore security label on %s", dev->data.disk->src);
if (cgroup != NULL) {
- if (qemuTeardownDiskCgroup(cgroup, dev->data.disk) < 0)
+ if (qemuTeardownDiskCgroup(driver, cgroup, dev->data.disk) < 0)
VIR_WARN("Failed to teardown cgroup for disk path %s",
NULLSTR(dev->data.disk->src));
}
@@ -8493,7 +8496,7 @@ static int qemudDomainDetachSCSIDiskDevice(struct qemud_driver *driver,
VIR_WARN("Unable to restore security label on %s", dev->data.disk->src);
if (cgroup != NULL) {
- if (qemuTeardownDiskCgroup(cgroup, dev->data.disk) < 0)
+ if (qemuTeardownDiskCgroup(driver, cgroup, dev->data.disk) < 0)
VIR_WARN("Failed to teardown cgroup for disk path %s",
NULLSTR(dev->data.disk->src));
}
@@ -9672,8 +9675,15 @@ static int qemuDomainGetBlockInfo(virDomainPtr dom,
goto cleanup;
}
} else {
- if ((format = virStorageFileProbeFormat(disk->src)) < 0)
+ if (driver->allowDiskFormatProbing) {
+ if ((format = virStorageFileProbeFormat(disk->src)) < 0)
+ goto cleanup;
+ } else {
+ qemuReportError(VIR_ERR_INTERNAL_ERROR,
+ _("no disk format for %s and probing is disabled"),
+ disk->src);
goto cleanup;
+ }
}
if (virStorageFileGetMetadataFromFD(path, fd,
diff --git a/src/qemu/qemu_security_dac.c b/src/qemu/qemu_security_dac.c
index 0bbcf69..55dc0c6 100644
--- a/src/qemu/qemu_security_dac.c
+++ b/src/qemu/qemu_security_dac.c
@@ -117,7 +117,7 @@ qemuSecurityDACSetSecurityImageLabel(virSecurityDriverPtr drv ATTRIBUTE_UNUSED,
return 0;
return virDomainDiskDefForeachPath(disk,
- true,
+ driver->allowDiskFormatProbing,
false,
qemuSecurityDACSetSecurityFileLabel,
NULL);
diff --git a/src/qemu/test_libvirtd_qemu.aug b/src/qemu/test_libvirtd_qemu.aug
index 3326cc5..f0c4a0d 100644
--- a/src/qemu/test_libvirtd_qemu.aug
+++ b/src/qemu/test_libvirtd_qemu.aug
@@ -101,6 +101,8 @@ relaxed_acs_check = 1
vnc_allow_host_audio = 1
clear_emulator_capabilities = 0
+
+allow_disk_format_probing = 1
"
test Libvirtd_qemu.lns get conf =
@@ -212,3 +214,5 @@ clear_emulator_capabilities = 0
{ "vnc_allow_host_audio" = "1" }
{ "#empty" }
{ "clear_emulator_capabilities" = "0" }
+{ "#empty" }
+{ "allow_disk_format_probing" = "1" }
diff --git a/src/security/security_apparmor.c b/src/security/security_apparmor.c
index cb5c739..c5f9829 100644
--- a/src/security/security_apparmor.c
+++ b/src/security/security_apparmor.c
@@ -157,6 +157,8 @@ load_profile(virSecurityDriverPtr drv,
char *xml = NULL;
int pipefd[2];
pid_t child;
+ const char *probe = virSecurityDriverGetAllowDiskFormatProbing(drv)
+ ? "1" : "0";
if (pipe(pipefd) < -1) {
virReportSystemError(errno, "%s", _("unable to create pipe"));
@@ -172,19 +174,19 @@ load_profile(virSecurityDriverPtr drv,
if (create) {
const char *const argv[] = {
- VIRT_AA_HELPER, "-c", "-u", profile, NULL
+ VIRT_AA_HELPER, "-p", probe, "-c", "-u", profile, NULL
};
ret = virExec(argv, NULL, NULL, &child,
pipefd[0], NULL, NULL, VIR_EXEC_NONE);
} else if (fn) {
const char *const argv[] = {
- VIRT_AA_HELPER, "-r", "-u", profile, "-f", fn, NULL
+ VIRT_AA_HELPER, "-p", probe, "-r", "-u", profile, "-f", fn, NULL
};
ret = virExec(argv, NULL, NULL, &child,
pipefd[0], NULL, NULL, VIR_EXEC_NONE);
} else {
const char *const argv[] = {
- VIRT_AA_HELPER, "-r", "-u", profile, NULL
+ VIRT_AA_HELPER, "-p", probe, "-r", "-u", profile, NULL
};
ret = virExec(argv, NULL, NULL, &child,
pipefd[0], NULL, NULL, VIR_EXEC_NONE);
@@ -347,9 +349,11 @@ AppArmorSecurityDriverProbe(void)
* currently not used.
*/
static int
-AppArmorSecurityDriverOpen(virSecurityDriverPtr drv)
+AppArmorSecurityDriverOpen(virSecurityDriverPtr drv,
+ bool allowDiskFormatProbing)
{
virSecurityDriverSetDOI(drv, SECURITY_APPARMOR_VOID_DOI);
+ virSecurityDriverSetAllowDiskFormatProbing(drv, allowDiskFormatProbing);
return 0;
}
diff --git a/src/security/security_driver.c b/src/security/security_driver.c
index aac9f78..9e32fa4 100644
--- a/src/security/security_driver.c
+++ b/src/security/security_driver.c
@@ -56,7 +56,8 @@ virSecurityDriverVerify(virDomainDefPtr def)
int
virSecurityDriverStartup(virSecurityDriverPtr *drv,
- const char *name)
+ const char *name,
+ bool allowDiskFormatProbing)
{
unsigned int i;
@@ -72,7 +73,7 @@ virSecurityDriverStartup(virSecurityDriverPtr *drv,
switch (tmp->probe()) {
case SECURITY_DRIVER_ENABLE:
virSecurityDriverInit(tmp);
- if (tmp->open(tmp) == -1) {
+ if (tmp->open(tmp, allowDiskFormatProbing) == -1) {
return -1;
} else {
*drv = tmp;
@@ -125,3 +126,14 @@ virSecurityDriverGetModel(virSecurityDriverPtr drv)
{
return drv->name;
}
+
+void virSecurityDriverSetAllowDiskFormatProbing(virSecurityDriverPtr drv,
+ bool allowDiskFormatProbing)
+{
+ drv->_private.allowDiskFormatProbing = allowDiskFormatProbing;
+}
+
+bool virSecurityDriverGetAllowDiskFormatProbing(virSecurityDriverPtr drv)
+{
+ return drv->_private.allowDiskFormatProbing;
+}
diff --git a/src/security/security_driver.h b/src/security/security_driver.h
index 61c9eb0..d768f32 100644
--- a/src/security/security_driver.h
+++ b/src/security/security_driver.h
@@ -33,7 +33,8 @@ typedef struct _virSecurityDriverState virSecurityDriverState;
typedef virSecurityDriverState *virSecurityDriverStatePtr;
typedef virSecurityDriverStatus (*virSecurityDriverProbe) (void);
-typedef int (*virSecurityDriverOpen) (virSecurityDriverPtr drv);
+typedef int (*virSecurityDriverOpen) (virSecurityDriverPtr drv,
+ bool allowDiskFormatProbing);
typedef int (*virSecurityDomainRestoreImageLabel) (virSecurityDriverPtr drv,
virDomainObjPtr vm,
virDomainDiskDefPtr disk);
@@ -102,12 +103,14 @@ struct _virSecurityDriver {
*/
struct {
char doi[VIR_SECURITY_DOI_BUFLEN];
+ bool allowDiskFormatProbing;
} _private;
};
/* Global methods */
int virSecurityDriverStartup(virSecurityDriverPtr *drv,
- const char *name);
+ const char *name,
+ bool allowDiskFormatProbing);
int
virSecurityDriverVerify(virDomainDefPtr def);
@@ -120,7 +123,10 @@ virSecurityDriverVerify(virDomainDefPtr def);
void virSecurityDriverInit(virSecurityDriverPtr drv);
int virSecurityDriverSetDOI(virSecurityDriverPtr drv,
const char *doi);
+void virSecurityDriverSetAllowDiskFormatProbing(virSecurityDriverPtr drv,
+ bool allowDiskFormatProbing);
const char *virSecurityDriverGetDOI(virSecurityDriverPtr drv);
const char *virSecurityDriverGetModel(virSecurityDriverPtr drv);
+bool virSecurityDriverGetAllowDiskFormatProbing(virSecurityDriverPtr drv);
#endif /* __VIR_SECURITY_H__ */
diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c
index cc3812b..a9dd836 100644
--- a/src/security/security_selinux.c
+++ b/src/security/security_selinux.c
@@ -266,13 +266,15 @@ SELinuxSecurityDriverProbe(void)
}
static int
-SELinuxSecurityDriverOpen(virSecurityDriverPtr drv)
+SELinuxSecurityDriverOpen(virSecurityDriverPtr drv,
+ bool allowDiskFormatProbing)
{
/*
* Where will the DOI come from? SELinux configuration, or qemu
* configuration? For the moment, we'll just set it to "0".
*/
virSecurityDriverSetDOI(drv, SECURITY_SELINUX_VOID_DOI);
+ virSecurityDriverSetAllowDiskFormatProbing(drv, allowDiskFormatProbing);
return SELinuxInitialize();
}
@@ -467,18 +469,19 @@ SELinuxSetSecurityFileLabel(virDomainDiskDefPtr disk,
}
static int
-SELinuxSetSecurityImageLabel(virSecurityDriverPtr drv ATTRIBUTE_UNUSED,
+SELinuxSetSecurityImageLabel(virSecurityDriverPtr drv,
virDomainObjPtr vm,
virDomainDiskDefPtr disk)
{
const virSecurityLabelDefPtr secdef = &vm->def->seclabel;
+ bool allowDiskFormatProbing = virSecurityDriverGetAllowDiskFormatProbing(drv);
if (secdef->type == VIR_DOMAIN_SECLABEL_STATIC)
return 0;
return virDomainDiskDefForeachPath(disk,
- true,
+ allowDiskFormatProbing,
false,
SELinuxSetSecurityFileLabel,
secdef);
diff --git a/src/security/virt-aa-helper.c b/src/security/virt-aa-helper.c
index 9ed0cd3..521545d 100644
--- a/src/security/virt-aa-helper.c
+++ b/src/security/virt-aa-helper.c
@@ -40,6 +40,7 @@
static char *progname;
typedef struct {
+ bool allowDiskFormatProbing;
char uuid[PROFILE_NAME_SIZE]; /* UUID of vm */
bool dryrun; /* dry run */
char cmd; /* 'c' create
@@ -844,7 +845,7 @@ get_files(vahControl * ctl)
for (i = 0; i < ctl->def->ndisks; i++) {
int ret = virDomainDiskDefForeachPath(ctl->def->disks[i],
- true,
+ ctl->allowDiskFormatProbing,
false,
add_file_path,
&buf);
@@ -943,6 +944,7 @@ vahParseArgv(vahControl * ctl, int argc, char **argv)
{
int arg, idx = 0;
struct option opt[] = {
+ {"probing", 1, 0, 'p' },
{"add", 0, 0, 'a'},
{"create", 0, 0, 'c'},
{"dryrun", 0, 0, 'd'},
@@ -991,6 +993,12 @@ vahParseArgv(vahControl * ctl, int argc, char **argv)
PROFILE_NAME_SIZE) == NULL)
vah_error(ctl, 1, "error copying UUID");
break;
+ case 'p':
+ if (STREQ(optarg, "1"))
+ ctl->allowDiskFormatProbing = true;
+ else
+ ctl->allowDiskFormatProbing = false;
+ break;
default:
vah_error(ctl, 1, "unsupported option");
break;
diff --git a/tests/seclabeltest.c b/tests/seclabeltest.c
index 26d1f86..ef3f026 100644
--- a/tests/seclabeltest.c
+++ b/tests/seclabeltest.c
@@ -15,7 +15,7 @@ main (int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
const char *doi, *model;
virSecurityDriverPtr security_drv;
- ret = virSecurityDriverStartup (&security_drv, "selinux");
+ ret = virSecurityDriverStartup (&security_drv, "selinux", false);
if (ret == -1)
{
fprintf (stderr, "Failed to start security driver");
--
1.7.1.1
+94
View File
@@ -0,0 +1,94 @@
From 3534cd47a57ee9cf7041472511444784f14d6939 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/11] 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 | 16 +++++++++++++++-
src/qemu/qemu_driver.c | 8 ++++++++
3 files changed, 25 insertions(+), 1 deletions(-)
diff --git a/src/conf/capabilities.h b/src/conf/capabilities.h
index 9290c82..f676eb8 100644
--- a/src/conf/capabilities.h
+++ b/src/conf/capabilities.h
@@ -123,6 +123,8 @@ struct _virCaps {
virCapsGuestPtr *guests;
unsigned char macPrefix[VIR_MAC_PREFIX_BUFLEN];
unsigned int emulatorRequired : 1;
+ const char *defaultDiskDriverName;
+ const char *defaultDiskDriverType;
void *(*privateDataAllocFunc)(void);
void (*privateDataFreeFunc)(void *);
int (*privateDataXMLFormat)(virBufferPtr, void *);
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index b20ca97..f3b8cfa 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -1639,6 +1639,16 @@ virDomainDiskDefParseXML(virCapsPtr caps,
def->serial = serial;
serial = NULL;
+ if (!def->driverType &&
+ caps->defaultDiskDriverType &&
+ !(def->driverType = strdup(caps->defaultDiskDriverType)))
+ goto no_memory;
+
+ if (!def->driverName &&
+ caps->defaultDiskDriverName &&
+ !(def->driverName = strdup(caps->defaultDiskDriverName)))
+ goto no_memory;
+
if (def->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE
&& virDomainDiskDefAssignAddress(caps, def) < 0)
goto error;
@@ -1659,6 +1669,9 @@ cleanup:
return def;
+no_memory:
+ virReportOOMError();
+
error:
virDomainDiskDefFree(def);
def = NULL;
@@ -4275,7 +4288,8 @@ static virDomainDefPtr virDomainDefParseXML(virCapsPtr caps,
if (n && VIR_ALLOC_N(def->disks, n) < 0)
goto no_memory;
for (i = 0 ; i < n ; i++) {
- virDomainDiskDefPtr disk = virDomainDiskDefParseXML(caps, nodes[i],
+ virDomainDiskDefPtr disk = virDomainDiskDefParseXML(caps,
+ nodes[i],
flags);
if (!disk)
goto error;
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 3c479c5..14b790e 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -1357,6 +1357,14 @@ qemuCreateCapabilities(virCapsPtr oldcaps,
return NULL;
}
+ if (driver->allowDiskFormatProbing) {
+ caps->defaultDiskDriverName = NULL;
+ caps->defaultDiskDriverType = NULL;
+ } else {
+ caps->defaultDiskDriverName = "qemu";
+ caps->defaultDiskDriverType = "raw";
+ }
+
/* Domain XML parser hooks */
caps->privateDataAllocFunc = qemuDomainObjPrivateAlloc;
caps->privateDataFreeFunc = qemuDomainObjPrivateFree;
--
1.7.1.1
@@ -0,0 +1,291 @@
From 2ba8625d6d148fa489586efabdfaf2ef20903762 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/11] 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(-)
diff --git a/src/storage/storage_backend.c b/src/storage/storage_backend.c
index aba8937..c185693 100644
--- a/src/storage/storage_backend.c
+++ b/src/storage/storage_backend.c
@@ -561,6 +561,69 @@ static int virStorageBackendCreateExecCommand(virStoragePoolObjPtr pool,
return 0;
}
+enum {
+ QEMU_IMG_BACKING_FORMAT_NONE = 0,
+ QEMU_IMG_BACKING_FORMAT_FLAG,
+ QEMU_IMG_BACKING_FORMAT_OPTIONS,
+};
+
+static int virStorageBackendQEMUImgBackingFormat(const char *qemuimg)
+{
+ const char *const qemuarg[] = { qemuimg, "-h", NULL };
+ const char *const qemuenv[] = { "LC_ALL=C", NULL };
+ pid_t child = 0;
+ int status;
+ int newstdout = -1;
+ char *help = NULL;
+ enum { MAX_HELP_OUTPUT_SIZE = 1024*8 };
+ int len;
+ char *start;
+ char *end;
+ char *tmp;
+ int ret = -1;
+
+ if (virExec(qemuarg, qemuenv, NULL,
+ &child, -1, &newstdout, NULL, VIR_EXEC_CLEAR_CAPS) < 0)
+ goto cleanup;
+
+ if ((len = virFileReadLimFD(newstdout, MAX_HELP_OUTPUT_SIZE, &help)) < 0) {
+ virReportSystemError(errno,
+ _("Unable to read '%s -h' output"),
+ qemuimg);
+ goto cleanup;
+ }
+
+ start = strstr(help, " create ");
+ end = strstr(start, "\n");
+ if ((tmp = strstr(start, "-F fmt")) && tmp < end)
+ ret = QEMU_IMG_BACKING_FORMAT_FLAG;
+ else if ((tmp = strstr(start, "[-o options]")) && tmp < end)
+ ret = QEMU_IMG_BACKING_FORMAT_OPTIONS;
+ else
+ ret = QEMU_IMG_BACKING_FORMAT_NONE;
+
+cleanup:
+ VIR_FREE(help);
+ close(newstdout);
+rewait:
+ if (child) {
+ if (waitpid(child, &status, 0) != child) {
+ if (errno == EINTR)
+ goto rewait;
+
+ VIR_ERROR(_("Unexpected exit status from qemu %d pid %lu"),
+ WEXITSTATUS(status), (unsigned long)child);
+ }
+ if (WEXITSTATUS(status) != 0) {
+ VIR_WARN("Unexpected exit status '%d', qemu probably failed",
+ WEXITSTATUS(status));
+ }
+ }
+
+ return ret;
+}
+
+
static int
virStorageBackendCreateQemuImg(virConnectPtr conn,
virStoragePoolObjPtr pool,
@@ -568,10 +631,9 @@ virStorageBackendCreateQemuImg(virConnectPtr conn,
virStorageVolDefPtr inputvol,
unsigned int flags ATTRIBUTE_UNUSED)
{
- int ret;
+ int ret = -1;
char size[100];
char *create_tool;
- short use_kvmimg;
const char *type = virStorageFileFormatTypeToString(vol->target.format);
const char *backingType = vol->backingStore.path ?
@@ -582,41 +644,10 @@ virStorageBackendCreateQemuImg(virConnectPtr conn,
const char *inputPath = inputvol ? inputvol->target.path : NULL;
/* Treat input block devices as 'raw' format */
const char *inputType = inputPath ?
- virStorageFileFormatTypeToString(inputvol->type == VIR_STORAGE_VOL_BLOCK ? VIR_STORAGE_FILE_RAW : inputvol->target.format) :
- NULL;
-
- const char **imgargv;
- /* The extra NULL field is for indicating encryption (-e). */
- const char *imgargvnormal[] = {
- NULL, "create",
- "-f", type,
- vol->target.path,
- size,
- NULL,
- NULL
- };
- /* Extra NULL fields are for including "backingType" when using
- * kvm-img (-F backingType), and for indicating encryption (-e).
- */
- const char *imgargvbacking[] = {
- NULL, "create",
- "-f", type,
- "-b", vol->backingStore.path,
- vol->target.path,
- size,
- NULL,
- NULL,
- NULL,
- NULL
- };
- const char *convargv[] = {
- NULL, "convert",
- "-f", inputType,
- "-O", type,
- inputPath,
- vol->target.path,
- NULL,
- };
+ virStorageFileFormatTypeToString(inputvol->type == VIR_STORAGE_VOL_BLOCK ?
+ VIR_STORAGE_FILE_RAW :
+ inputvol->target.format) :
+ NULL;
if (type == NULL) {
virStorageReportError(VIR_ERR_INTERNAL_ERROR,
@@ -690,44 +721,103 @@ virStorageBackendCreateQemuImg(virConnectPtr conn,
}
}
- if ((create_tool = virFindFileInPath("kvm-img")) != NULL)
- use_kvmimg = 1;
- else if ((create_tool = virFindFileInPath("qemu-img")) != NULL)
- use_kvmimg = 0;
- else {
+ /* Size in KB */
+ snprintf(size, sizeof(size), "%lluK", vol->capacity/1024);
+
+ /* KVM is usually ahead of qemu on features, so try that first */
+ create_tool = virFindFileInPath("kvm-img");
+ if (!create_tool)
+ create_tool = virFindFileInPath("qemu-img");
+
+ if (!create_tool) {
virStorageReportError(VIR_ERR_INTERNAL_ERROR,
"%s", _("unable to find kvm-img or qemu-img"));
return -1;
}
if (inputvol) {
- convargv[0] = create_tool;
- imgargv = convargv;
+ const char *imgargv[] = {
+ create_tool,
+ "convert",
+ "-f", inputType,
+ "-O", type,
+ inputPath,
+ vol->target.path,
+ NULL,
+ };
+
+ ret = virStorageBackendCreateExecCommand(pool, vol, imgargv);
} else if (vol->backingStore.path) {
- imgargvbacking[0] = create_tool;
- if (use_kvmimg) {
- imgargvbacking[6] = "-F";
- imgargvbacking[7] = backingType;
- imgargvbacking[8] = vol->target.path;
- imgargvbacking[9] = size;
+ const char *imgargv[] = {
+ create_tool,
+ "create",
+ "-f", type,
+ "-b", vol->backingStore.path,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+ };
+ int imgformat = virStorageBackendQEMUImgBackingFormat(create_tool);
+ char *optflag = NULL;
+ if (imgformat < 0)
+ goto cleanup;
+
+ switch (imgformat) {
+ case QEMU_IMG_BACKING_FORMAT_FLAG:
+ imgargv[6] = "-F";
+ imgargv[7] = backingType;
+ imgargv[8] = vol->target.path;
+ imgargv[9] = size;
+ if (vol->target.encryption != NULL)
+ imgargv[10] = "-e";
+ break;
+
+ case QEMU_IMG_BACKING_FORMAT_OPTIONS:
+ if (virAsprintf(&optflag, "backing_fmt=%s", backingType) < 0) {
+ virReportOOMError();
+ goto cleanup;
+ }
+ imgargv[6] = "-o";
+ imgargv[7] = optflag;
+ imgargv[8] = vol->target.path;
+ imgargv[9] = size;
if (vol->target.encryption != NULL)
- imgargvbacking[10] = "-e";
- } else if (vol->target.encryption != NULL)
- imgargvbacking[8] = "-e";
- imgargv = imgargvbacking;
+ imgargv[10] = "-e";
+ break;
+
+ default:
+ VIR_INFO("Unable to set backing store format for %s with %s",
+ vol->target.path, create_tool);
+ imgargv[6] = vol->target.path;
+ imgargv[7] = size;
+ if (vol->target.encryption != NULL)
+ imgargv[8] = "-e";
+ }
+
+ ret = virStorageBackendCreateExecCommand(pool, vol, imgargv);
+ VIR_FREE(optflag);
} else {
- imgargvnormal[0] = create_tool;
- imgargv = imgargvnormal;
+ /* The extra NULL field is for indicating encryption (-e). */
+ const char *imgargv[] = {
+ create_tool,
+ "create",
+ "-f", type,
+ vol->target.path,
+ size,
+ NULL,
+ NULL
+ };
if (vol->target.encryption != NULL)
imgargv[6] = "-e";
- }
+ ret = virStorageBackendCreateExecCommand(pool, vol, imgargv);
+ }
- /* Size in KB */
- snprintf(size, sizeof(size), "%lluK", vol->capacity/1024);
-
- ret = virStorageBackendCreateExecCommand(pool, vol, imgargv);
- VIR_FREE(imgargv[0]);
+ cleanup:
+ VIR_FREE(create_tool);
return ret;
}
--
1.7.1.1
+165
View File
@@ -0,0 +1,165 @@
From d33f44c2e74de28c89b64cdc2c0a6564662e075c Mon Sep 17 00:00:00 2001
From: Daniel P. Berrange <berrange@redhat.com>
Date: Fri, 9 Jul 2010 11:28:40 +0100
Subject: [PATCH 11/11] Use the extract backing store format in storage volume lookup
The storage volume lookup code was probing for the backing store
format, instead of using the format extracted from the file
itself. This meant it could report in accurate information. If
a format is included in the file, then use that in preference,
with probing as a fallback.
* src/storage/storage_backend_fs.c: Use extracted backing store
format
---
src/storage/storage_backend_fs.c | 80 +++++++++++++++++---------------------
1 files changed, 36 insertions(+), 44 deletions(-)
diff --git a/src/storage/storage_backend_fs.c b/src/storage/storage_backend_fs.c
index d3ac0fe..ffb0071 100644
--- a/src/storage/storage_backend_fs.c
+++ b/src/storage/storage_backend_fs.c
@@ -51,6 +51,7 @@
static int
virStorageBackendProbeTarget(virStorageVolTargetPtr target,
char **backingStore,
+ int *backingStoreFormat,
unsigned long long *allocation,
unsigned long long *capacity,
virStorageEncryptionPtr *encryption)
@@ -58,6 +59,10 @@ virStorageBackendProbeTarget(virStorageVolTargetPtr target,
int fd, ret;
virStorageFileMetadata meta;
+ if (backingStore)
+ *backingStore = NULL;
+ if (backingStoreFormat)
+ *backingStoreFormat = VIR_STORAGE_FILE_AUTO;
if (encryption)
*encryption = NULL;
@@ -89,22 +94,30 @@ virStorageBackendProbeTarget(virStorageVolTargetPtr target,
close(fd);
- if (backingStore) {
- *backingStore = meta.backingStore;
- meta.backingStore = NULL;
+ if (meta.backingStore) {
+ if (backingStore) {
+ *backingStore = meta.backingStore;
+ meta.backingStore = NULL;
+ if (meta.backingStoreFormat == VIR_STORAGE_FILE_AUTO) {
+ if ((*backingStoreFormat = virStorageFileProbeFormat(*backingStore)) < 0) {
+ close(fd);
+ goto cleanup;
+ }
+ } else {
+ *backingStoreFormat = meta.backingStoreFormat;
+ }
+ } else {
+ VIR_FREE(meta.backingStore);
+ }
}
- VIR_FREE(meta.backingStore);
-
if (capacity && meta.capacity)
*capacity = meta.capacity;
if (encryption != NULL && meta.encrypted) {
if (VIR_ALLOC(*encryption) < 0) {
virReportOOMError();
- if (backingStore)
- VIR_FREE(*backingStore);
- return -1;
+ goto cleanup;
}
switch (target->format) {
@@ -124,6 +137,11 @@ virStorageBackendProbeTarget(virStorageVolTargetPtr target,
}
return 0;
+
+cleanup:
+ if (backingStore)
+ VIR_FREE(*backingStore);
+ return -1;
}
#if WITH_STORAGE_FS
@@ -585,6 +603,7 @@ virStorageBackendFileSystemRefresh(virConnectPtr conn ATTRIBUTE_UNUSED,
while ((ent = readdir(dir)) != NULL) {
int ret;
char *backingStore;
+ int backingStoreFormat;
if (VIR_ALLOC(vol) < 0)
goto no_memory;
@@ -604,6 +623,7 @@ virStorageBackendFileSystemRefresh(virConnectPtr conn ATTRIBUTE_UNUSED,
if ((ret = virStorageBackendProbeTarget(&vol->target,
&backingStore,
+ &backingStoreFormat,
&vol->allocation,
&vol->capacity,
&vol->target.encryption)) < 0) {
@@ -619,46 +639,18 @@ virStorageBackendFileSystemRefresh(virConnectPtr conn ATTRIBUTE_UNUSED,
}
if (backingStore != NULL) {
- if (vol->target.format == VIR_STORAGE_FILE_QCOW2 &&
- STRPREFIX("fmt:", backingStore)) {
- char *fmtstr = backingStore + 4;
- char *path = strchr(fmtstr, ':');
- if (!path) {
- VIR_FREE(backingStore);
- } else {
- *path = '\0';
- if ((vol->backingStore.format =
- virStorageFileFormatTypeFromString(fmtstr)) < 0) {
- VIR_FREE(backingStore);
- } else {
- memmove(backingStore, path, strlen(path) + 1);
- vol->backingStore.path = backingStore;
-
- if (virStorageBackendUpdateVolTargetInfo(&vol->backingStore,
- NULL,
- NULL) < 0)
- VIR_FREE(vol->backingStore);
- }
- }
- } else {
- vol->backingStore.path = backingStore;
-
- if ((ret = virStorageBackendProbeTarget(&vol->backingStore,
- NULL, NULL, NULL,
- NULL)) < 0) {
- if (ret == -1)
- goto cleanup;
- else {
- /* Silently ignore non-regular files,
- * eg '.' '..', 'lost+found' */
- VIR_FREE(vol->backingStore);
- }
- }
+ vol->backingStore.path = backingStore;
+ vol->backingStore.format = backingStoreFormat;
+
+ if (virStorageBackendUpdateVolTargetInfo(&vol->backingStore,
+ NULL,
+ NULL) < 0) {
+ VIR_FREE(vol->backingStore.path);
+ goto cleanup;
}
}
-
if (VIR_REALLOC_N(pool->volumes.objs,
pool->volumes.count+1) < 0)
goto no_memory;
--
1.7.1.1
@@ -0,0 +1,265 @@
From 112a309bc7839e95c558b535143f855ce89cca8c 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] CVE-2010-2242 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(-)
diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c
index 72255c1..80ed57a 100644
--- a/src/network/bridge_driver.c
+++ b/src/network/bridge_driver.c
@@ -638,18 +638,74 @@ networkAddMasqueradingIptablesRules(struct network_driver *driver,
goto masqerr2;
}
- /* enable masquerading */
+ /*
+ * 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 */
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'"),
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,
@@ -814,8 +870,17 @@ networkRemoveIptablesRules(struct network_driver *driver,
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,
diff --git a/src/util/iptables.c b/src/util/iptables.c
index d06b857..f63e8c6 100644
--- a/src/util/iptables.c
+++ b/src/util/iptables.c
@@ -692,25 +692,49 @@ iptablesRemoveForwardRejectIn(iptablesContext *ctx,
*/
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(iptablesContext *ctx,
* @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(iptablesContext *ctx,
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(iptablesContext *ctx,
* @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(iptablesContext *ctx,
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);
}
diff --git a/src/util/iptables.h b/src/util/iptables.h
index 7d55a6d..b47d854 100644
--- a/src/util/iptables.h
+++ b/src/util/iptables.h
@@ -85,9 +85,11 @@ int iptablesRemoveForwardRejectIn (iptablesContext *ctx,
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__ */
--
1.6.6.1
+1026 -2031
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -1 +1 @@
SHA512 (libvirt-3.7.0.tar.xz) = b3f7021ef4c6954430f8fa503f0c49e3df4f662b228cb631ba2c2139ecec2307dde6cec05037cc28663e82ab1001296c20c5c68acd183cd364dd484a7746f498
14164638fe0e7f65e425acc85dabc517 libvirt-0.8.2.tar.gz