Compare commits
299 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5fccec3f3b | |||
| e698b1d369 | |||
| 97d2066b3e | |||
| 1fefcb5913 | |||
| 310d2dbd80 | |||
| 0649b336a0 | |||
| 8d00f2a3c0 | |||
| 90bdf4b1ee | |||
| d670e246d0 | |||
| 50e7b9a91d | |||
| 5cbc0451ce | |||
| b420054636 | |||
| 143fedee46 | |||
| 88887cac0f | |||
| 579afc99f2 | |||
| 7f5808b9d0 | |||
| 4df5f77071 | |||
| 1bdd527daf | |||
| e5fa1c00d2 | |||
| 18f7b8c79c | |||
| 782468f8e9 | |||
| 202e7d9569 | |||
| 0676a07265 | |||
| f57ce74947 | |||
| 851cfde15b | |||
| 06123137eb | |||
| 6ccf3cb58c | |||
| 030ddaa4ef | |||
| a8886736c4 | |||
| 4fd635e537 | |||
| 6210c457fc | |||
| 82926cfdf0 | |||
| e7a3ca6f6b | |||
| 1ae6f647b7 | |||
| 48941c011f | |||
| a3c4cc6f3d | |||
| 90fbcbd48f | |||
| 6efd96d995 | |||
| 21316e7a45 | |||
| 8adbb7a402 | |||
| 3f19d41908 | |||
| 34da93e0c9 | |||
| 208f506190 | |||
| 0ca715cad9 | |||
| 0f5d8c1c22 | |||
| a56bcbd063 | |||
| 89c3fa751c | |||
| 051644ffcb | |||
| 2a9c282548 | |||
| 2ae80af461 | |||
| 7335ede0e1 | |||
| 6c92ba3805 | |||
| 446f680673 | |||
| 3f56aa2870 | |||
| 3cec91694f | |||
| cb0cfa566f | |||
| a27acebf66 | |||
| 99d3a0ca1a | |||
| 9c962ebc4f | |||
| 99cbbf6606 | |||
| b73e509648 | |||
| b23ff9c0f7 | |||
| 20f9ed9c4c | |||
| 04cb28c315 | |||
| a74ea318d1 | |||
| 98ed6b4e36 | |||
| 2c49d1fd11 | |||
| 6e7bca6631 | |||
| 2fe145bb02 | |||
| 10b7d235e3 | |||
| 232e2e7de2 | |||
| fb1e4b061e | |||
| 0b1a013081 | |||
| a972457f43 | |||
| 67cfa34a05 | |||
| fc2ebb7646 | |||
| e92b461b4f | |||
| b1ac7b5791 | |||
| 88424efe85 | |||
| 4e2aab98a2 | |||
| f4bc1a2fe2 | |||
| a4bf2768b8 | |||
| 47cd44e9da | |||
| 731c6b90ff | |||
| 47ca46905d | |||
| 860ffc5b13 | |||
| 611b2ee520 | |||
| edcb926f9d | |||
| caebff8304 | |||
| 8fa41135ca | |||
| 0debbff964 | |||
| d6cc78be66 | |||
| 8d9645735e | |||
| 4c65f08330 | |||
| 2427f8f078 | |||
| d168e4f934 | |||
| 4dd365589f | |||
| 50e253df29 | |||
| cb71801a2b | |||
| 4a9c74e91d | |||
| 281508ec99 | |||
| feb92626e1 | |||
| 93cadb0880 | |||
| dd6b57aa60 | |||
| b8cb754e9d | |||
| dbe61507bd | |||
| ce7b23d9d0 | |||
| 8ded6ff93e | |||
| 1ef96f3488 | |||
| ee3bf37900 | |||
| 7452a06938 | |||
| fe8f9ed9c4 | |||
| 1b64f74c82 | |||
| c81949046d | |||
| 19dcb913e6 | |||
| e4b5ba1a9d | |||
| 5f1a422d83 | |||
| c5b0b3ef9d | |||
| c0a04cb876 | |||
| 3cc7cdf12f | |||
| 6b531d9967 | |||
| 4d05ac021c | |||
| d29aa84b17 | |||
| a075adc818 | |||
| 4d0e63f99c | |||
| 9e11936ec5 | |||
| a4075ec632 | |||
| dadb59c95f | |||
| e73cc6a9d8 | |||
| 10cd84e37f | |||
| e63e2040cd | |||
| 91063332d7 | |||
| 503330ba5d | |||
| 0a64085f47 | |||
| 1073e2447a | |||
| 5b1a906ace | |||
| aff97e0146 | |||
| a4b41a378b | |||
| 3ec523d168 | |||
| 622cf0d642 | |||
| a540751e83 | |||
| 11b596669a | |||
| fefbae879b | |||
| 695b281409 | |||
| 9f9eae34c1 | |||
| ae37ed3500 | |||
| f7f509999b | |||
| 419bcc4b2f | |||
| 7b59d4f7eb | |||
| 03326e9c04 | |||
| f40b464d1e | |||
| 810ca6c207 | |||
| 8df3aef6aa | |||
| 0223d5a656 | |||
| aad810a204 | |||
| 1b8b7567b1 | |||
| 442040caac | |||
| 65efaafca2 | |||
| e87c8ab0c7 | |||
| be6bda45b4 | |||
| 8c9e40d383 | |||
| 0f6f9b973a | |||
| 3db6039b2b | |||
| 4051217c8b | |||
| c5c28baba1 | |||
| 43618df1d4 | |||
| a2951dccb5 | |||
| b884323c03 | |||
| adeaf839fd | |||
| 40d99010e1 | |||
| 11755d8663 | |||
| 2daa92daf9 | |||
| db2858c661 | |||
| 53adb9aaba | |||
| 168df8b606 | |||
| f9085f2538 | |||
| b159bbdc98 | |||
| a5af3cf105 | |||
| 27ca069db7 | |||
| 000a3274d2 | |||
| 19c7799c31 | |||
| 198ff818c6 | |||
| e80c83ad06 | |||
| 660e0112c6 | |||
| 45c1cabef6 | |||
| 56be2c5e38 | |||
| 4aa9c4f1a3 | |||
| 7be420ad22 | |||
| 40b00623a4 | |||
| ce09ec66c7 | |||
| 97d7c80e2e | |||
| b856ae03bf | |||
| 803b3b891a | |||
| 350081d1a9 | |||
| 1b71b68bb9 | |||
| 4084288dd5 | |||
| d1cd1b7ceb | |||
| 5ed69704b9 | |||
| be6e136cb1 | |||
| d3109abfa4 | |||
| f5ff4a2393 | |||
| 8cc50838dc | |||
| 2c2e71c0ce | |||
| 96b1b18b42 | |||
| f7763bfd17 | |||
| 404e58cb18 | |||
| cd3767e3b9 | |||
| f1867a5ecc | |||
| b5548f62cb | |||
| 52f3bedee7 | |||
| f87237919c | |||
| e8969fb913 | |||
| 74d46bc7dd | |||
| 4b6ea94306 | |||
| 963754bc8c | |||
| 7b5483236c | |||
| 438006407c | |||
| 76c8282ee2 | |||
| f463598b24 | |||
| f4e752a385 | |||
| c37cb21dea | |||
| e0bfc1f8aa | |||
| 544ad4a787 | |||
| 8f163760ed | |||
| 565427cf89 | |||
| e10da2f6d4 | |||
| aa386576d5 | |||
| c73c129b48 | |||
| afe729ac3c | |||
| b6038bae4f | |||
| e6d9787587 | |||
| 44699dc495 | |||
| 991d719dde | |||
| 96a520b555 | |||
| e31df5e9de | |||
| 6763b267b9 | |||
| 24e91208a4 | |||
| 15dec999e7 | |||
| d6b0635d3d | |||
| 336a93264e | |||
| 6398d1cff5 | |||
| 6926ed26ea | |||
| 6253f97a2d | |||
| 37ddbd0eac | |||
| 95fe7c8df2 | |||
| 79ae809020 | |||
| f19e302ba9 | |||
| e9c1d3f4b0 | |||
| 0f577d932b | |||
| 21a02c2e90 | |||
| 4e460d5f09 | |||
| f9de2f6bc6 | |||
| 2daa1b7814 | |||
| f99eeb8567 | |||
| 7069f75cb8 | |||
| 2cac7dac46 | |||
| 913c3c6554 | |||
| a5a4c0c89b | |||
| 8c8aca2fab | |||
| daf8e124ca | |||
| 38c4b724fe | |||
| 4d00487275 | |||
| a6831c26c1 | |||
| c363c7ebdb | |||
| 18ee6daf8a | |||
| 459eb426c3 | |||
| a0d670d2bf | |||
| d7b41212c1 | |||
| 2e1539eba4 | |||
| ee9521d87c | |||
| 8d8fc08bac | |||
| e79d304c79 | |||
| db03f03fd9 | |||
| 957403ebec | |||
| 6c32e1aaeb | |||
| 362e335c0b | |||
| ed6c49f874 | |||
| 47fcec5405 | |||
| d7239a45b6 | |||
| f13fb18c58 | |||
| d29644418d | |||
| ed9e426b26 | |||
| 659febf9ff | |||
| fca1fccfad | |||
| f713d63bab | |||
| 5a45e466cf | |||
| 742b24eb23 | |||
| 03369d2383 | |||
| 2605d662e0 | |||
| e8394ab5b5 | |||
| 8ad156a5c2 | |||
| f2d6fb6239 | |||
| e3a592c38d | |||
| 7e99819dda | |||
| a160d7f98d | |||
| 36cab842e8 | |||
| 7b7b86e327 | |||
| f4bfe638b6 | |||
| 0e9d242f05 |
+1
-1
@@ -2,4 +2,4 @@
|
||||
*.rpm
|
||||
i686
|
||||
x86_64
|
||||
libvirt-*.tar.gz
|
||||
libvirt-*.tar.xz
|
||||
|
||||
@@ -0,0 +1,145 @@
|
||||
From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= <berrange@redhat.com>
|
||||
Date: Mon, 18 Mar 2019 10:58:48 +0000
|
||||
Subject: [PATCH] storage: split off code for calling rbd_list
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
The rbd_list method has a quite unpleasant signature returning an
|
||||
array of strings in a single buffer instead of an array. It is
|
||||
being deprecated in favour of rbd_list2. To maintain clarity of
|
||||
code when supporting both APIs in parallel, split the rbd_list
|
||||
code out into a separate method.
|
||||
|
||||
In splitting this we now honour the rbd_list failures.
|
||||
|
||||
Reviewed-by: Ján Tomko <jtomko@redhat.com>
|
||||
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
|
||||
(cherry picked from commit 28c8403ed07896d6d7e06d7726ed904027206719)
|
||||
---
|
||||
src/storage/storage_backend_rbd.c | 83 +++++++++++++++++++++----------
|
||||
1 file changed, 58 insertions(+), 25 deletions(-)
|
||||
|
||||
diff --git a/src/storage/storage_backend_rbd.c b/src/storage/storage_backend_rbd.c
|
||||
index 2b7af1db23..0865163756 100644
|
||||
--- a/src/storage/storage_backend_rbd.c
|
||||
+++ b/src/storage/storage_backend_rbd.c
|
||||
@@ -565,19 +565,68 @@ volStorageBackendRBDRefreshVolInfo(virStorageVolDefPtr vol,
|
||||
return ret;
|
||||
}
|
||||
|
||||
+
|
||||
+static char **
|
||||
+virStorageBackendRBDGetVolNames(virStorageBackendRBDStatePtr ptr)
|
||||
+{
|
||||
+ char **names = NULL;
|
||||
+ size_t nnames = 0;
|
||||
+ int rc;
|
||||
+ size_t max_size = 1024;
|
||||
+ VIR_AUTOFREE(char *) namebuf = NULL;
|
||||
+ const char *name;
|
||||
+
|
||||
+ while (true) {
|
||||
+ if (VIR_ALLOC_N(namebuf, max_size) < 0)
|
||||
+ goto error;
|
||||
+
|
||||
+ rc = rbd_list(ptr->ioctx, namebuf, &max_size);
|
||||
+ if (rc >= 0)
|
||||
+ break;
|
||||
+ if (rc != -ERANGE) {
|
||||
+ virReportSystemError(-rc, "%s", _("Unable to list RBD images"));
|
||||
+ goto error;
|
||||
+ }
|
||||
+ VIR_FREE(namebuf);
|
||||
+ }
|
||||
+
|
||||
+ for (name = namebuf; name < namebuf + max_size;) {
|
||||
+ VIR_AUTOFREE(char *) namedup = NULL;
|
||||
+
|
||||
+ if (STREQ(name, ""))
|
||||
+ break;
|
||||
+
|
||||
+ if (VIR_STRDUP(namedup, name) < 0)
|
||||
+ goto error;
|
||||
+
|
||||
+ if (VIR_APPEND_ELEMENT(names, nnames, namedup) < 0)
|
||||
+ goto error;
|
||||
+
|
||||
+ name += strlen(name) + 1;
|
||||
+ }
|
||||
+
|
||||
+ if (VIR_EXPAND_N(names, nnames, 1) < 0)
|
||||
+ goto error;
|
||||
+
|
||||
+ return names;
|
||||
+
|
||||
+ error:
|
||||
+ virStringListFreeCount(names, nnames);
|
||||
+ return NULL;
|
||||
+}
|
||||
+
|
||||
+
|
||||
static int
|
||||
virStorageBackendRBDRefreshPool(virStoragePoolObjPtr pool)
|
||||
{
|
||||
- size_t max_size = 1024;
|
||||
int ret = -1;
|
||||
- int len = -1;
|
||||
int r = 0;
|
||||
- char *name;
|
||||
virStoragePoolDefPtr def = virStoragePoolObjGetDef(pool);
|
||||
virStorageBackendRBDStatePtr ptr = NULL;
|
||||
struct rados_cluster_stat_t clusterstat;
|
||||
struct rados_pool_stat_t poolstat;
|
||||
- VIR_AUTOFREE(char *) names = NULL;
|
||||
+ char **names = NULL;
|
||||
+ size_t i;
|
||||
|
||||
if (!(ptr = virStorageBackendRBDNewState(pool)))
|
||||
goto cleanup;
|
||||
@@ -602,33 +651,16 @@ virStorageBackendRBDRefreshPool(virStoragePoolObjPtr pool)
|
||||
def->source.name, clusterstat.kb, clusterstat.kb_avail,
|
||||
poolstat.num_bytes);
|
||||
|
||||
- while (true) {
|
||||
- if (VIR_ALLOC_N(names, max_size) < 0)
|
||||
- goto cleanup;
|
||||
-
|
||||
- len = rbd_list(ptr->ioctx, names, &max_size);
|
||||
- if (len >= 0)
|
||||
- break;
|
||||
- if (len != -ERANGE) {
|
||||
- VIR_WARN("%s", "A problem occurred while listing RBD images");
|
||||
- goto cleanup;
|
||||
- }
|
||||
- VIR_FREE(names);
|
||||
- }
|
||||
+ if (!(names = virStorageBackendRBDGetVolNames(ptr)))
|
||||
+ goto cleanup;
|
||||
|
||||
- for (name = names; name < names + max_size;) {
|
||||
+ for (i = 0; names[i] != NULL; i++) {
|
||||
VIR_AUTOPTR(virStorageVolDef) vol = NULL;
|
||||
|
||||
- if (STREQ(name, ""))
|
||||
- break;
|
||||
-
|
||||
if (VIR_ALLOC(vol) < 0)
|
||||
goto cleanup;
|
||||
|
||||
- if (VIR_STRDUP(vol->name, name) < 0)
|
||||
- goto cleanup;
|
||||
-
|
||||
- name += strlen(name) + 1;
|
||||
+ VIR_STEAL_PTR(vol->name, names[i]);
|
||||
|
||||
r = volStorageBackendRBDRefreshVolInfo(vol, pool, ptr);
|
||||
|
||||
@@ -661,6 +693,7 @@ virStorageBackendRBDRefreshPool(virStoragePoolObjPtr pool)
|
||||
ret = 0;
|
||||
|
||||
cleanup:
|
||||
+ virStringListFree(names);
|
||||
virStorageBackendRBDFreeState(&ptr);
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= <berrange@redhat.com>
|
||||
Date: Mon, 18 Mar 2019 11:11:38 +0000
|
||||
Subject: [PATCH] storage: add support for new rbd_list2 method
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
The rbd_list method has been deprecated in Ceph >= 14.0.0
|
||||
in favour of the new rbd_list2 method which populates an
|
||||
array of structs.
|
||||
|
||||
Reviewed-by: Ján Tomko <jtomko@redhat.com>
|
||||
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
|
||||
(cherry picked from commit 3aa190f2a43a632b542a6ba751a6c3ab4d51f1dd)
|
||||
---
|
||||
m4/virt-storage-rbd.m4 | 1 +
|
||||
src/storage/storage_backend_rbd.c | 43 +++++++++++++++++++++++++++++++
|
||||
2 files changed, 44 insertions(+)
|
||||
|
||||
diff --git a/m4/virt-storage-rbd.m4 b/m4/virt-storage-rbd.m4
|
||||
index 17e2115309..f3d9d04908 100644
|
||||
--- a/m4/virt-storage-rbd.m4
|
||||
+++ b/m4/virt-storage-rbd.m4
|
||||
@@ -33,6 +33,7 @@ AC_DEFUN([LIBVIRT_STORAGE_CHECK_RBD], [
|
||||
old_LIBS="$LIBS"
|
||||
LIBS="$LIBS $LIBRBD_LIBS"
|
||||
AC_CHECK_FUNCS([rbd_get_features],[],[LIBRBD_FOUND=no])
|
||||
+ AC_CHECK_FUNCS([rbd_list2])
|
||||
LIBS="$old_LIBS"
|
||||
fi
|
||||
|
||||
diff --git a/src/storage/storage_backend_rbd.c b/src/storage/storage_backend_rbd.c
|
||||
index 0865163756..bfc3419f9c 100644
|
||||
--- a/src/storage/storage_backend_rbd.c
|
||||
+++ b/src/storage/storage_backend_rbd.c
|
||||
@@ -566,6 +566,48 @@ volStorageBackendRBDRefreshVolInfo(virStorageVolDefPtr vol,
|
||||
}
|
||||
|
||||
|
||||
+#ifdef HAVE_RBD_LIST2
|
||||
+static char **
|
||||
+virStorageBackendRBDGetVolNames(virStorageBackendRBDStatePtr ptr)
|
||||
+{
|
||||
+ char **names = NULL;
|
||||
+ size_t nnames = 0;
|
||||
+ int rc;
|
||||
+ rbd_image_spec_t *images = NULL;
|
||||
+ size_t nimages = 16;
|
||||
+ size_t i;
|
||||
+
|
||||
+ while (true) {
|
||||
+ if (VIR_ALLOC_N(images, nimages) < 0)
|
||||
+ goto error;
|
||||
+
|
||||
+ rc = rbd_list2(ptr->ioctx, images, &nimages);
|
||||
+ if (rc >= 0)
|
||||
+ break;
|
||||
+ if (rc != -ERANGE) {
|
||||
+ virReportSystemError(-rc, "%s", _("Unable to list RBD images"));
|
||||
+ goto error;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (VIR_ALLOC_N(names, nimages + 1) < 0)
|
||||
+ goto error;
|
||||
+ nnames = nimages;
|
||||
+
|
||||
+ for (i = 0; i < nimages; i++)
|
||||
+ VIR_STEAL_PTR(names[i], images->name);
|
||||
+
|
||||
+ return names;
|
||||
+
|
||||
+ error:
|
||||
+ virStringListFreeCount(names, nnames);
|
||||
+ rbd_image_spec_list_cleanup(images, nimages);
|
||||
+ VIR_FREE(images);
|
||||
+ return NULL;
|
||||
+}
|
||||
+
|
||||
+#else /* ! HAVE_RBD_LIST2 */
|
||||
+
|
||||
static char **
|
||||
virStorageBackendRBDGetVolNames(virStorageBackendRBDStatePtr ptr)
|
||||
{
|
||||
@@ -614,6 +656,7 @@ virStorageBackendRBDGetVolNames(virStorageBackendRBDStatePtr ptr)
|
||||
virStringListFreeCount(names, nnames);
|
||||
return NULL;
|
||||
}
|
||||
+#endif /* ! HAVE_RBD_LIST2 */
|
||||
|
||||
|
||||
static int
|
||||
@@ -0,0 +1,133 @@
|
||||
From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= <berrange@redhat.com>
|
||||
Date: Mon, 18 Mar 2019 17:31:21 +0000
|
||||
Subject: [PATCH] network: improve error report when firewall chain creation
|
||||
fails
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
During startup we create some top level chains in which all
|
||||
virtual network firewall rules will be placed. The upfront
|
||||
creation is done to avoid slowing down creation of individual
|
||||
virtual networks by checking for chain existance every time.
|
||||
|
||||
There are some factors which can cause this upfront creation
|
||||
to fail and while a message will get into the libvirtd log
|
||||
this won't be seen by users who later try to start a virtual
|
||||
network. Instead they'll just get a message saying that the
|
||||
libvirt top level chain does not exist. This message is
|
||||
accurate, but unhelpful for solving the root cause.
|
||||
|
||||
This patch thus saves any error during daemon startup and
|
||||
reports it when trying to create a virtual network later.
|
||||
|
||||
Reviewed-by: Andrea Bolognani <abologna@redhat.com>
|
||||
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
|
||||
(cherry picked from commit 9f4e35dc73ec9e940aa61bc7c140c2b800218ef3)
|
||||
---
|
||||
src/network/bridge_driver.c | 3 +--
|
||||
src/network/bridge_driver_linux.c | 31 +++++++++++++++++++++-------
|
||||
src/network/bridge_driver_nop.c | 3 +--
|
||||
src/network/bridge_driver_platform.h | 2 +-
|
||||
4 files changed, 27 insertions(+), 12 deletions(-)
|
||||
|
||||
diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c
|
||||
index b3ca5b8a15..1da60f0a21 100644
|
||||
--- a/src/network/bridge_driver.c
|
||||
+++ b/src/network/bridge_driver.c
|
||||
@@ -2108,8 +2108,7 @@ static void
|
||||
networkReloadFirewallRules(virNetworkDriverStatePtr driver, bool startup)
|
||||
{
|
||||
VIR_INFO("Reloading iptables rules");
|
||||
- if (networkPreReloadFirewallRules(startup) < 0)
|
||||
- return;
|
||||
+ networkPreReloadFirewallRules(startup);
|
||||
virNetworkObjListForEach(driver->networks,
|
||||
networkReloadFirewallRulesHelper,
|
||||
NULL);
|
||||
diff --git a/src/network/bridge_driver_linux.c b/src/network/bridge_driver_linux.c
|
||||
index b10d0a6c4d..c899f4b6d0 100644
|
||||
--- a/src/network/bridge_driver_linux.c
|
||||
+++ b/src/network/bridge_driver_linux.c
|
||||
@@ -35,11 +35,25 @@ VIR_LOG_INIT("network.bridge_driver_linux");
|
||||
|
||||
#define PROC_NET_ROUTE "/proc/net/route"
|
||||
|
||||
-int networkPreReloadFirewallRules(bool startup)
|
||||
+static virErrorPtr errInit;
|
||||
+
|
||||
+void networkPreReloadFirewallRules(bool startup)
|
||||
{
|
||||
- int ret = iptablesSetupPrivateChains();
|
||||
- if (ret < 0)
|
||||
- return -1;
|
||||
+ int rc;
|
||||
+
|
||||
+ /* We create global rules upfront as we don't want
|
||||
+ * the perf hit of conditionally figuring out whether
|
||||
+ * to create them each time a network is started.
|
||||
+ *
|
||||
+ * Any errors here are saved to be reported at time
|
||||
+ * of starting the network though as that makes them
|
||||
+ * more likely to be seen by a human
|
||||
+ */
|
||||
+ rc = iptablesSetupPrivateChains();
|
||||
+ if (rc < 0) {
|
||||
+ errInit = virSaveLastError();
|
||||
+ virResetLastError();
|
||||
+ }
|
||||
|
||||
/*
|
||||
* If this is initial startup, and we just created the
|
||||
@@ -54,10 +68,8 @@ int networkPreReloadFirewallRules(bool startup)
|
||||
* rules will be present. Thus we can safely just tell it
|
||||
* to always delete from the builin chain
|
||||
*/
|
||||
- if (startup && ret == 1)
|
||||
+ if (startup && rc == 1)
|
||||
iptablesSetDeletePrivate(false);
|
||||
-
|
||||
- return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -671,6 +683,11 @@ int networkAddFirewallRules(virNetworkDefPtr def)
|
||||
virFirewallPtr fw = NULL;
|
||||
int ret = -1;
|
||||
|
||||
+ if (errInit) {
|
||||
+ virSetError(errInit);
|
||||
+ return -1;
|
||||
+ }
|
||||
+
|
||||
if (def->bridgeZone) {
|
||||
|
||||
/* if a firewalld zone has been specified, fail/log an error
|
||||
diff --git a/src/network/bridge_driver_nop.c b/src/network/bridge_driver_nop.c
|
||||
index a0e57012f9..ea9db338cb 100644
|
||||
--- a/src/network/bridge_driver_nop.c
|
||||
+++ b/src/network/bridge_driver_nop.c
|
||||
@@ -19,9 +19,8 @@
|
||||
|
||||
#include <config.h>
|
||||
|
||||
-int networkPreReloadFirewallRules(bool startup ATTRIBUTE_UNUSED)
|
||||
+void networkPreReloadFirewallRules(bool startup ATTRIBUTE_UNUSED)
|
||||
{
|
||||
- return 0;
|
||||
}
|
||||
|
||||
|
||||
diff --git a/src/network/bridge_driver_platform.h b/src/network/bridge_driver_platform.h
|
||||
index baeb22bc3e..95fd64bdc7 100644
|
||||
--- a/src/network/bridge_driver_platform.h
|
||||
+++ b/src/network/bridge_driver_platform.h
|
||||
@@ -58,7 +58,7 @@ struct _virNetworkDriverState {
|
||||
typedef struct _virNetworkDriverState virNetworkDriverState;
|
||||
typedef virNetworkDriverState *virNetworkDriverStatePtr;
|
||||
|
||||
-int networkPreReloadFirewallRules(bool startup);
|
||||
+void networkPreReloadFirewallRules(bool startup);
|
||||
void networkPostReloadFirewallRules(bool startup);
|
||||
|
||||
int networkCheckRouteCollision(virNetworkDefPtr def);
|
||||
@@ -0,0 +1,149 @@
|
||||
From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= <berrange@redhat.com>
|
||||
Date: Mon, 18 Mar 2019 16:49:32 +0000
|
||||
Subject: [PATCH] network: split setup of ipv4 and ipv6 top level chains
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
During startup libvirtd creates top level chains for both ipv4
|
||||
and ipv6 protocols. If this fails for any reason then startup
|
||||
of virtual networks is blocked.
|
||||
|
||||
The default virtual network, however, only requires use of ipv4
|
||||
and some servers have ipv6 disabled so it is expected that ipv6
|
||||
chain creation will fail. There could equally be servers with
|
||||
no ipv4, only ipv6.
|
||||
|
||||
This patch thus makes error reporting a little more fine grained
|
||||
so that it works more sensibly when either ipv4 or ipv6 is
|
||||
disabled on the server. Only the protocols that are actually
|
||||
used by the virtual network have errors reported.
|
||||
|
||||
Reviewed-by: Andrea Bolognani <abologna@redhat.com>
|
||||
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
|
||||
(cherry picked from commit 686803a1a2e1e0641916b1c9e2c7e3910fe598d4)
|
||||
---
|
||||
src/network/bridge_driver_linux.c | 34 +++++++++++++++++++++++++------
|
||||
src/util/viriptables.c | 14 ++++---------
|
||||
src/util/viriptables.h | 2 +-
|
||||
3 files changed, 33 insertions(+), 17 deletions(-)
|
||||
|
||||
diff --git a/src/network/bridge_driver_linux.c b/src/network/bridge_driver_linux.c
|
||||
index c899f4b6d0..50fc197134 100644
|
||||
--- a/src/network/bridge_driver_linux.c
|
||||
+++ b/src/network/bridge_driver_linux.c
|
||||
@@ -35,10 +35,12 @@ VIR_LOG_INIT("network.bridge_driver_linux");
|
||||
|
||||
#define PROC_NET_ROUTE "/proc/net/route"
|
||||
|
||||
-static virErrorPtr errInit;
|
||||
+static virErrorPtr errInitV4;
|
||||
+static virErrorPtr errInitV6;
|
||||
|
||||
void networkPreReloadFirewallRules(bool startup)
|
||||
{
|
||||
+ bool created = false;
|
||||
int rc;
|
||||
|
||||
/* We create global rules upfront as we don't want
|
||||
@@ -49,11 +51,21 @@ void networkPreReloadFirewallRules(bool startup)
|
||||
* of starting the network though as that makes them
|
||||
* more likely to be seen by a human
|
||||
*/
|
||||
- rc = iptablesSetupPrivateChains();
|
||||
+ rc = iptablesSetupPrivateChains(VIR_FIREWALL_LAYER_IPV4);
|
||||
if (rc < 0) {
|
||||
- errInit = virSaveLastError();
|
||||
+ errInitV4 = virSaveLastError();
|
||||
virResetLastError();
|
||||
}
|
||||
+ if (rc)
|
||||
+ created = true;
|
||||
+
|
||||
+ rc = iptablesSetupPrivateChains(VIR_FIREWALL_LAYER_IPV6);
|
||||
+ if (rc < 0) {
|
||||
+ errInitV6 = virSaveLastError();
|
||||
+ virResetLastError();
|
||||
+ }
|
||||
+ if (rc)
|
||||
+ created = true;
|
||||
|
||||
/*
|
||||
* If this is initial startup, and we just created the
|
||||
@@ -68,7 +80,7 @@ void networkPreReloadFirewallRules(bool startup)
|
||||
* rules will be present. Thus we can safely just tell it
|
||||
* to always delete from the builin chain
|
||||
*/
|
||||
- if (startup && rc == 1)
|
||||
+ if (startup && created)
|
||||
iptablesSetDeletePrivate(false);
|
||||
}
|
||||
|
||||
@@ -683,8 +695,18 @@ int networkAddFirewallRules(virNetworkDefPtr def)
|
||||
virFirewallPtr fw = NULL;
|
||||
int ret = -1;
|
||||
|
||||
- if (errInit) {
|
||||
- virSetError(errInit);
|
||||
+ if (errInitV4 &&
|
||||
+ (virNetworkDefGetIPByIndex(def, AF_INET, 0) ||
|
||||
+ virNetworkDefGetRouteByIndex(def, AF_INET, 0))) {
|
||||
+ virSetError(errInitV4);
|
||||
+ return -1;
|
||||
+ }
|
||||
+
|
||||
+ if (errInitV6 &&
|
||||
+ (virNetworkDefGetIPByIndex(def, AF_INET6, 0) ||
|
||||
+ virNetworkDefGetRouteByIndex(def, AF_INET6, 0) ||
|
||||
+ def->ipv6nogw)) {
|
||||
+ virSetError(errInitV6);
|
||||
return -1;
|
||||
}
|
||||
|
||||
diff --git a/src/util/viriptables.c b/src/util/viriptables.c
|
||||
index d67b640a3b..0e3c0ad73a 100644
|
||||
--- a/src/util/viriptables.c
|
||||
+++ b/src/util/viriptables.c
|
||||
@@ -127,7 +127,7 @@ iptablesPrivateChainCreate(virFirewallPtr fw,
|
||||
|
||||
|
||||
int
|
||||
-iptablesSetupPrivateChains(void)
|
||||
+iptablesSetupPrivateChains(virFirewallLayer layer)
|
||||
{
|
||||
virFirewallPtr fw = NULL;
|
||||
int ret = -1;
|
||||
@@ -143,17 +143,11 @@ iptablesSetupPrivateChains(void)
|
||||
};
|
||||
bool changed = false;
|
||||
iptablesGlobalChainData data[] = {
|
||||
- { VIR_FIREWALL_LAYER_IPV4, "filter",
|
||||
+ { layer, "filter",
|
||||
filter_chains, ARRAY_CARDINALITY(filter_chains), &changed },
|
||||
- { VIR_FIREWALL_LAYER_IPV4, "nat",
|
||||
+ { layer, "nat",
|
||||
natmangle_chains, ARRAY_CARDINALITY(natmangle_chains), &changed },
|
||||
- { VIR_FIREWALL_LAYER_IPV4, "mangle",
|
||||
- natmangle_chains, ARRAY_CARDINALITY(natmangle_chains), &changed },
|
||||
- { VIR_FIREWALL_LAYER_IPV6, "filter",
|
||||
- filter_chains, ARRAY_CARDINALITY(filter_chains), &changed },
|
||||
- { VIR_FIREWALL_LAYER_IPV6, "nat",
|
||||
- natmangle_chains, ARRAY_CARDINALITY(natmangle_chains), &changed },
|
||||
- { VIR_FIREWALL_LAYER_IPV6, "mangle",
|
||||
+ { layer, "mangle",
|
||||
natmangle_chains, ARRAY_CARDINALITY(natmangle_chains), &changed },
|
||||
};
|
||||
size_t i;
|
||||
diff --git a/src/util/viriptables.h b/src/util/viriptables.h
|
||||
index 903f390f89..e680407ec8 100644
|
||||
--- a/src/util/viriptables.h
|
||||
+++ b/src/util/viriptables.h
|
||||
@@ -24,7 +24,7 @@
|
||||
# include "virsocketaddr.h"
|
||||
# include "virfirewall.h"
|
||||
|
||||
-int iptablesSetupPrivateChains (void);
|
||||
+int iptablesSetupPrivateChains (virFirewallLayer layer);
|
||||
|
||||
void iptablesSetDeletePrivate (bool pvt);
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= <berrange@redhat.com>
|
||||
Date: Wed, 13 Mar 2019 16:21:15 +0000
|
||||
Subject: [PATCH] network: avoid trying to create global firewall rules if
|
||||
unprivileged
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
The unprivileged libvirtd does not have permission to create firewall
|
||||
rules, or bridge devices, or do anything to the host network in
|
||||
general. Historically we still activate the network driver though and
|
||||
let the network start API call fail.
|
||||
|
||||
The startup code path which reloads firewall rules on active networks
|
||||
would thus effectively be a no-op when unprivileged as it is impossible
|
||||
for there to be any active networks
|
||||
|
||||
With the change to use a global set of firewall chains, however, we now
|
||||
have code that is run unconditionally.
|
||||
|
||||
Ideally we would not register the network driver at all when
|
||||
unprivileged, but the entanglement with the virt drivers currently makes
|
||||
that impractical. As a temporary hack, we just make the firewall reload
|
||||
into a no-op.
|
||||
|
||||
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
|
||||
(cherry picked from commit 5d010c3df6152cf5fb00f1f67d22151241f4a8a2)
|
||||
---
|
||||
src/network/bridge_driver.c | 4 ++++
|
||||
1 file changed, 4 insertions(+)
|
||||
|
||||
diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c
|
||||
index 1da60f0a21..0e1d5efd8e 100644
|
||||
--- a/src/network/bridge_driver.c
|
||||
+++ b/src/network/bridge_driver.c
|
||||
@@ -2108,6 +2108,10 @@ static void
|
||||
networkReloadFirewallRules(virNetworkDriverStatePtr driver, bool startup)
|
||||
{
|
||||
VIR_INFO("Reloading iptables rules");
|
||||
+ /* Ideally we'd not even register the driver when unprivilegd
|
||||
+ * but until we untangle the virt driver that's not viable */
|
||||
+ if (!driver->privileged)
|
||||
+ return;
|
||||
networkPreReloadFirewallRules(startup);
|
||||
virNetworkObjListForEach(driver->networks,
|
||||
networkReloadFirewallRulesHelper,
|
||||
@@ -0,0 +1,57 @@
|
||||
From: Andrea Bolognani <abologna@redhat.com>
|
||||
Date: Wed, 27 Feb 2019 18:41:35 +0100
|
||||
Subject: [PATCH] qemu: Allow creating ppc64 guests with graphics and no USB
|
||||
mouse
|
||||
|
||||
The existing behavior for ppc64 guests is to always add a USB
|
||||
keyboard and mouse combo if graphics are present; unfortunately,
|
||||
this means any attempt to use a USB tablet will cause both pointing
|
||||
devices to show up in the guest, which in turn will result in poor
|
||||
user experience.
|
||||
|
||||
We can't just stop adding the USB mouse or start adding a USB tablet
|
||||
instead, because existing applications and users might rely on the
|
||||
current behavior; however, we can avoid adding the USB mouse if a USB
|
||||
tablet is already present, thus allowing users and applications to
|
||||
create guests that contain a single pointing device.
|
||||
|
||||
https://bugzilla.redhat.com/show_bug.cgi?id=1683681
|
||||
|
||||
Signed-off-by: Andrea Bolognani <abologna@redhat.com>
|
||||
Reviewed-by: Cole Robinson <crobinso@redhat.com>
|
||||
(cherry picked from commit 186bb479d0f409dc75175bea48a760838c479a6c)
|
||||
---
|
||||
src/qemu/qemu_domain.c | 20 ++++++++++++++++++++
|
||||
1 file changed, 20 insertions(+)
|
||||
|
||||
diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
|
||||
index 59fe1eb401..915795ab84 100644
|
||||
--- a/src/qemu/qemu_domain.c
|
||||
+++ b/src/qemu/qemu_domain.c
|
||||
@@ -3476,6 +3476,26 @@ qemuDomainDefAddDefaultDevices(virDomainDefPtr def,
|
||||
virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_S390) && def->memballoon)
|
||||
def->memballoon->model = VIR_DOMAIN_MEMBALLOON_MODEL_NONE;
|
||||
|
||||
+ if (addDefaultUSBMouse) {
|
||||
+ bool hasUSBTablet = false;
|
||||
+ size_t j;
|
||||
+
|
||||
+ for (j = 0; j < def->ninputs; j++) {
|
||||
+ if (def->inputs[j]->type == VIR_DOMAIN_INPUT_TYPE_TABLET &&
|
||||
+ def->inputs[j]->bus == VIR_DOMAIN_INPUT_BUS_USB) {
|
||||
+ hasUSBTablet = true;
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ /* Historically, we have automatically added USB keyboard and
|
||||
+ * mouse to some guests. While the former device is generally
|
||||
+ * safe to have, adding the latter is undesiderable if a USB
|
||||
+ * tablet is already present in the guest */
|
||||
+ if (hasUSBTablet)
|
||||
+ addDefaultUSBMouse = false;
|
||||
+ }
|
||||
+
|
||||
if (addDefaultUSBKBD &&
|
||||
def->ngraphics > 0 &&
|
||||
virDomainDefMaybeAddInput(def,
|
||||
@@ -0,0 +1,53 @@
|
||||
From: Pavel Hrdina <phrdina@redhat.com>
|
||||
Date: Tue, 19 Feb 2019 15:42:51 +0100
|
||||
Subject: [PATCH] util: implement virCgroupV2(Set|Get)CpusetMems
|
||||
|
||||
Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
|
||||
(cherry picked from commit 74e7da060543a87610b42fc6ba26a45b0a6e3974)
|
||||
---
|
||||
src/util/vircgroupv2.c | 25 +++++++++++++++++++++++++
|
||||
1 file changed, 25 insertions(+)
|
||||
|
||||
diff --git a/src/util/vircgroupv2.c b/src/util/vircgroupv2.c
|
||||
index e0fa8e1cc0..4cfbd52f2d 100644
|
||||
--- a/src/util/vircgroupv2.c
|
||||
+++ b/src/util/vircgroupv2.c
|
||||
@@ -1561,6 +1561,28 @@ virCgroupV2GetCpuacctStat(virCgroupPtr group,
|
||||
}
|
||||
|
||||
|
||||
+static int
|
||||
+virCgroupV2SetCpusetMems(virCgroupPtr group,
|
||||
+ const char *mems)
|
||||
+{
|
||||
+ return virCgroupSetValueStr(group,
|
||||
+ VIR_CGROUP_CONTROLLER_CPUSET,
|
||||
+ "cpuset.mems",
|
||||
+ mems);
|
||||
+}
|
||||
+
|
||||
+
|
||||
+static int
|
||||
+virCgroupV2GetCpusetMems(virCgroupPtr group,
|
||||
+ char **mems)
|
||||
+{
|
||||
+ return virCgroupGetValueStr(group,
|
||||
+ VIR_CGROUP_CONTROLLER_CPUSET,
|
||||
+ "cpuset.mems",
|
||||
+ mems);
|
||||
+}
|
||||
+
|
||||
+
|
||||
virCgroupBackend virCgroupV2Backend = {
|
||||
.type = VIR_CGROUP_BACKEND_TYPE_V2,
|
||||
|
||||
@@ -1620,6 +1642,9 @@ virCgroupBackend virCgroupV2Backend = {
|
||||
|
||||
.getCpuacctUsage = virCgroupV2GetCpuacctUsage,
|
||||
.getCpuacctStat = virCgroupV2GetCpuacctStat,
|
||||
+
|
||||
+ .setCpusetMems = virCgroupV2SetCpusetMems,
|
||||
+ .getCpusetMems = virCgroupV2GetCpusetMems,
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
From: Pavel Hrdina <phrdina@redhat.com>
|
||||
Date: Tue, 19 Feb 2019 15:53:34 +0100
|
||||
Subject: [PATCH] util: implement virCgroupV2(Set|Get)CpusetMemoryMigrate
|
||||
|
||||
Cgroups v2 don't have memory_migrate interface and the migration is
|
||||
enabled by default.
|
||||
|
||||
Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
|
||||
(cherry picked from commit 77c1cf4da2f761a91756c09fa4fd37ae1802e650)
|
||||
---
|
||||
src/util/vircgroupv2.c | 19 +++++++++++++++++++
|
||||
1 file changed, 19 insertions(+)
|
||||
|
||||
diff --git a/src/util/vircgroupv2.c b/src/util/vircgroupv2.c
|
||||
index 4cfbd52f2d..f3aa6ebc48 100644
|
||||
--- a/src/util/vircgroupv2.c
|
||||
+++ b/src/util/vircgroupv2.c
|
||||
@@ -1583,6 +1583,23 @@ virCgroupV2GetCpusetMems(virCgroupPtr group,
|
||||
}
|
||||
|
||||
|
||||
+static int
|
||||
+virCgroupV2SetCpusetMemoryMigrate(virCgroupPtr group ATTRIBUTE_UNUSED,
|
||||
+ bool migrate ATTRIBUTE_UNUSED)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+
|
||||
+static int
|
||||
+virCgroupV2GetCpusetMemoryMigrate(virCgroupPtr group ATTRIBUTE_UNUSED,
|
||||
+ bool *migrate)
|
||||
+{
|
||||
+ *migrate = true;
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+
|
||||
virCgroupBackend virCgroupV2Backend = {
|
||||
.type = VIR_CGROUP_BACKEND_TYPE_V2,
|
||||
|
||||
@@ -1645,6 +1662,8 @@ virCgroupBackend virCgroupV2Backend = {
|
||||
|
||||
.setCpusetMems = virCgroupV2SetCpusetMems,
|
||||
.getCpusetMems = virCgroupV2GetCpusetMems,
|
||||
+ .setCpusetMemoryMigrate = virCgroupV2SetCpusetMemoryMigrate,
|
||||
+ .getCpusetMemoryMigrate = virCgroupV2GetCpusetMemoryMigrate,
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
From: Pavel Hrdina <phrdina@redhat.com>
|
||||
Date: Tue, 19 Feb 2019 15:55:38 +0100
|
||||
Subject: [PATCH] util: implement virCgroupV2(Set|Get)CpusetCpus
|
||||
|
||||
Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
|
||||
(cherry picked from commit 3b72c84ff1c1b8b393ba9c2ccb004f8eb1ebda95)
|
||||
---
|
||||
src/util/vircgroupv2.c | 24 ++++++++++++++++++++++++
|
||||
1 file changed, 24 insertions(+)
|
||||
|
||||
diff --git a/src/util/vircgroupv2.c b/src/util/vircgroupv2.c
|
||||
index f3aa6ebc48..25afab1cad 100644
|
||||
--- a/src/util/vircgroupv2.c
|
||||
+++ b/src/util/vircgroupv2.c
|
||||
@@ -1600,6 +1600,28 @@ virCgroupV2GetCpusetMemoryMigrate(virCgroupPtr group ATTRIBUTE_UNUSED,
|
||||
}
|
||||
|
||||
|
||||
+static int
|
||||
+virCgroupV2SetCpusetCpus(virCgroupPtr group,
|
||||
+ const char *cpus)
|
||||
+{
|
||||
+ return virCgroupSetValueStr(group,
|
||||
+ VIR_CGROUP_CONTROLLER_CPUSET,
|
||||
+ "cpuset.cpus",
|
||||
+ cpus);
|
||||
+}
|
||||
+
|
||||
+
|
||||
+static int
|
||||
+virCgroupV2GetCpusetCpus(virCgroupPtr group,
|
||||
+ char **cpus)
|
||||
+{
|
||||
+ return virCgroupGetValueStr(group,
|
||||
+ VIR_CGROUP_CONTROLLER_CPUSET,
|
||||
+ "cpuset.cpus",
|
||||
+ cpus);
|
||||
+}
|
||||
+
|
||||
+
|
||||
virCgroupBackend virCgroupV2Backend = {
|
||||
.type = VIR_CGROUP_BACKEND_TYPE_V2,
|
||||
|
||||
@@ -1664,6 +1686,8 @@ virCgroupBackend virCgroupV2Backend = {
|
||||
.getCpusetMems = virCgroupV2GetCpusetMems,
|
||||
.setCpusetMemoryMigrate = virCgroupV2SetCpusetMemoryMigrate,
|
||||
.getCpusetMemoryMigrate = virCgroupV2GetCpusetMemoryMigrate,
|
||||
+ .setCpusetCpus = virCgroupV2SetCpusetCpus,
|
||||
+ .getCpusetCpus = virCgroupV2GetCpusetCpus,
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
From: Pavel Hrdina <phrdina@redhat.com>
|
||||
Date: Wed, 20 Feb 2019 13:50:23 +0100
|
||||
Subject: [PATCH] util: enable cgroups v2 cpuset controller for threads
|
||||
|
||||
When we create cgroup for qemu threads we need to enable cpuset
|
||||
controller in order to use it.
|
||||
|
||||
Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
|
||||
(cherry picked from commit a6aedcf39bd3212a3cd624b765bb724fd36d6a8a)
|
||||
---
|
||||
src/util/vircgroupv2.c | 6 ++++++
|
||||
1 file changed, 6 insertions(+)
|
||||
|
||||
diff --git a/src/util/vircgroupv2.c b/src/util/vircgroupv2.c
|
||||
index 25afab1cad..4084929c5a 100644
|
||||
--- a/src/util/vircgroupv2.c
|
||||
+++ b/src/util/vircgroupv2.c
|
||||
@@ -400,6 +400,12 @@ virCgroupV2MakeGroup(virCgroupPtr parent ATTRIBUTE_UNUSED,
|
||||
VIR_CGROUP_CONTROLLER_CPU) < 0) {
|
||||
return -1;
|
||||
}
|
||||
+
|
||||
+ if (virCgroupV2HasController(parent, VIR_CGROUP_CONTROLLER_CPUSET) &&
|
||||
+ virCgroupV2EnableController(parent,
|
||||
+ VIR_CGROUP_CONTROLLER_CPUSET) < 0) {
|
||||
+ return -1;
|
||||
+ }
|
||||
} else {
|
||||
size_t i;
|
||||
for (i = 0; i < VIR_CGROUP_CONTROLLER_LAST; i++) {
|
||||
@@ -0,0 +1,51 @@
|
||||
From: Jiri Denemark <jdenemar@redhat.com>
|
||||
Date: Fri, 5 Apr 2019 11:33:32 +0200
|
||||
Subject: [PATCH] cpu_x86: Do not cache microcode version
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
The microcode version checks are used to invalidate cached CPU data we
|
||||
get from QEMU. To minimize /proc/cpuinfo parsing the microcode version
|
||||
was only read when libvirtd started and cached for the daemon's
|
||||
lifetime. However, the CPU microcode can change anytime (updating the
|
||||
microcode package can automatically upload it to the CPU) and we need to
|
||||
stop caching it to avoid using stale CPU model data.
|
||||
|
||||
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
|
||||
Reviewed-by: Ján Tomko <jtomko@redhat.com>
|
||||
(cherry picked from commit be46f613261d3b655a1f15afd635087e68a9c39b)
|
||||
---
|
||||
src/cpu/cpu_x86.c | 5 +----
|
||||
1 file changed, 1 insertion(+), 4 deletions(-)
|
||||
|
||||
diff --git a/src/cpu/cpu_x86.c b/src/cpu/cpu_x86.c
|
||||
index d3a88da21d..470de83a87 100644
|
||||
--- a/src/cpu/cpu_x86.c
|
||||
+++ b/src/cpu/cpu_x86.c
|
||||
@@ -165,7 +165,6 @@ struct _virCPUx86Map {
|
||||
};
|
||||
|
||||
static virCPUx86MapPtr cpuMap;
|
||||
-static unsigned int microcodeVersion;
|
||||
|
||||
int virCPUx86DriverOnceInit(void);
|
||||
VIR_ONCE_GLOBAL_INIT(virCPUx86Driver);
|
||||
@@ -1332,8 +1331,6 @@ virCPUx86DriverOnceInit(void)
|
||||
if (!(cpuMap = virCPUx86LoadMap()))
|
||||
return -1;
|
||||
|
||||
- microcodeVersion = virHostCPUGetMicrocodeVersion();
|
||||
-
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2373,7 +2370,7 @@ virCPUx86GetHost(virCPUDefPtr cpu,
|
||||
goto cleanup;
|
||||
|
||||
ret = x86DecodeCPUData(cpu, cpuData, models);
|
||||
- cpu->microcodeVersion = microcodeVersion;
|
||||
+ cpu->microcodeVersion = virHostCPUGetMicrocodeVersion();
|
||||
|
||||
cleanup:
|
||||
virCPUx86DataFree(cpuData);
|
||||
@@ -0,0 +1,143 @@
|
||||
From: Jiri Denemark <jdenemar@redhat.com>
|
||||
Date: Fri, 12 Apr 2019 21:21:05 +0200
|
||||
Subject: [PATCH] qemu: Don't cache microcode version
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
My earlier commit be46f61326 was incomplete. It removed caching of
|
||||
microcode version in the CPU driver, which means the capabilities XML
|
||||
will see the correct microcode version. But it is also cached in the
|
||||
QEMU capabilities cache where it is used to detect whether we need to
|
||||
reprobe QEMU. By missing the second place, the original commit
|
||||
be46f61326 made the situation even worse since libvirt would report
|
||||
correct microcode version while still using the old host CPU model
|
||||
(visible in domain capabilities XML).
|
||||
|
||||
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
|
||||
Reviewed-by: Ján Tomko <jtomko@redhat.com>
|
||||
(cherry picked from commit 673c62a3b7855a0685d8f116e227c402720b9ee9)
|
||||
---
|
||||
src/qemu/qemu_capabilities.c | 12 ++++++++----
|
||||
src/qemu/qemu_capabilities.h | 3 +--
|
||||
src/qemu/qemu_driver.c | 9 +--------
|
||||
tests/testutilsqemu.c | 2 +-
|
||||
4 files changed, 11 insertions(+), 15 deletions(-)
|
||||
|
||||
diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c
|
||||
index b48bcbebee..e5b1c90253 100644
|
||||
--- a/src/qemu/qemu_capabilities.c
|
||||
+++ b/src/qemu/qemu_capabilities.c
|
||||
@@ -4487,7 +4487,7 @@ virQEMUCapsNewData(const char *binary,
|
||||
priv->libDir,
|
||||
priv->runUid,
|
||||
priv->runGid,
|
||||
- priv->microcodeVersion,
|
||||
+ virHostCPUGetMicrocodeVersion(),
|
||||
priv->kernelVersion);
|
||||
}
|
||||
|
||||
@@ -4570,8 +4570,7 @@ virFileCachePtr
|
||||
virQEMUCapsCacheNew(const char *libDir,
|
||||
const char *cacheDir,
|
||||
uid_t runUid,
|
||||
- gid_t runGid,
|
||||
- unsigned int microcodeVersion)
|
||||
+ gid_t runGid)
|
||||
{
|
||||
char *capsCacheDir = NULL;
|
||||
virFileCachePtr cache = NULL;
|
||||
@@ -4595,7 +4594,6 @@ virQEMUCapsCacheNew(const char *libDir,
|
||||
|
||||
priv->runUid = runUid;
|
||||
priv->runGid = runGid;
|
||||
- priv->microcodeVersion = microcodeVersion;
|
||||
priv->kvmUsable = VIR_TRISTATE_BOOL_ABSENT;
|
||||
|
||||
if (uname(&uts) == 0 &&
|
||||
@@ -4617,8 +4615,11 @@ virQEMUCapsPtr
|
||||
virQEMUCapsCacheLookup(virFileCachePtr cache,
|
||||
const char *binary)
|
||||
{
|
||||
+ virQEMUCapsCachePrivPtr priv = virFileCacheGetPriv(cache);
|
||||
virQEMUCapsPtr ret = NULL;
|
||||
|
||||
+ priv->microcodeVersion = virHostCPUGetMicrocodeVersion();
|
||||
+
|
||||
ret = virFileCacheLookup(cache, binary);
|
||||
|
||||
VIR_DEBUG("Returning caps %p for %s", ret, binary);
|
||||
@@ -4672,6 +4673,7 @@ virQEMUCapsPtr
|
||||
virQEMUCapsCacheLookupByArch(virFileCachePtr cache,
|
||||
virArch arch)
|
||||
{
|
||||
+ virQEMUCapsCachePrivPtr priv = virFileCacheGetPriv(cache);
|
||||
virQEMUCapsPtr ret = NULL;
|
||||
const char *binaryFilters[] = {
|
||||
"qemu-system-",
|
||||
@@ -4684,6 +4686,8 @@ virQEMUCapsCacheLookupByArch(virFileCachePtr cache,
|
||||
size_t i;
|
||||
size_t j;
|
||||
|
||||
+ priv->microcodeVersion = virHostCPUGetMicrocodeVersion();
|
||||
+
|
||||
for (i = 0; i < ARRAY_CARDINALITY(binaryFilters); i++) {
|
||||
for (j = 0; j < ARRAY_CARDINALITY(archs); j++) {
|
||||
struct virQEMUCapsSearchData data = {
|
||||
diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h
|
||||
index ba84052bca..a6a655ac0f 100644
|
||||
--- a/src/qemu/qemu_capabilities.h
|
||||
+++ b/src/qemu/qemu_capabilities.h
|
||||
@@ -587,8 +587,7 @@ void virQEMUCapsFilterByMachineType(virQEMUCapsPtr qemuCaps,
|
||||
virFileCachePtr virQEMUCapsCacheNew(const char *libDir,
|
||||
const char *cacheDir,
|
||||
uid_t uid,
|
||||
- gid_t gid,
|
||||
- unsigned int microcodeVersion);
|
||||
+ gid_t gid);
|
||||
virQEMUCapsPtr virQEMUCapsCacheLookup(virFileCachePtr cache,
|
||||
const char *binary);
|
||||
virQEMUCapsPtr virQEMUCapsCacheLookupCopy(virFileCachePtr cache,
|
||||
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
|
||||
index 36426cd65a..75d31efd14 100644
|
||||
--- a/src/qemu/qemu_driver.c
|
||||
+++ b/src/qemu/qemu_driver.c
|
||||
@@ -585,8 +585,6 @@ qemuStateInitialize(bool privileged,
|
||||
char *hugepagePath = NULL;
|
||||
char *memoryBackingPath = NULL;
|
||||
size_t i;
|
||||
- virCPUDefPtr hostCPU = NULL;
|
||||
- unsigned int microcodeVersion = 0;
|
||||
|
||||
if (VIR_ALLOC(qemu_driver) < 0)
|
||||
return -1;
|
||||
@@ -809,15 +807,10 @@ 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,
|
||||
- microcodeVersion);
|
||||
+ run_gid);
|
||||
if (!qemu_driver->qemuCapsCache)
|
||||
goto error;
|
||||
|
||||
diff --git a/tests/testutilsqemu.c b/tests/testutilsqemu.c
|
||||
index 1736bad032..e30c0599ad 100644
|
||||
--- a/tests/testutilsqemu.c
|
||||
+++ b/tests/testutilsqemu.c
|
||||
@@ -740,7 +740,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, 0);
|
||||
+ driver->qemuCapsCache = virQEMUCapsCacheNew("/dev/null", "/dev/null", 0, 0);
|
||||
if (!driver->qemuCapsCache)
|
||||
goto error;
|
||||
|
||||
@@ -0,0 +1,876 @@
|
||||
From: Jiri Denemark <jdenemar@redhat.com>
|
||||
Date: Tue, 9 Apr 2019 12:35:51 +0200
|
||||
Subject: [PATCH] cputest: Add data for Intel(R) Xeon(R) CPU E3-1225 v5
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
|
||||
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
|
||||
(cherry picked from commit 5cd9db3ac11e88846cbcf95fad9f6fae9d880dee)
|
||||
---
|
||||
tests/cputest.c | 1 +
|
||||
.../x86_64-cpuid-Xeon-E3-1225-v5-disabled.xml | 7 +
|
||||
.../x86_64-cpuid-Xeon-E3-1225-v5-enabled.xml | 8 +
|
||||
.../x86_64-cpuid-Xeon-E3-1225-v5-guest.xml | 28 +
|
||||
.../x86_64-cpuid-Xeon-E3-1225-v5-host.xml | 29 +
|
||||
.../x86_64-cpuid-Xeon-E3-1225-v5-json.xml | 11 +
|
||||
.../x86_64-cpuid-Xeon-E3-1225-v5.json | 652 ++++++++++++++++++
|
||||
.../x86_64-cpuid-Xeon-E3-1225-v5.sig | 4 +
|
||||
.../x86_64-cpuid-Xeon-E3-1225-v5.xml | 47 ++
|
||||
9 files changed, 787 insertions(+)
|
||||
create mode 100644 tests/cputestdata/x86_64-cpuid-Xeon-E3-1225-v5-disabled.xml
|
||||
create mode 100644 tests/cputestdata/x86_64-cpuid-Xeon-E3-1225-v5-enabled.xml
|
||||
create mode 100644 tests/cputestdata/x86_64-cpuid-Xeon-E3-1225-v5-guest.xml
|
||||
create mode 100644 tests/cputestdata/x86_64-cpuid-Xeon-E3-1225-v5-host.xml
|
||||
create mode 100644 tests/cputestdata/x86_64-cpuid-Xeon-E3-1225-v5-json.xml
|
||||
create mode 100644 tests/cputestdata/x86_64-cpuid-Xeon-E3-1225-v5.json
|
||||
create mode 100644 tests/cputestdata/x86_64-cpuid-Xeon-E3-1225-v5.sig
|
||||
create mode 100644 tests/cputestdata/x86_64-cpuid-Xeon-E3-1225-v5.xml
|
||||
|
||||
diff --git a/tests/cputest.c b/tests/cputest.c
|
||||
index b75d864d8e..5866ca9edb 100644
|
||||
--- a/tests/cputest.c
|
||||
+++ b/tests/cputest.c
|
||||
@@ -1184,6 +1184,7 @@ mymain(void)
|
||||
DO_TEST_CPUID(VIR_ARCH_X86_64, "Phenom-B95", JSON_HOST);
|
||||
DO_TEST_CPUID(VIR_ARCH_X86_64, "Ryzen-7-1800X-Eight-Core", JSON_HOST);
|
||||
DO_TEST_CPUID(VIR_ARCH_X86_64, "Xeon-5110", JSON_NONE);
|
||||
+ DO_TEST_CPUID(VIR_ARCH_X86_64, "Xeon-E3-1225-v5", JSON_MODELS);
|
||||
DO_TEST_CPUID(VIR_ARCH_X86_64, "Xeon-E3-1245-v5", JSON_MODELS);
|
||||
DO_TEST_CPUID(VIR_ARCH_X86_64, "Xeon-E5-2609-v3", JSON_MODELS);
|
||||
DO_TEST_CPUID(VIR_ARCH_X86_64, "Xeon-E5-2623-v4", JSON_MODELS);
|
||||
diff --git a/tests/cputestdata/x86_64-cpuid-Xeon-E3-1225-v5-disabled.xml b/tests/cputestdata/x86_64-cpuid-Xeon-E3-1225-v5-disabled.xml
|
||||
new file mode 100644
|
||||
index 0000000000..ce51903e53
|
||||
--- /dev/null
|
||||
+++ b/tests/cputestdata/x86_64-cpuid-Xeon-E3-1225-v5-disabled.xml
|
||||
@@ -0,0 +1,7 @@
|
||||
+<!-- Features disabled by QEMU -->
|
||||
+<cpudata arch='x86'>
|
||||
+ <cpuid eax_in='0x00000001' ecx_in='0x00' eax='0x00000000' ebx='0x00000000' ecx='0x0800c1fc' edx='0xb0600000'/>
|
||||
+ <cpuid eax_in='0x00000007' ecx_in='0x00' eax='0x00000000' ebx='0x02000000' ecx='0x00000000' edx='0x00000000'/>
|
||||
+ <cpuid eax_in='0x0000000d' ecx_in='0x01' eax='0x00000008' ebx='0x00000000' ecx='0x00000000' edx='0x00000000'/>
|
||||
+ <cpuid eax_in='0x80000007' ecx_in='0x00' eax='0x00000000' ebx='0x00000000' ecx='0x00000000' edx='0x00000100'/>
|
||||
+</cpudata>
|
||||
diff --git a/tests/cputestdata/x86_64-cpuid-Xeon-E3-1225-v5-enabled.xml b/tests/cputestdata/x86_64-cpuid-Xeon-E3-1225-v5-enabled.xml
|
||||
new file mode 100644
|
||||
index 0000000000..0deca9fba6
|
||||
--- /dev/null
|
||||
+++ b/tests/cputestdata/x86_64-cpuid-Xeon-E3-1225-v5-enabled.xml
|
||||
@@ -0,0 +1,8 @@
|
||||
+<!-- Features enabled by QEMU -->
|
||||
+<cpudata arch='x86'>
|
||||
+ <cpuid eax_in='0x00000001' ecx_in='0x00' eax='0x00000000' ebx='0x00000000' ecx='0xf7fa3203' edx='0x0f8bfbff'/>
|
||||
+ <cpuid eax_in='0x00000006' ecx_in='0x00' eax='0x00000004' ebx='0x00000000' ecx='0x00000000' edx='0x00000000'/>
|
||||
+ <cpuid eax_in='0x00000007' ecx_in='0x00' eax='0x00000000' ebx='0x009c4fbb' ecx='0x00000000' edx='0x8c000000'/>
|
||||
+ <cpuid eax_in='0x0000000d' ecx_in='0x01' eax='0x00000007' ebx='0x00000000' ecx='0x00000000' edx='0x00000000'/>
|
||||
+ <cpuid eax_in='0x80000001' ecx_in='0x00' eax='0x00000000' ebx='0x00000000' ecx='0x00000121' edx='0x2c100800'/>
|
||||
+</cpudata>
|
||||
diff --git a/tests/cputestdata/x86_64-cpuid-Xeon-E3-1225-v5-guest.xml b/tests/cputestdata/x86_64-cpuid-Xeon-E3-1225-v5-guest.xml
|
||||
new file mode 100644
|
||||
index 0000000000..70a0fc3286
|
||||
--- /dev/null
|
||||
+++ b/tests/cputestdata/x86_64-cpuid-Xeon-E3-1225-v5-guest.xml
|
||||
@@ -0,0 +1,28 @@
|
||||
+<cpu mode='custom' match='exact'>
|
||||
+ <model fallback='forbid'>Skylake-Client-IBRS</model>
|
||||
+ <vendor>Intel</vendor>
|
||||
+ <feature policy='require' name='ds'/>
|
||||
+ <feature policy='require' name='acpi'/>
|
||||
+ <feature policy='require' name='ss'/>
|
||||
+ <feature policy='require' name='ht'/>
|
||||
+ <feature policy='require' name='tm'/>
|
||||
+ <feature policy='require' name='pbe'/>
|
||||
+ <feature policy='require' name='dtes64'/>
|
||||
+ <feature policy='require' name='monitor'/>
|
||||
+ <feature policy='require' name='ds_cpl'/>
|
||||
+ <feature policy='require' name='vmx'/>
|
||||
+ <feature policy='require' name='smx'/>
|
||||
+ <feature policy='require' name='est'/>
|
||||
+ <feature policy='require' name='tm2'/>
|
||||
+ <feature policy='require' name='xtpr'/>
|
||||
+ <feature policy='require' name='pdcm'/>
|
||||
+ <feature policy='require' name='osxsave'/>
|
||||
+ <feature policy='require' name='tsc_adjust'/>
|
||||
+ <feature policy='require' name='clflushopt'/>
|
||||
+ <feature policy='require' name='intel-pt'/>
|
||||
+ <feature policy='require' name='stibp'/>
|
||||
+ <feature policy='require' name='ssbd'/>
|
||||
+ <feature policy='require' name='xsaves'/>
|
||||
+ <feature policy='require' name='pdpe1gb'/>
|
||||
+ <feature policy='require' name='invtsc'/>
|
||||
+</cpu>
|
||||
diff --git a/tests/cputestdata/x86_64-cpuid-Xeon-E3-1225-v5-host.xml b/tests/cputestdata/x86_64-cpuid-Xeon-E3-1225-v5-host.xml
|
||||
new file mode 100644
|
||||
index 0000000000..bbdfb6aa61
|
||||
--- /dev/null
|
||||
+++ b/tests/cputestdata/x86_64-cpuid-Xeon-E3-1225-v5-host.xml
|
||||
@@ -0,0 +1,29 @@
|
||||
+<cpu>
|
||||
+ <arch>x86_64</arch>
|
||||
+ <model>Skylake-Client-IBRS</model>
|
||||
+ <vendor>Intel</vendor>
|
||||
+ <feature name='ds'/>
|
||||
+ <feature name='acpi'/>
|
||||
+ <feature name='ss'/>
|
||||
+ <feature name='ht'/>
|
||||
+ <feature name='tm'/>
|
||||
+ <feature name='pbe'/>
|
||||
+ <feature name='dtes64'/>
|
||||
+ <feature name='monitor'/>
|
||||
+ <feature name='ds_cpl'/>
|
||||
+ <feature name='vmx'/>
|
||||
+ <feature name='smx'/>
|
||||
+ <feature name='est'/>
|
||||
+ <feature name='tm2'/>
|
||||
+ <feature name='xtpr'/>
|
||||
+ <feature name='pdcm'/>
|
||||
+ <feature name='osxsave'/>
|
||||
+ <feature name='tsc_adjust'/>
|
||||
+ <feature name='clflushopt'/>
|
||||
+ <feature name='intel-pt'/>
|
||||
+ <feature name='stibp'/>
|
||||
+ <feature name='ssbd'/>
|
||||
+ <feature name='xsaves'/>
|
||||
+ <feature name='pdpe1gb'/>
|
||||
+ <feature name='invtsc'/>
|
||||
+</cpu>
|
||||
diff --git a/tests/cputestdata/x86_64-cpuid-Xeon-E3-1225-v5-json.xml b/tests/cputestdata/x86_64-cpuid-Xeon-E3-1225-v5-json.xml
|
||||
new file mode 100644
|
||||
index 0000000000..1f321db273
|
||||
--- /dev/null
|
||||
+++ b/tests/cputestdata/x86_64-cpuid-Xeon-E3-1225-v5-json.xml
|
||||
@@ -0,0 +1,11 @@
|
||||
+<cpu mode='custom' match='exact'>
|
||||
+ <model fallback='forbid'>Skylake-Client-IBRS</model>
|
||||
+ <vendor>Intel</vendor>
|
||||
+ <feature policy='require' name='ss'/>
|
||||
+ <feature policy='require' name='hypervisor'/>
|
||||
+ <feature policy='require' name='tsc_adjust'/>
|
||||
+ <feature policy='require' name='clflushopt'/>
|
||||
+ <feature policy='require' name='stibp'/>
|
||||
+ <feature policy='require' name='ssbd'/>
|
||||
+ <feature policy='require' name='pdpe1gb'/>
|
||||
+</cpu>
|
||||
diff --git a/tests/cputestdata/x86_64-cpuid-Xeon-E3-1225-v5.json b/tests/cputestdata/x86_64-cpuid-Xeon-E3-1225-v5.json
|
||||
new file mode 100644
|
||||
index 0000000000..084747556b
|
||||
--- /dev/null
|
||||
+++ b/tests/cputestdata/x86_64-cpuid-Xeon-E3-1225-v5.json
|
||||
@@ -0,0 +1,652 @@
|
||||
+{
|
||||
+ "return": {
|
||||
+ "model": {
|
||||
+ "name": "base",
|
||||
+ "props": {
|
||||
+ "phys-bits": 0,
|
||||
+ "core-id": -1,
|
||||
+ "xlevel": 2147483656,
|
||||
+ "cmov": true,
|
||||
+ "ia64": false,
|
||||
+ "aes": true,
|
||||
+ "mmx": true,
|
||||
+ "rdpid": false,
|
||||
+ "arat": true,
|
||||
+ "gfni": false,
|
||||
+ "pause-filter": false,
|
||||
+ "xsavec": true,
|
||||
+ "intel-pt": false,
|
||||
+ "osxsave": false,
|
||||
+ "hv-frequencies": false,
|
||||
+ "tsc-frequency": 0,
|
||||
+ "xd": true,
|
||||
+ "hv-vendor-id": "",
|
||||
+ "kvm-asyncpf": true,
|
||||
+ "kvm_asyncpf": true,
|
||||
+ "perfctr_core": false,
|
||||
+ "perfctr-core": false,
|
||||
+ "mpx": true,
|
||||
+ "pbe": false,
|
||||
+ "decodeassists": false,
|
||||
+ "avx512cd": false,
|
||||
+ "sse4_1": true,
|
||||
+ "sse4.1": true,
|
||||
+ "sse4-1": true,
|
||||
+ "family": 6,
|
||||
+ "legacy-cache": true,
|
||||
+ "vmware-cpuid-freq": true,
|
||||
+ "avx512f": false,
|
||||
+ "msr": true,
|
||||
+ "mce": true,
|
||||
+ "mca": true,
|
||||
+ "hv-runtime": false,
|
||||
+ "xcrypt": false,
|
||||
+ "thread-id": -1,
|
||||
+ "min-level": 13,
|
||||
+ "xgetbv1": true,
|
||||
+ "cid": false,
|
||||
+ "hv-relaxed": false,
|
||||
+ "hv-crash": false,
|
||||
+ "ds": false,
|
||||
+ "fxsr": true,
|
||||
+ "xsaveopt": true,
|
||||
+ "xtpr": false,
|
||||
+ "avx512vl": false,
|
||||
+ "avx512-vpopcntdq": false,
|
||||
+ "phe": false,
|
||||
+ "extapic": false,
|
||||
+ "3dnowprefetch": true,
|
||||
+ "avx512vbmi2": false,
|
||||
+ "cr8legacy": false,
|
||||
+ "stibp": true,
|
||||
+ "cpuid-0xb": true,
|
||||
+ "xcrypt-en": false,
|
||||
+ "kvm_pv_eoi": true,
|
||||
+ "apic-id": 4294967295,
|
||||
+ "pn": false,
|
||||
+ "dca": false,
|
||||
+ "vendor": "GenuineIntel",
|
||||
+ "pku": false,
|
||||
+ "smx": false,
|
||||
+ "cmp_legacy": false,
|
||||
+ "cmp-legacy": false,
|
||||
+ "node-id": -1,
|
||||
+ "avx512-4fmaps": false,
|
||||
+ "vmcb_clean": false,
|
||||
+ "vmcb-clean": false,
|
||||
+ "3dnowext": false,
|
||||
+ "hle": true,
|
||||
+ "npt": false,
|
||||
+ "memory": "/machine/unattached/system[0]",
|
||||
+ "clwb": false,
|
||||
+ "lbrv": false,
|
||||
+ "adx": true,
|
||||
+ "ss": true,
|
||||
+ "pni": true,
|
||||
+ "svm_lock": false,
|
||||
+ "svm-lock": false,
|
||||
+ "pfthreshold": false,
|
||||
+ "smep": true,
|
||||
+ "smap": true,
|
||||
+ "x2apic": true,
|
||||
+ "avx512vbmi": false,
|
||||
+ "avx512vnni": false,
|
||||
+ "hv-stimer": false,
|
||||
+ "i64": true,
|
||||
+ "flushbyasid": false,
|
||||
+ "f16c": true,
|
||||
+ "ace2-en": false,
|
||||
+ "pat": true,
|
||||
+ "pae": true,
|
||||
+ "sse": true,
|
||||
+ "phe-en": false,
|
||||
+ "kvm_nopiodelay": true,
|
||||
+ "kvm-nopiodelay": true,
|
||||
+ "tm": false,
|
||||
+ "kvmclock-stable-bit": true,
|
||||
+ "hypervisor": true,
|
||||
+ "socket-id": -1,
|
||||
+ "pcommit": false,
|
||||
+ "syscall": true,
|
||||
+ "level": 13,
|
||||
+ "avx512dq": false,
|
||||
+ "svm": false,
|
||||
+ "full-cpuid-auto-level": true,
|
||||
+ "hv-reset": false,
|
||||
+ "invtsc": false,
|
||||
+ "sse3": true,
|
||||
+ "sse2": true,
|
||||
+ "ssbd": true,
|
||||
+ "est": false,
|
||||
+ "avx512ifma": false,
|
||||
+ "tm2": false,
|
||||
+ "kvm-pv-eoi": true,
|
||||
+ "cx8": true,
|
||||
+ "kvm_mmu": false,
|
||||
+ "kvm-mmu": false,
|
||||
+ "sse4_2": true,
|
||||
+ "sse4.2": true,
|
||||
+ "sse4-2": true,
|
||||
+ "pge": true,
|
||||
+ "fill-mtrr-mask": true,
|
||||
+ "avx512bitalg": false,
|
||||
+ "nodeid_msr": false,
|
||||
+ "pdcm": false,
|
||||
+ "movbe": true,
|
||||
+ "model": 94,
|
||||
+ "nrip_save": false,
|
||||
+ "nrip-save": false,
|
||||
+ "kvm_pv_unhalt": true,
|
||||
+ "ssse3": true,
|
||||
+ "sse4a": false,
|
||||
+ "invpcid": true,
|
||||
+ "pdpe1gb": true,
|
||||
+ "tsc-deadline": true,
|
||||
+ "fma": true,
|
||||
+ "cx16": true,
|
||||
+ "de": true,
|
||||
+ "enforce": false,
|
||||
+ "stepping": 3,
|
||||
+ "xsave": true,
|
||||
+ "clflush": true,
|
||||
+ "skinit": false,
|
||||
+ "tsc": true,
|
||||
+ "tce": false,
|
||||
+ "fpu": true,
|
||||
+ "ibs": false,
|
||||
+ "ds_cpl": false,
|
||||
+ "ds-cpl": false,
|
||||
+ "host-phys-bits": true,
|
||||
+ "fma4": false,
|
||||
+ "la57": false,
|
||||
+ "osvw": false,
|
||||
+ "check": true,
|
||||
+ "hv-spinlocks": -1,
|
||||
+ "pmu": false,
|
||||
+ "pmm": false,
|
||||
+ "apic": true,
|
||||
+ "spec-ctrl": true,
|
||||
+ "min-xlevel2": 0,
|
||||
+ "tsc-adjust": true,
|
||||
+ "tsc_adjust": true,
|
||||
+ "kvm-steal-time": true,
|
||||
+ "kvm_steal_time": true,
|
||||
+ "kvmclock": true,
|
||||
+ "l3-cache": true,
|
||||
+ "lwp": false,
|
||||
+ "ibpb": false,
|
||||
+ "xop": false,
|
||||
+ "avx": true,
|
||||
+ "ospke": false,
|
||||
+ "ace2": false,
|
||||
+ "avx512bw": false,
|
||||
+ "acpi": false,
|
||||
+ "hv-vapic": false,
|
||||
+ "fsgsbase": true,
|
||||
+ "ht": false,
|
||||
+ "nx": true,
|
||||
+ "pclmulqdq": true,
|
||||
+ "mmxext": false,
|
||||
+ "vaes": false,
|
||||
+ "popcnt": true,
|
||||
+ "xsaves": false,
|
||||
+ "tcg-cpuid": true,
|
||||
+ "lm": true,
|
||||
+ "umip": false,
|
||||
+ "pse": true,
|
||||
+ "avx2": true,
|
||||
+ "sep": true,
|
||||
+ "pclmuldq": true,
|
||||
+ "virt-ssbd": false,
|
||||
+ "x-hv-max-vps": -1,
|
||||
+ "nodeid-msr": false,
|
||||
+ "md-clear": true,
|
||||
+ "kvm": true,
|
||||
+ "misalignsse": false,
|
||||
+ "min-xlevel": 2147483656,
|
||||
+ "kvm-pv-unhalt": true,
|
||||
+ "bmi2": true,
|
||||
+ "bmi1": true,
|
||||
+ "realized": false,
|
||||
+ "tsc_scale": false,
|
||||
+ "tsc-scale": false,
|
||||
+ "topoext": false,
|
||||
+ "hv-vpindex": false,
|
||||
+ "xlevel2": 0,
|
||||
+ "clflushopt": true,
|
||||
+ "kvm-no-smi-migration": false,
|
||||
+ "monitor": false,
|
||||
+ "avx512er": false,
|
||||
+ "pmm-en": false,
|
||||
+ "pcid": true,
|
||||
+ "3dnow": false,
|
||||
+ "erms": true,
|
||||
+ "lahf-lm": true,
|
||||
+ "lahf_lm": true,
|
||||
+ "vpclmulqdq": false,
|
||||
+ "fxsr-opt": false,
|
||||
+ "hv-synic": false,
|
||||
+ "xstore": false,
|
||||
+ "fxsr_opt": false,
|
||||
+ "kvm-hint-dedicated": false,
|
||||
+ "rtm": true,
|
||||
+ "lmce": true,
|
||||
+ "hv-time": false,
|
||||
+ "perfctr-nb": false,
|
||||
+ "perfctr_nb": false,
|
||||
+ "ffxsr": false,
|
||||
+ "rdrand": true,
|
||||
+ "rdseed": true,
|
||||
+ "avx512-4vnniw": false,
|
||||
+ "vmx": false,
|
||||
+ "vme": true,
|
||||
+ "dtes64": false,
|
||||
+ "mtrr": true,
|
||||
+ "rdtscp": true,
|
||||
+ "pse36": true,
|
||||
+ "kvm-pv-tlb-flush": false,
|
||||
+ "tbm": false,
|
||||
+ "wdt": false,
|
||||
+ "pause_filter": false,
|
||||
+ "sha-ni": false,
|
||||
+ "model-id": "Intel(R) Xeon(R) CPU E3-1225 v5 @ 3.30GHz",
|
||||
+ "abm": true,
|
||||
+ "avx512pf": false,
|
||||
+ "xstore-en": false
|
||||
+ }
|
||||
+ }
|
||||
+ },
|
||||
+ "id": "model-expansion"
|
||||
+}
|
||||
+
|
||||
+{
|
||||
+ "return": [
|
||||
+ {
|
||||
+ "name": "max",
|
||||
+ "typename": "max-x86_64-cpu",
|
||||
+ "unavailable-features": [],
|
||||
+ "static": false,
|
||||
+ "migration-safe": false
|
||||
+ },
|
||||
+ {
|
||||
+ "name": "host",
|
||||
+ "typename": "host-x86_64-cpu",
|
||||
+ "unavailable-features": [],
|
||||
+ "static": false,
|
||||
+ "migration-safe": false
|
||||
+ },
|
||||
+ {
|
||||
+ "name": "base",
|
||||
+ "typename": "base-x86_64-cpu",
|
||||
+ "unavailable-features": [],
|
||||
+ "static": true,
|
||||
+ "migration-safe": true
|
||||
+ },
|
||||
+ {
|
||||
+ "name": "qemu64",
|
||||
+ "typename": "qemu64-x86_64-cpu",
|
||||
+ "unavailable-features": [],
|
||||
+ "static": false,
|
||||
+ "migration-safe": true
|
||||
+ },
|
||||
+ {
|
||||
+ "name": "qemu32",
|
||||
+ "typename": "qemu32-x86_64-cpu",
|
||||
+ "unavailable-features": [],
|
||||
+ "static": false,
|
||||
+ "migration-safe": true
|
||||
+ },
|
||||
+ {
|
||||
+ "name": "phenom",
|
||||
+ "typename": "phenom-x86_64-cpu",
|
||||
+ "unavailable-features": [
|
||||
+ "mmxext",
|
||||
+ "fxsr-opt",
|
||||
+ "3dnowext",
|
||||
+ "3dnow",
|
||||
+ "sse4a",
|
||||
+ "npt"
|
||||
+ ],
|
||||
+ "static": false,
|
||||
+ "migration-safe": true
|
||||
+ },
|
||||
+ {
|
||||
+ "name": "pentium3",
|
||||
+ "typename": "pentium3-x86_64-cpu",
|
||||
+ "unavailable-features": [],
|
||||
+ "static": false,
|
||||
+ "migration-safe": true
|
||||
+ },
|
||||
+ {
|
||||
+ "name": "pentium2",
|
||||
+ "typename": "pentium2-x86_64-cpu",
|
||||
+ "unavailable-features": [],
|
||||
+ "static": false,
|
||||
+ "migration-safe": true
|
||||
+ },
|
||||
+ {
|
||||
+ "name": "pentium",
|
||||
+ "typename": "pentium-x86_64-cpu",
|
||||
+ "unavailable-features": [],
|
||||
+ "static": false,
|
||||
+ "migration-safe": true
|
||||
+ },
|
||||
+ {
|
||||
+ "name": "n270",
|
||||
+ "typename": "n270-x86_64-cpu",
|
||||
+ "unavailable-features": [],
|
||||
+ "static": false,
|
||||
+ "migration-safe": true
|
||||
+ },
|
||||
+ {
|
||||
+ "name": "kvm64",
|
||||
+ "typename": "kvm64-x86_64-cpu",
|
||||
+ "unavailable-features": [],
|
||||
+ "static": false,
|
||||
+ "migration-safe": true
|
||||
+ },
|
||||
+ {
|
||||
+ "name": "kvm32",
|
||||
+ "typename": "kvm32-x86_64-cpu",
|
||||
+ "unavailable-features": [],
|
||||
+ "static": false,
|
||||
+ "migration-safe": true
|
||||
+ },
|
||||
+ {
|
||||
+ "name": "cpu64-rhel6",
|
||||
+ "typename": "cpu64-rhel6-x86_64-cpu",
|
||||
+ "unavailable-features": [
|
||||
+ "sse4a"
|
||||
+ ],
|
||||
+ "static": false,
|
||||
+ "migration-safe": true
|
||||
+ },
|
||||
+ {
|
||||
+ "name": "coreduo",
|
||||
+ "typename": "coreduo-x86_64-cpu",
|
||||
+ "unavailable-features": [],
|
||||
+ "static": false,
|
||||
+ "migration-safe": true
|
||||
+ },
|
||||
+ {
|
||||
+ "name": "core2duo",
|
||||
+ "typename": "core2duo-x86_64-cpu",
|
||||
+ "unavailable-features": [],
|
||||
+ "static": false,
|
||||
+ "migration-safe": true
|
||||
+ },
|
||||
+ {
|
||||
+ "name": "athlon",
|
||||
+ "typename": "athlon-x86_64-cpu",
|
||||
+ "unavailable-features": [
|
||||
+ "mmxext",
|
||||
+ "3dnowext",
|
||||
+ "3dnow"
|
||||
+ ],
|
||||
+ "static": false,
|
||||
+ "migration-safe": true
|
||||
+ },
|
||||
+ {
|
||||
+ "name": "Westmere",
|
||||
+ "typename": "Westmere-x86_64-cpu",
|
||||
+ "unavailable-features": [],
|
||||
+ "static": false,
|
||||
+ "migration-safe": true
|
||||
+ },
|
||||
+ {
|
||||
+ "name": "Westmere-IBRS",
|
||||
+ "typename": "Westmere-IBRS-x86_64-cpu",
|
||||
+ "unavailable-features": [],
|
||||
+ "static": false,
|
||||
+ "migration-safe": true
|
||||
+ },
|
||||
+ {
|
||||
+ "name": "Skylake-Server",
|
||||
+ "typename": "Skylake-Server-x86_64-cpu",
|
||||
+ "unavailable-features": [
|
||||
+ "avx512f",
|
||||
+ "avx512dq",
|
||||
+ "clwb",
|
||||
+ "avx512cd",
|
||||
+ "avx512bw",
|
||||
+ "avx512vl",
|
||||
+ "avx512f",
|
||||
+ "avx512f",
|
||||
+ "avx512f"
|
||||
+ ],
|
||||
+ "static": false,
|
||||
+ "migration-safe": true
|
||||
+ },
|
||||
+ {
|
||||
+ "name": "Skylake-Server-IBRS",
|
||||
+ "typename": "Skylake-Server-IBRS-x86_64-cpu",
|
||||
+ "unavailable-features": [
|
||||
+ "avx512f",
|
||||
+ "avx512dq",
|
||||
+ "clwb",
|
||||
+ "avx512cd",
|
||||
+ "avx512bw",
|
||||
+ "avx512vl",
|
||||
+ "avx512f",
|
||||
+ "avx512f",
|
||||
+ "avx512f"
|
||||
+ ],
|
||||
+ "static": false,
|
||||
+ "migration-safe": true
|
||||
+ },
|
||||
+ {
|
||||
+ "name": "Skylake-Client",
|
||||
+ "typename": "Skylake-Client-x86_64-cpu",
|
||||
+ "unavailable-features": [],
|
||||
+ "static": false,
|
||||
+ "migration-safe": true
|
||||
+ },
|
||||
+ {
|
||||
+ "name": "Skylake-Client-IBRS",
|
||||
+ "typename": "Skylake-Client-IBRS-x86_64-cpu",
|
||||
+ "unavailable-features": [],
|
||||
+ "static": false,
|
||||
+ "migration-safe": true
|
||||
+ },
|
||||
+ {
|
||||
+ "name": "SandyBridge",
|
||||
+ "typename": "SandyBridge-x86_64-cpu",
|
||||
+ "unavailable-features": [],
|
||||
+ "static": false,
|
||||
+ "migration-safe": true
|
||||
+ },
|
||||
+ {
|
||||
+ "name": "SandyBridge-IBRS",
|
||||
+ "typename": "SandyBridge-IBRS-x86_64-cpu",
|
||||
+ "unavailable-features": [],
|
||||
+ "static": false,
|
||||
+ "migration-safe": true
|
||||
+ },
|
||||
+ {
|
||||
+ "name": "Penryn",
|
||||
+ "typename": "Penryn-x86_64-cpu",
|
||||
+ "unavailable-features": [],
|
||||
+ "static": false,
|
||||
+ "migration-safe": true
|
||||
+ },
|
||||
+ {
|
||||
+ "name": "Opteron_G5",
|
||||
+ "typename": "Opteron_G5-x86_64-cpu",
|
||||
+ "unavailable-features": [
|
||||
+ "sse4a",
|
||||
+ "misalignsse",
|
||||
+ "xop",
|
||||
+ "fma4",
|
||||
+ "tbm"
|
||||
+ ],
|
||||
+ "static": false,
|
||||
+ "migration-safe": true
|
||||
+ },
|
||||
+ {
|
||||
+ "name": "Opteron_G4",
|
||||
+ "typename": "Opteron_G4-x86_64-cpu",
|
||||
+ "unavailable-features": [
|
||||
+ "sse4a",
|
||||
+ "misalignsse",
|
||||
+ "xop",
|
||||
+ "fma4"
|
||||
+ ],
|
||||
+ "static": false,
|
||||
+ "migration-safe": true
|
||||
+ },
|
||||
+ {
|
||||
+ "name": "Opteron_G3",
|
||||
+ "typename": "Opteron_G3-x86_64-cpu",
|
||||
+ "unavailable-features": [
|
||||
+ "sse4a",
|
||||
+ "misalignsse"
|
||||
+ ],
|
||||
+ "static": false,
|
||||
+ "migration-safe": true
|
||||
+ },
|
||||
+ {
|
||||
+ "name": "Opteron_G2",
|
||||
+ "typename": "Opteron_G2-x86_64-cpu",
|
||||
+ "unavailable-features": [],
|
||||
+ "static": false,
|
||||
+ "migration-safe": true
|
||||
+ },
|
||||
+ {
|
||||
+ "name": "Opteron_G1",
|
||||
+ "typename": "Opteron_G1-x86_64-cpu",
|
||||
+ "unavailable-features": [],
|
||||
+ "static": false,
|
||||
+ "migration-safe": true
|
||||
+ },
|
||||
+ {
|
||||
+ "name": "Nehalem",
|
||||
+ "typename": "Nehalem-x86_64-cpu",
|
||||
+ "unavailable-features": [],
|
||||
+ "static": false,
|
||||
+ "migration-safe": true
|
||||
+ },
|
||||
+ {
|
||||
+ "name": "Nehalem-IBRS",
|
||||
+ "typename": "Nehalem-IBRS-x86_64-cpu",
|
||||
+ "unavailable-features": [],
|
||||
+ "static": false,
|
||||
+ "migration-safe": true
|
||||
+ },
|
||||
+ {
|
||||
+ "name": "IvyBridge",
|
||||
+ "typename": "IvyBridge-x86_64-cpu",
|
||||
+ "unavailable-features": [],
|
||||
+ "static": false,
|
||||
+ "migration-safe": true
|
||||
+ },
|
||||
+ {
|
||||
+ "name": "IvyBridge-IBRS",
|
||||
+ "typename": "IvyBridge-IBRS-x86_64-cpu",
|
||||
+ "unavailable-features": [],
|
||||
+ "static": false,
|
||||
+ "migration-safe": true
|
||||
+ },
|
||||
+ {
|
||||
+ "name": "Haswell",
|
||||
+ "typename": "Haswell-x86_64-cpu",
|
||||
+ "unavailable-features": [],
|
||||
+ "static": false,
|
||||
+ "migration-safe": true
|
||||
+ },
|
||||
+ {
|
||||
+ "name": "Haswell-noTSX",
|
||||
+ "typename": "Haswell-noTSX-x86_64-cpu",
|
||||
+ "unavailable-features": [],
|
||||
+ "static": false,
|
||||
+ "migration-safe": true
|
||||
+ },
|
||||
+ {
|
||||
+ "name": "Haswell-noTSX-IBRS",
|
||||
+ "typename": "Haswell-noTSX-IBRS-x86_64-cpu",
|
||||
+ "unavailable-features": [],
|
||||
+ "static": false,
|
||||
+ "migration-safe": true
|
||||
+ },
|
||||
+ {
|
||||
+ "name": "Haswell-IBRS",
|
||||
+ "typename": "Haswell-IBRS-x86_64-cpu",
|
||||
+ "unavailable-features": [],
|
||||
+ "static": false,
|
||||
+ "migration-safe": true
|
||||
+ },
|
||||
+ {
|
||||
+ "name": "EPYC",
|
||||
+ "typename": "EPYC-x86_64-cpu",
|
||||
+ "unavailable-features": [
|
||||
+ "sha-ni",
|
||||
+ "mmxext",
|
||||
+ "fxsr-opt",
|
||||
+ "cr8legacy",
|
||||
+ "sse4a",
|
||||
+ "misalignsse",
|
||||
+ "osvw"
|
||||
+ ],
|
||||
+ "static": false,
|
||||
+ "migration-safe": true
|
||||
+ },
|
||||
+ {
|
||||
+ "name": "EPYC-IBPB",
|
||||
+ "typename": "EPYC-IBPB-x86_64-cpu",
|
||||
+ "unavailable-features": [
|
||||
+ "sha-ni",
|
||||
+ "mmxext",
|
||||
+ "fxsr-opt",
|
||||
+ "cr8legacy",
|
||||
+ "sse4a",
|
||||
+ "misalignsse",
|
||||
+ "osvw",
|
||||
+ "ibpb"
|
||||
+ ],
|
||||
+ "static": false,
|
||||
+ "migration-safe": true
|
||||
+ },
|
||||
+ {
|
||||
+ "name": "Conroe",
|
||||
+ "typename": "Conroe-x86_64-cpu",
|
||||
+ "unavailable-features": [],
|
||||
+ "static": false,
|
||||
+ "migration-safe": true
|
||||
+ },
|
||||
+ {
|
||||
+ "name": "Broadwell",
|
||||
+ "typename": "Broadwell-x86_64-cpu",
|
||||
+ "unavailable-features": [],
|
||||
+ "static": false,
|
||||
+ "migration-safe": true
|
||||
+ },
|
||||
+ {
|
||||
+ "name": "Broadwell-noTSX",
|
||||
+ "typename": "Broadwell-noTSX-x86_64-cpu",
|
||||
+ "unavailable-features": [],
|
||||
+ "static": false,
|
||||
+ "migration-safe": true
|
||||
+ },
|
||||
+ {
|
||||
+ "name": "Broadwell-noTSX-IBRS",
|
||||
+ "typename": "Broadwell-noTSX-IBRS-x86_64-cpu",
|
||||
+ "unavailable-features": [],
|
||||
+ "static": false,
|
||||
+ "migration-safe": true
|
||||
+ },
|
||||
+ {
|
||||
+ "name": "Broadwell-IBRS",
|
||||
+ "typename": "Broadwell-IBRS-x86_64-cpu",
|
||||
+ "unavailable-features": [],
|
||||
+ "static": false,
|
||||
+ "migration-safe": true
|
||||
+ },
|
||||
+ {
|
||||
+ "name": "486",
|
||||
+ "typename": "486-x86_64-cpu",
|
||||
+ "unavailable-features": [],
|
||||
+ "static": false,
|
||||
+ "migration-safe": true
|
||||
+ }
|
||||
+ ],
|
||||
+ "id": "definitions"
|
||||
+}
|
||||
diff --git a/tests/cputestdata/x86_64-cpuid-Xeon-E3-1225-v5.sig b/tests/cputestdata/x86_64-cpuid-Xeon-E3-1225-v5.sig
|
||||
new file mode 100644
|
||||
index 0000000000..7e57c2ded6
|
||||
--- /dev/null
|
||||
+++ b/tests/cputestdata/x86_64-cpuid-Xeon-E3-1225-v5.sig
|
||||
@@ -0,0 +1,4 @@
|
||||
+0506e3
|
||||
+family: 6 (0x06)
|
||||
+model: 94 (0x5e)
|
||||
+stepping: 3 (0x03)
|
||||
diff --git a/tests/cputestdata/x86_64-cpuid-Xeon-E3-1225-v5.xml b/tests/cputestdata/x86_64-cpuid-Xeon-E3-1225-v5.xml
|
||||
new file mode 100644
|
||||
index 0000000000..437429d61d
|
||||
--- /dev/null
|
||||
+++ b/tests/cputestdata/x86_64-cpuid-Xeon-E3-1225-v5.xml
|
||||
@@ -0,0 +1,47 @@
|
||||
+<!-- Intel(R) Xeon(R) CPU E3-1225 v5 @ 3.30GHz -->
|
||||
+<cpudata arch='x86'>
|
||||
+ <cpuid eax_in='0x00000000' ecx_in='0x00' eax='0x00000016' ebx='0x756e6547' ecx='0x6c65746e' edx='0x49656e69'/>
|
||||
+ <cpuid eax_in='0x00000001' ecx_in='0x00' eax='0x000506e3' ebx='0x06100800' ecx='0x7ffafbff' edx='0xbfebfbff'/>
|
||||
+ <cpuid eax_in='0x00000002' ecx_in='0x00' eax='0x76036301' ebx='0x00f0b6ff' ecx='0x00000000' edx='0x00c30000'/>
|
||||
+ <cpuid eax_in='0x00000003' ecx_in='0x00' eax='0x00000000' ebx='0x00000000' ecx='0x00000000' edx='0x00000000'/>
|
||||
+ <cpuid eax_in='0x00000004' ecx_in='0x00' eax='0x1c004121' ebx='0x01c0003f' ecx='0x0000003f' edx='0x00000000'/>
|
||||
+ <cpuid eax_in='0x00000004' ecx_in='0x01' eax='0x1c004122' ebx='0x01c0003f' ecx='0x0000003f' edx='0x00000000'/>
|
||||
+ <cpuid eax_in='0x00000004' ecx_in='0x02' eax='0x1c004143' ebx='0x00c0003f' ecx='0x000003ff' edx='0x00000000'/>
|
||||
+ <cpuid eax_in='0x00000004' ecx_in='0x03' eax='0x1c03c163' ebx='0x03c0003f' ecx='0x00001fff' edx='0x00000006'/>
|
||||
+ <cpuid eax_in='0x00000005' ecx_in='0x00' eax='0x00000040' ebx='0x00000040' ecx='0x00000003' edx='0x00142120'/>
|
||||
+ <cpuid eax_in='0x00000006' ecx_in='0x00' eax='0x000027f7' ebx='0x00000002' ecx='0x00000009' edx='0x00000000'/>
|
||||
+ <cpuid eax_in='0x00000007' ecx_in='0x00' eax='0x00000000' ebx='0x029c6fbf' ecx='0x00000000' edx='0x9c002400'/>
|
||||
+ <cpuid eax_in='0x00000008' ecx_in='0x00' eax='0x00000000' ebx='0x00000000' ecx='0x00000000' edx='0x00000000'/>
|
||||
+ <cpuid eax_in='0x00000009' ecx_in='0x00' eax='0x00000000' ebx='0x00000000' ecx='0x00000000' edx='0x00000000'/>
|
||||
+ <cpuid eax_in='0x0000000a' ecx_in='0x00' eax='0x07300804' ebx='0x00000000' ecx='0x00000000' edx='0x00000603'/>
|
||||
+ <cpuid eax_in='0x0000000b' ecx_in='0x00' eax='0x00000001' ebx='0x00000001' ecx='0x00000100' edx='0x00000006'/>
|
||||
+ <cpuid eax_in='0x0000000b' ecx_in='0x01' eax='0x00000004' ebx='0x00000004' ecx='0x00000201' edx='0x00000006'/>
|
||||
+ <cpuid eax_in='0x0000000c' ecx_in='0x00' eax='0x00000000' ebx='0x00000000' ecx='0x00000000' edx='0x00000000'/>
|
||||
+ <cpuid eax_in='0x0000000d' ecx_in='0x00' eax='0x0000001f' ebx='0x00000440' ecx='0x00000440' edx='0x00000000'/>
|
||||
+ <cpuid eax_in='0x0000000d' ecx_in='0x01' eax='0x0000000f' ebx='0x000003c0' ecx='0x00000100' edx='0x00000000'/>
|
||||
+ <cpuid eax_in='0x0000000d' ecx_in='0x02' eax='0x00000100' ebx='0x00000240' ecx='0x00000000' edx='0x00000000'/>
|
||||
+ <cpuid eax_in='0x0000000d' ecx_in='0x03' eax='0x00000040' ebx='0x000003c0' ecx='0x00000000' edx='0x00000000'/>
|
||||
+ <cpuid eax_in='0x0000000d' ecx_in='0x04' eax='0x00000040' ebx='0x00000400' ecx='0x00000000' edx='0x00000000'/>
|
||||
+ <cpuid eax_in='0x0000000d' ecx_in='0x08' eax='0x00000080' ebx='0x00000000' ecx='0x00000001' edx='0x00000000'/>
|
||||
+ <cpuid eax_in='0x0000000e' ecx_in='0x00' eax='0x00000000' ebx='0x00000000' ecx='0x00000000' edx='0x00000000'/>
|
||||
+ <cpuid eax_in='0x0000000f' ecx_in='0x00' eax='0x00000000' ebx='0x00000000' ecx='0x00000000' edx='0x00000000'/>
|
||||
+ <cpuid eax_in='0x00000010' ecx_in='0x00' eax='0x00000000' ebx='0x00000000' ecx='0x00000000' edx='0x00000000'/>
|
||||
+ <cpuid eax_in='0x00000011' ecx_in='0x00' eax='0x00000000' ebx='0x00000000' ecx='0x00000000' edx='0x00000000'/>
|
||||
+ <cpuid eax_in='0x00000012' ecx_in='0x00' eax='0x00000000' ebx='0x00000000' ecx='0x00000000' edx='0x00000000'/>
|
||||
+ <cpuid eax_in='0x00000013' ecx_in='0x00' eax='0x00000000' ebx='0x00000000' ecx='0x00000000' edx='0x00000000'/>
|
||||
+ <cpuid eax_in='0x00000014' ecx_in='0x00' eax='0x00000001' ebx='0x0000000f' ecx='0x00000007' edx='0x00000000'/>
|
||||
+ <cpuid eax_in='0x00000014' ecx_in='0x01' eax='0x02490002' ebx='0x003f3fff' ecx='0x00000000' edx='0x00000000'/>
|
||||
+ <cpuid eax_in='0x00000015' ecx_in='0x00' eax='0x00000002' ebx='0x00000114' ecx='0x00000000' edx='0x00000000'/>
|
||||
+ <cpuid eax_in='0x00000016' ecx_in='0x00' eax='0x00000ce4' ebx='0x00000e74' ecx='0x00000064' edx='0x00000000'/>
|
||||
+ <cpuid eax_in='0x80000000' ecx_in='0x00' eax='0x80000008' ebx='0x00000000' ecx='0x00000000' edx='0x00000000'/>
|
||||
+ <cpuid eax_in='0x80000001' ecx_in='0x00' eax='0x00000000' ebx='0x00000000' ecx='0x00000121' edx='0x2c100800'/>
|
||||
+ <cpuid eax_in='0x80000002' ecx_in='0x00' eax='0x65746e49' ebx='0x2952286c' ecx='0x6f655820' edx='0x2952286e'/>
|
||||
+ <cpuid eax_in='0x80000003' ecx_in='0x00' eax='0x55504320' ebx='0x2d334520' ecx='0x35323231' edx='0x20357620'/>
|
||||
+ <cpuid eax_in='0x80000004' ecx_in='0x00' eax='0x2e332040' ebx='0x48473033' ecx='0x0000007a' edx='0x00000000'/>
|
||||
+ <cpuid eax_in='0x80000005' ecx_in='0x00' eax='0x00000000' ebx='0x00000000' ecx='0x00000000' edx='0x00000000'/>
|
||||
+ <cpuid eax_in='0x80000006' ecx_in='0x00' eax='0x00000000' ebx='0x00000000' ecx='0x01006040' edx='0x00000000'/>
|
||||
+ <cpuid eax_in='0x80000007' ecx_in='0x00' eax='0x00000000' ebx='0x00000000' ecx='0x00000000' edx='0x00000100'/>
|
||||
+ <cpuid eax_in='0x80000008' ecx_in='0x00' eax='0x00003027' ebx='0x00000000' ecx='0x00000000' edx='0x00000000'/>
|
||||
+ <cpuid eax_in='0x80860000' ecx_in='0x00' eax='0x00000ce4' ebx='0x00000e74' ecx='0x00000064' edx='0x00000000'/>
|
||||
+ <cpuid eax_in='0xc0000000' ecx_in='0x00' eax='0x00000ce4' ebx='0x00000e74' ecx='0x00000064' edx='0x00000000'/>
|
||||
+</cpudata>
|
||||
@@ -0,0 +1,94 @@
|
||||
From: Jiri Denemark <jdenemar@redhat.com>
|
||||
Date: Tue, 9 Apr 2019 12:35:52 +0200
|
||||
Subject: [PATCH] cpu_map: Define md-clear CPUID bit
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
CVE-2018-12126, CVE-2018-12127, CVE-2018-12130, CVE-2019-11091
|
||||
|
||||
The bit is set when microcode provides the mechanism to invoke a flush
|
||||
of various exploitable CPU buffers by invoking the VERW instruction.
|
||||
|
||||
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
|
||||
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
|
||||
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
|
||||
(cherry picked from commit 538d873571d7a682852dc1d70e5f4478f4d64e85)
|
||||
|
||||
Conflicts:
|
||||
tests/cputestdata/x86_64-cpuid-Xeon-Platinum-8268-guest.xml
|
||||
tests/cputestdata/x86_64-cpuid-Xeon-Platinum-8268-host.xml
|
||||
- test data missing downstream
|
||||
|
||||
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
|
||||
---
|
||||
src/cpu_map/x86_features.xml | 3 +++
|
||||
tests/cputestdata/x86_64-cpuid-Xeon-E3-1225-v5-enabled.xml | 2 +-
|
||||
tests/cputestdata/x86_64-cpuid-Xeon-E3-1225-v5-guest.xml | 1 +
|
||||
tests/cputestdata/x86_64-cpuid-Xeon-E3-1225-v5-host.xml | 1 +
|
||||
tests/cputestdata/x86_64-cpuid-Xeon-E3-1225-v5-json.xml | 1 +
|
||||
5 files changed, 7 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/src/cpu_map/x86_features.xml b/src/cpu_map/x86_features.xml
|
||||
index 02431bea29..11479f0433 100644
|
||||
--- a/src/cpu_map/x86_features.xml
|
||||
+++ b/src/cpu_map/x86_features.xml
|
||||
@@ -317,6 +317,9 @@
|
||||
<feature name='avx512-4fmaps'>
|
||||
<cpuid eax_in='0x07' ecx_in='0x00' edx='0x00000008'/>
|
||||
</feature>
|
||||
+ <feature name='md-clear'> <!-- md_clear -->
|
||||
+ <cpuid eax_in='0x07' ecx_in='0x00' edx='0x00000400'/>
|
||||
+ </feature>
|
||||
<feature name='pconfig'>
|
||||
<cpuid eax_in='0x07' ecx_in='0x00' edx='0x00040000'/>
|
||||
</feature>
|
||||
diff --git a/tests/cputestdata/x86_64-cpuid-Xeon-E3-1225-v5-enabled.xml b/tests/cputestdata/x86_64-cpuid-Xeon-E3-1225-v5-enabled.xml
|
||||
index 0deca9fba6..74763a462b 100644
|
||||
--- a/tests/cputestdata/x86_64-cpuid-Xeon-E3-1225-v5-enabled.xml
|
||||
+++ b/tests/cputestdata/x86_64-cpuid-Xeon-E3-1225-v5-enabled.xml
|
||||
@@ -2,7 +2,7 @@
|
||||
<cpudata arch='x86'>
|
||||
<cpuid eax_in='0x00000001' ecx_in='0x00' eax='0x00000000' ebx='0x00000000' ecx='0xf7fa3203' edx='0x0f8bfbff'/>
|
||||
<cpuid eax_in='0x00000006' ecx_in='0x00' eax='0x00000004' ebx='0x00000000' ecx='0x00000000' edx='0x00000000'/>
|
||||
- <cpuid eax_in='0x00000007' ecx_in='0x00' eax='0x00000000' ebx='0x009c4fbb' ecx='0x00000000' edx='0x8c000000'/>
|
||||
+ <cpuid eax_in='0x00000007' ecx_in='0x00' eax='0x00000000' ebx='0x009c4fbb' ecx='0x00000000' edx='0x8c000400'/>
|
||||
<cpuid eax_in='0x0000000d' ecx_in='0x01' eax='0x00000007' ebx='0x00000000' ecx='0x00000000' edx='0x00000000'/>
|
||||
<cpuid eax_in='0x80000001' ecx_in='0x00' eax='0x00000000' ebx='0x00000000' ecx='0x00000121' edx='0x2c100800'/>
|
||||
</cpudata>
|
||||
diff --git a/tests/cputestdata/x86_64-cpuid-Xeon-E3-1225-v5-guest.xml b/tests/cputestdata/x86_64-cpuid-Xeon-E3-1225-v5-guest.xml
|
||||
index 70a0fc3286..867970d2c7 100644
|
||||
--- a/tests/cputestdata/x86_64-cpuid-Xeon-E3-1225-v5-guest.xml
|
||||
+++ b/tests/cputestdata/x86_64-cpuid-Xeon-E3-1225-v5-guest.xml
|
||||
@@ -20,6 +20,7 @@
|
||||
<feature policy='require' name='tsc_adjust'/>
|
||||
<feature policy='require' name='clflushopt'/>
|
||||
<feature policy='require' name='intel-pt'/>
|
||||
+ <feature policy='require' name='md-clear'/>
|
||||
<feature policy='require' name='stibp'/>
|
||||
<feature policy='require' name='ssbd'/>
|
||||
<feature policy='require' name='xsaves'/>
|
||||
diff --git a/tests/cputestdata/x86_64-cpuid-Xeon-E3-1225-v5-host.xml b/tests/cputestdata/x86_64-cpuid-Xeon-E3-1225-v5-host.xml
|
||||
index bbdfb6aa61..e7ced42797 100644
|
||||
--- a/tests/cputestdata/x86_64-cpuid-Xeon-E3-1225-v5-host.xml
|
||||
+++ b/tests/cputestdata/x86_64-cpuid-Xeon-E3-1225-v5-host.xml
|
||||
@@ -21,6 +21,7 @@
|
||||
<feature name='tsc_adjust'/>
|
||||
<feature name='clflushopt'/>
|
||||
<feature name='intel-pt'/>
|
||||
+ <feature name='md-clear'/>
|
||||
<feature name='stibp'/>
|
||||
<feature name='ssbd'/>
|
||||
<feature name='xsaves'/>
|
||||
diff --git a/tests/cputestdata/x86_64-cpuid-Xeon-E3-1225-v5-json.xml b/tests/cputestdata/x86_64-cpuid-Xeon-E3-1225-v5-json.xml
|
||||
index 1f321db273..a5591278df 100644
|
||||
--- a/tests/cputestdata/x86_64-cpuid-Xeon-E3-1225-v5-json.xml
|
||||
+++ b/tests/cputestdata/x86_64-cpuid-Xeon-E3-1225-v5-json.xml
|
||||
@@ -5,6 +5,7 @@
|
||||
<feature policy='require' name='hypervisor'/>
|
||||
<feature policy='require' name='tsc_adjust'/>
|
||||
<feature policy='require' name='clflushopt'/>
|
||||
+ <feature policy='require' name='md-clear'/>
|
||||
<feature policy='require' name='stibp'/>
|
||||
<feature policy='require' name='ssbd'/>
|
||||
<feature policy='require' name='pdpe1gb'/>
|
||||
@@ -0,0 +1,54 @@
|
||||
From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= <berrange@redhat.com>
|
||||
Date: Tue, 30 Apr 2019 17:26:13 +0100
|
||||
Subject: [PATCH] admin: reject clients unless their UID matches the current
|
||||
UID
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
The admin protocol RPC messages are only intended for use by the user
|
||||
running the daemon. As such they should not be allowed for any client
|
||||
UID that does not match the server UID.
|
||||
|
||||
Fixes CVE-2019-10132
|
||||
|
||||
Reviewed-by: Ján Tomko <jtomko@redhat.com>
|
||||
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
|
||||
(cherry picked from commit 96f41cd765c9e525fe28ee5abbfbf4a79b3720c7)
|
||||
---
|
||||
src/admin/admin_server_dispatch.c | 22 ++++++++++++++++++++++
|
||||
1 file changed, 22 insertions(+)
|
||||
|
||||
diff --git a/src/admin/admin_server_dispatch.c b/src/admin/admin_server_dispatch.c
|
||||
index 85e693d76c..6e3b99f97d 100644
|
||||
--- a/src/admin/admin_server_dispatch.c
|
||||
+++ b/src/admin/admin_server_dispatch.c
|
||||
@@ -64,6 +64,28 @@ remoteAdmClientNew(virNetServerClientPtr client ATTRIBUTE_UNUSED,
|
||||
void *opaque)
|
||||
{
|
||||
struct daemonAdmClientPrivate *priv;
|
||||
+ uid_t clientuid;
|
||||
+ gid_t clientgid;
|
||||
+ pid_t clientpid;
|
||||
+ unsigned long long timestamp;
|
||||
+
|
||||
+ if (virNetServerClientGetUNIXIdentity(client,
|
||||
+ &clientuid,
|
||||
+ &clientgid,
|
||||
+ &clientpid,
|
||||
+ ×tamp) < 0)
|
||||
+ return NULL;
|
||||
+
|
||||
+ VIR_DEBUG("New client pid %lld uid %lld",
|
||||
+ (long long)clientpid,
|
||||
+ (long long)clientuid);
|
||||
+
|
||||
+ if (geteuid() != clientuid) {
|
||||
+ virReportRestrictedError(_("Disallowing client %lld with uid %lld"),
|
||||
+ (long long)clientpid,
|
||||
+ (long long)clientuid);
|
||||
+ return NULL;
|
||||
+ }
|
||||
|
||||
if (VIR_ALLOC(priv) < 0)
|
||||
return NULL;
|
||||
@@ -0,0 +1,47 @@
|
||||
From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= <berrange@redhat.com>
|
||||
Date: Tue, 30 Apr 2019 16:51:37 +0100
|
||||
Subject: [PATCH] locking: restrict sockets to mode 0600
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
The virtlockd daemon's only intended client is the libvirtd daemon. As
|
||||
such it should never allow clients from other user accounts to connect.
|
||||
The code already enforces this and drops clients from other UIDs, but
|
||||
we can get earlier (and thus stronger) protection against DoS by setting
|
||||
the socket permissions to 0600
|
||||
|
||||
Fixes CVE-2019-10132
|
||||
|
||||
Reviewed-by: Ján Tomko <jtomko@redhat.com>
|
||||
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
|
||||
(cherry picked from commit f111e09468693909b1f067aa575efdafd9a262a1)
|
||||
---
|
||||
src/locking/virtlockd-admin.socket.in | 1 +
|
||||
src/locking/virtlockd.socket.in | 1 +
|
||||
2 files changed, 2 insertions(+)
|
||||
|
||||
diff --git a/src/locking/virtlockd-admin.socket.in b/src/locking/virtlockd-admin.socket.in
|
||||
index 2a7500f3d0..f674c492f7 100644
|
||||
--- a/src/locking/virtlockd-admin.socket.in
|
||||
+++ b/src/locking/virtlockd-admin.socket.in
|
||||
@@ -5,6 +5,7 @@ Before=libvirtd.service
|
||||
[Socket]
|
||||
ListenStream=@localstatedir@/run/libvirt/virtlockd-admin-sock
|
||||
Service=virtlockd.service
|
||||
+SocketMode=0600
|
||||
|
||||
[Install]
|
||||
WantedBy=sockets.target
|
||||
diff --git a/src/locking/virtlockd.socket.in b/src/locking/virtlockd.socket.in
|
||||
index 45e0f20235..d701b27516 100644
|
||||
--- a/src/locking/virtlockd.socket.in
|
||||
+++ b/src/locking/virtlockd.socket.in
|
||||
@@ -4,6 +4,7 @@ Before=libvirtd.service
|
||||
|
||||
[Socket]
|
||||
ListenStream=@localstatedir@/run/libvirt/virtlockd-sock
|
||||
+SocketMode=0600
|
||||
|
||||
[Install]
|
||||
WantedBy=sockets.target
|
||||
@@ -0,0 +1,47 @@
|
||||
From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= <berrange@redhat.com>
|
||||
Date: Tue, 30 Apr 2019 17:27:41 +0100
|
||||
Subject: [PATCH] logging: restrict sockets to mode 0600
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
The virtlogd daemon's only intended client is the libvirtd daemon. As
|
||||
such it should never allow clients from other user accounts to connect.
|
||||
The code already enforces this and drops clients from other UIDs, but
|
||||
we can get earlier (and thus stronger) protection against DoS by setting
|
||||
the socket permissions to 0600
|
||||
|
||||
Fixes CVE-2019-10132
|
||||
|
||||
Reviewed-by: Ján Tomko <jtomko@redhat.com>
|
||||
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
|
||||
(cherry picked from commit e37bd65f9948c1185456b2cdaa3bd6e875af680f)
|
||||
---
|
||||
src/logging/virtlogd-admin.socket.in | 1 +
|
||||
src/logging/virtlogd.socket.in | 1 +
|
||||
2 files changed, 2 insertions(+)
|
||||
|
||||
diff --git a/src/logging/virtlogd-admin.socket.in b/src/logging/virtlogd-admin.socket.in
|
||||
index 595e6c4c4b..5c41dfeb7b 100644
|
||||
--- a/src/logging/virtlogd-admin.socket.in
|
||||
+++ b/src/logging/virtlogd-admin.socket.in
|
||||
@@ -5,6 +5,7 @@ Before=libvirtd.service
|
||||
[Socket]
|
||||
ListenStream=@localstatedir@/run/libvirt/virtlogd-admin-sock
|
||||
Service=virtlogd.service
|
||||
+SocketMode=0600
|
||||
|
||||
[Install]
|
||||
WantedBy=sockets.target
|
||||
diff --git a/src/logging/virtlogd.socket.in b/src/logging/virtlogd.socket.in
|
||||
index 22b9360c8d..ae48cdab9a 100644
|
||||
--- a/src/logging/virtlogd.socket.in
|
||||
+++ b/src/logging/virtlogd.socket.in
|
||||
@@ -4,6 +4,7 @@ Before=libvirtd.service
|
||||
|
||||
[Socket]
|
||||
ListenStream=@localstatedir@/run/libvirt/virtlogd-sock
|
||||
+SocketMode=0600
|
||||
|
||||
[Install]
|
||||
WantedBy=sockets.target
|
||||
@@ -0,0 +1,81 @@
|
||||
From: =?UTF-8?q?J=C3=A1n=20Tomko?= <jtomko@redhat.com>
|
||||
Date: Fri, 14 Jun 2019 08:47:42 +0200
|
||||
Subject: [PATCH] api: disallow virDomainSaveImageGetXMLDesc on read-only
|
||||
connections
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
The virDomainSaveImageGetXMLDesc API is taking a path parameter,
|
||||
which can point to any path on the system. This file will then be
|
||||
read and parsed by libvirtd running with root privileges.
|
||||
|
||||
Forbid it on read-only connections.
|
||||
|
||||
Fixes: CVE-2019-10161
|
||||
Reported-by: Matthias Gerstner <mgerstner@suse.de>
|
||||
Signed-off-by: Ján Tomko <jtomko@redhat.com>
|
||||
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
|
||||
(cherry picked from commit aed6a032cead4386472afb24b16196579e239580)
|
||||
---
|
||||
src/libvirt-domain.c | 11 ++---------
|
||||
src/qemu/qemu_driver.c | 2 +-
|
||||
src/remote/remote_protocol.x | 3 +--
|
||||
3 files changed, 4 insertions(+), 12 deletions(-)
|
||||
|
||||
diff --git a/src/libvirt-domain.c b/src/libvirt-domain.c
|
||||
index 072b92b717..ba0aaccdc1 100644
|
||||
--- a/src/libvirt-domain.c
|
||||
+++ b/src/libvirt-domain.c
|
||||
@@ -1073,8 +1073,7 @@ virDomainRestoreFlags(virConnectPtr conn, const char *from, const char *dxml,
|
||||
* previously by virDomainSave() or virDomainSaveFlags().
|
||||
*
|
||||
* No security-sensitive data will be included unless @flags contains
|
||||
- * VIR_DOMAIN_SAVE_IMAGE_XML_SECURE; this flag is rejected on read-only
|
||||
- * connections.
|
||||
+ * VIR_DOMAIN_SAVE_IMAGE_XML_SECURE.
|
||||
*
|
||||
* Returns a 0 terminated UTF-8 encoded XML instance, or NULL in case of
|
||||
* error. The caller must free() the returned value.
|
||||
@@ -1090,13 +1089,7 @@ virDomainSaveImageGetXMLDesc(virConnectPtr conn, const char *file,
|
||||
|
||||
virCheckConnectReturn(conn, NULL);
|
||||
virCheckNonNullArgGoto(file, error);
|
||||
-
|
||||
- if ((conn->flags & VIR_CONNECT_RO) &&
|
||||
- (flags & VIR_DOMAIN_SAVE_IMAGE_XML_SECURE)) {
|
||||
- virReportError(VIR_ERR_OPERATION_DENIED, "%s",
|
||||
- _("virDomainSaveImageGetXMLDesc with secure flag"));
|
||||
- goto error;
|
||||
- }
|
||||
+ virCheckReadOnlyGoto(conn->flags, error);
|
||||
|
||||
if (conn->driver->domainSaveImageGetXMLDesc) {
|
||||
char *ret;
|
||||
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
|
||||
index 75d31efd14..b4a52f87a9 100644
|
||||
--- a/src/qemu/qemu_driver.c
|
||||
+++ b/src/qemu/qemu_driver.c
|
||||
@@ -7083,7 +7083,7 @@ qemuDomainSaveImageGetXMLDesc(virConnectPtr conn, const char *path,
|
||||
if (fd < 0)
|
||||
goto cleanup;
|
||||
|
||||
- if (virDomainSaveImageGetXMLDescEnsureACL(conn, def, flags) < 0)
|
||||
+ if (virDomainSaveImageGetXMLDescEnsureACL(conn, def) < 0)
|
||||
goto cleanup;
|
||||
|
||||
ret = qemuDomainDefFormatXML(driver, def, flags);
|
||||
diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x
|
||||
index 60cc40e04a..a67aba6131 100644
|
||||
--- a/src/remote/remote_protocol.x
|
||||
+++ b/src/remote/remote_protocol.x
|
||||
@@ -5234,8 +5234,7 @@ enum remote_procedure {
|
||||
/**
|
||||
* @generate: both
|
||||
* @priority: high
|
||||
- * @acl: domain:read
|
||||
- * @acl: domain:read_secure:VIR_DOMAIN_SAVE_IMAGE_XML_SECURE
|
||||
+ * @acl: domain:write
|
||||
*/
|
||||
REMOTE_PROC_DOMAIN_SAVE_IMAGE_GET_XML_DESC = 235,
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
From: =?UTF-8?q?J=C3=A1n=20Tomko?= <jtomko@redhat.com>
|
||||
Date: Fri, 14 Jun 2019 09:14:53 +0200
|
||||
Subject: [PATCH] api: disallow virDomainManagedSaveDefineXML on read-only
|
||||
connections
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
The virDomainManagedSaveDefineXML can be used to alter the domain's
|
||||
config used for managedsave or even execute arbitrary emulator binaries.
|
||||
Forbid it on read-only connections.
|
||||
|
||||
Fixes: CVE-2019-10166
|
||||
Reported-by: Matthias Gerstner <mgerstner@suse.de>
|
||||
Signed-off-by: Ján Tomko <jtomko@redhat.com>
|
||||
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
|
||||
(cherry picked from commit db0b78457f183e4c7ac45bc94de86044a1e2056a)
|
||||
---
|
||||
src/libvirt-domain.c | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/src/libvirt-domain.c b/src/libvirt-domain.c
|
||||
index ba0aaccdc1..ac7c4708b9 100644
|
||||
--- a/src/libvirt-domain.c
|
||||
+++ b/src/libvirt-domain.c
|
||||
@@ -9565,6 +9565,7 @@ virDomainManagedSaveDefineXML(virDomainPtr domain, const char *dxml,
|
||||
|
||||
virCheckDomainReturn(domain, -1);
|
||||
conn = domain->conn;
|
||||
+ virCheckReadOnlyGoto(conn->flags, error);
|
||||
|
||||
if (conn->driver->domainManagedSaveDefineXML) {
|
||||
int ret;
|
||||
@@ -0,0 +1,31 @@
|
||||
From: =?UTF-8?q?J=C3=A1n=20Tomko?= <jtomko@redhat.com>
|
||||
Date: Fri, 14 Jun 2019 09:16:14 +0200
|
||||
Subject: [PATCH] api: disallow virConnectGetDomainCapabilities on read-only
|
||||
connections
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
This API can be used to execute arbitrary emulators.
|
||||
Forbid it on read-only connections.
|
||||
|
||||
Fixes: CVE-2019-10167
|
||||
Signed-off-by: Ján Tomko <jtomko@redhat.com>
|
||||
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
|
||||
(cherry picked from commit 8afa68bac0cf99d1f8aaa6566685c43c22622f26)
|
||||
---
|
||||
src/libvirt-domain.c | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/src/libvirt-domain.c b/src/libvirt-domain.c
|
||||
index ac7c4708b9..f7b834dfa6 100644
|
||||
--- a/src/libvirt-domain.c
|
||||
+++ b/src/libvirt-domain.c
|
||||
@@ -11360,6 +11360,7 @@ virConnectGetDomainCapabilities(virConnectPtr conn,
|
||||
virResetLastError();
|
||||
|
||||
virCheckConnectReturn(conn, NULL);
|
||||
+ virCheckReadOnlyGoto(conn->flags, error);
|
||||
|
||||
if (conn->driver->connectGetDomainCapabilities) {
|
||||
char *ret;
|
||||
@@ -0,0 +1,39 @@
|
||||
From: =?UTF-8?q?J=C3=A1n=20Tomko?= <jtomko@redhat.com>
|
||||
Date: Fri, 14 Jun 2019 09:17:39 +0200
|
||||
Subject: [PATCH] api: disallow virConnect*HypervisorCPU on read-only
|
||||
connections
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
These APIs can be used to execute arbitrary emulators.
|
||||
Forbid them on read-only connections.
|
||||
|
||||
Fixes: CVE-2019-10168
|
||||
Signed-off-by: Ján Tomko <jtomko@redhat.com>
|
||||
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
|
||||
(cherry picked from commit bf6c2830b6c338b1f5699b095df36f374777b291)
|
||||
---
|
||||
src/libvirt-host.c | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
diff --git a/src/libvirt-host.c b/src/libvirt-host.c
|
||||
index e20d6ee250..2978825d22 100644
|
||||
--- a/src/libvirt-host.c
|
||||
+++ b/src/libvirt-host.c
|
||||
@@ -1041,6 +1041,7 @@ virConnectCompareHypervisorCPU(virConnectPtr conn,
|
||||
|
||||
virCheckConnectReturn(conn, VIR_CPU_COMPARE_ERROR);
|
||||
virCheckNonNullArgGoto(xmlCPU, error);
|
||||
+ virCheckReadOnlyGoto(conn->flags, error);
|
||||
|
||||
if (conn->driver->connectCompareHypervisorCPU) {
|
||||
int ret;
|
||||
@@ -1234,6 +1235,7 @@ virConnectBaselineHypervisorCPU(virConnectPtr conn,
|
||||
|
||||
virCheckConnectReturn(conn, NULL);
|
||||
virCheckNonNullArgGoto(xmlCPUs, error);
|
||||
+ virCheckReadOnlyGoto(conn->flags, error);
|
||||
|
||||
if (conn->driver->connectBaselineHypervisorCPU) {
|
||||
char *cpu;
|
||||
@@ -0,0 +1,32 @@
|
||||
From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= <berrange@redhat.com>
|
||||
Date: Wed, 27 Mar 2019 10:59:58 +0000
|
||||
Subject: [PATCH] api: disallow virDomainGetHostname for read-only connections
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
The virDomainGetHostname API is fetching guest information and this may
|
||||
involve use of an untrusted guest agent. As such its use must be
|
||||
forbidden on a read-only connection to libvirt.
|
||||
|
||||
Fixes CVE-2019-3886
|
||||
Reviewed-by: Jim Fehlig <jfehlig@suse.com>
|
||||
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
|
||||
(cherry picked from commit 2a07c990bd9143d7a0fe8d1b6b7c763c52185240)
|
||||
---
|
||||
src/libvirt-domain.c | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
diff --git a/src/libvirt-domain.c b/src/libvirt-domain.c
|
||||
index f7b834dfa6..c9bff31af5 100644
|
||||
--- a/src/libvirt-domain.c
|
||||
+++ b/src/libvirt-domain.c
|
||||
@@ -11025,6 +11025,8 @@ virDomainGetHostname(virDomainPtr domain, unsigned int flags)
|
||||
virCheckDomainReturn(domain, NULL);
|
||||
conn = domain->conn;
|
||||
|
||||
+ virCheckReadOnlyGoto(domain->conn->flags, error);
|
||||
+
|
||||
if (conn->driver->domainGetHostname) {
|
||||
char *ret;
|
||||
ret = conn->driver->domainGetHostname(domain, flags);
|
||||
@@ -0,0 +1,42 @@
|
||||
From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= <berrange@redhat.com>
|
||||
Date: Wed, 27 Mar 2019 11:22:49 +0000
|
||||
Subject: [PATCH] remote: enforce ACL write permission for getting guest time &
|
||||
hostname
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Getting the guest time and hostname both require use of guest agent
|
||||
commands. These must not be allowed for read-only users, so the
|
||||
permissions check must validate "write" permission not "read".
|
||||
|
||||
Fixes CVE-2019-3886
|
||||
Reviewed-by: Jim Fehlig <jfehlig@suse.com>
|
||||
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
|
||||
(cherry picked from commit ae076bb40e0e150aef41361b64001138d04d6c60)
|
||||
---
|
||||
src/remote/remote_protocol.x | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x
|
||||
index a67aba6131..ff9e34a852 100644
|
||||
--- a/src/remote/remote_protocol.x
|
||||
+++ b/src/remote/remote_protocol.x
|
||||
@@ -5504,7 +5504,7 @@ enum remote_procedure {
|
||||
|
||||
/**
|
||||
* @generate: both
|
||||
- * @acl: domain:read
|
||||
+ * @acl: domain:write
|
||||
*/
|
||||
REMOTE_PROC_DOMAIN_GET_HOSTNAME = 277,
|
||||
|
||||
@@ -5899,7 +5899,7 @@ enum remote_procedure {
|
||||
|
||||
/**
|
||||
* @generate: none
|
||||
- * @acl: domain:read
|
||||
+ * @acl: domain:write
|
||||
*/
|
||||
REMOTE_PROC_DOMAIN_GET_TIME = 337,
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
From: Michal Privoznik <mprivozn@redhat.com>
|
||||
Date: Wed, 10 Apr 2019 17:14:25 +0200
|
||||
Subject: [PATCH] qemu: Set up EMULATOR thread and cpuset.mems before
|
||||
exec()-ing qemu
|
||||
|
||||
It's funny how this went unnoticed for such a long time. Long
|
||||
story short, if a domain is configured with
|
||||
VIR_DOMAIN_NUMATUNE_MEM_STRICT libvirt doesn't really honour
|
||||
that. This is because of 7e72ac787848 after which libvirt allowed
|
||||
qemu to allocate memory just anywhere and only after that it used
|
||||
some magic involving cpuset.memory_migrate and cpuset.mems to
|
||||
move the memory to desired NUMA nodes. This was done in order to
|
||||
work around some KVM bug where KVM would fail if there wasn't a
|
||||
DMA zone available on the NUMA node. Well, while the work around
|
||||
might stopped libvirt tickling the KVM bug it also caused a bug
|
||||
on libvirt side: if there is not enough memory on configured NUMA
|
||||
node(s) then any attempt to start a domain must fail. Because of
|
||||
the way we play with guest memory domains can start just happily.
|
||||
|
||||
The solution is to move the child we've just forked into emulator
|
||||
cgroup, set up cpuset.mems and exec() qemu only after that.
|
||||
|
||||
This basically reverts 7e72ac787848b7434c9 which was a workaround
|
||||
for kernel bug. This bug was apparently fixed because I've tested
|
||||
this successfully with recent kernel.
|
||||
|
||||
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
|
||||
Reviewed-by: Martin Kletzander <mkletzan@redhat.com>
|
||||
(cherry picked from commit 0eaa4716e1b8f6eb59d77049aed3735c3b5fbdd6)
|
||||
---
|
||||
src/qemu/qemu_process.c | 8 ++++----
|
||||
1 file changed, 4 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
|
||||
index 68c670d3f2..3bcc2ebd71 100644
|
||||
--- a/src/qemu/qemu_process.c
|
||||
+++ b/src/qemu/qemu_process.c
|
||||
@@ -6636,6 +6636,10 @@ qemuProcessLaunch(virConnectPtr conn,
|
||||
if (qemuProcessInitCpuAffinity(vm) < 0)
|
||||
goto cleanup;
|
||||
|
||||
+ VIR_DEBUG("Setting emulator tuning/settings");
|
||||
+ if (qemuProcessSetupEmulator(vm) < 0)
|
||||
+ goto cleanup;
|
||||
+
|
||||
VIR_DEBUG("Setting cgroup for external devices (if required)");
|
||||
if (qemuSetupCgroupForExtDevices(vm, driver) < 0)
|
||||
goto cleanup;
|
||||
@@ -6727,10 +6731,6 @@ qemuProcessLaunch(virConnectPtr conn,
|
||||
if (qemuProcessDetectIOThreadPIDs(driver, vm, asyncJob) < 0)
|
||||
goto cleanup;
|
||||
|
||||
- VIR_DEBUG("Setting emulator tuning/settings");
|
||||
- if (qemuProcessSetupEmulator(vm) < 0)
|
||||
- goto cleanup;
|
||||
-
|
||||
VIR_DEBUG("Setting global CPU cgroup (if required)");
|
||||
if (qemuSetupGlobalCpuCgroup(vm) < 0)
|
||||
goto cleanup;
|
||||
@@ -0,0 +1,35 @@
|
||||
From: Peter Krempa <pkrempa@redhat.com>
|
||||
Date: Fri, 17 May 2019 10:15:53 +0200
|
||||
Subject: [PATCH] qemu: blockjob: Fix saving of inactive XML after completed
|
||||
legacy blockjob
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Commit c257352797 introduced a logic bug where we will never save the
|
||||
inactive XML after a blockjob as the variable which was determining
|
||||
whether to do so is cleared right before. Thus even if we correctly
|
||||
modify the inactive state it will be rolled back when libvirtd is
|
||||
restarted.
|
||||
|
||||
Reported-by: Thomas Stein <hello@himbee.re>
|
||||
Signed-off-by: Peter Krempa <pkrempa@redhat.com>
|
||||
Reviewed-by: Ján Tomko <jtomko@redhat.com>
|
||||
(cherry picked from commit 4d8cc5a07a0dcc0ac99377f66a4649d219705452)
|
||||
---
|
||||
src/qemu/qemu_blockjob.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/src/qemu/qemu_blockjob.c b/src/qemu/qemu_blockjob.c
|
||||
index fa7e4c8625..f105632a09 100644
|
||||
--- a/src/qemu/qemu_blockjob.c
|
||||
+++ b/src/qemu/qemu_blockjob.c
|
||||
@@ -363,7 +363,7 @@ qemuBlockJobEventProcessLegacy(virQEMUDriverPtr driver,
|
||||
if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm, driver->caps) < 0)
|
||||
VIR_WARN("Unable to save status on vm %s after block job", vm->def->name);
|
||||
|
||||
- if (job->newstate == VIR_DOMAIN_BLOCK_JOB_COMPLETED && vm->newDef) {
|
||||
+ if (job->state == VIR_DOMAIN_BLOCK_JOB_COMPLETED && vm->newDef) {
|
||||
if (virDomainSaveConfig(cfg->configDir, driver->caps, vm->newDef) < 0)
|
||||
VIR_WARN("Unable to update persistent definition on vm %s "
|
||||
"after block job", vm->def->name);
|
||||
@@ -1,356 +0,0 @@
|
||||
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
|
||||
|
||||
@@ -1,159 +0,0 @@
|
||||
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
|
||||
|
||||
@@ -1,585 +0,0 @@
|
||||
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
|
||||
|
||||
@@ -1,285 +0,0 @@
|
||||
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
|
||||
|
||||
@@ -1,170 +0,0 @@
|
||||
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
|
||||
|
||||
@@ -1,506 +0,0 @@
|
||||
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
@@ -1,468 +0,0 @@
|
||||
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
|
||||
|
||||
@@ -1,94 +0,0 @@
|
||||
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
|
||||
|
||||
@@ -1,291 +0,0 @@
|
||||
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
|
||||
|
||||
@@ -1,165 +0,0 @@
|
||||
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
|
||||
|
||||
@@ -1,265 +0,0 @@
|
||||
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
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
From 66aaaf1af42d6f1e9f9b75bd1514c0c097e244e6 Mon Sep 17 00:00:00 2001
|
||||
From: Jiri Denemark <jdenemar@redhat.com>
|
||||
Date: Fri, 25 Mar 2011 16:45:45 +0100
|
||||
Subject: [PATCH 2/2] daemon: Avoid resetting errors before they are reported
|
||||
|
||||
https://bugzilla.redhat.com/show_bug.cgi?id=690733
|
||||
|
||||
Commit f44bfb7 was supposed to make sure no additional libvirt API (esp.
|
||||
*Free) is called before remoteDispatchConnError() is called on error.
|
||||
However, the patch missed two instances.
|
||||
(cherry picked from commit 55cc591fc18e87b29febf78dc5b424b7c12f7349)
|
||||
---
|
||||
daemon/remote.c | 6 ++++--
|
||||
1 files changed, 4 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/daemon/remote.c b/daemon/remote.c
|
||||
index abf9cf3..8a25f05 100644
|
||||
--- a/daemon/remote.c
|
||||
+++ b/daemon/remote.c
|
||||
@@ -4531,12 +4531,13 @@ remoteDispatchStoragePoolListVolumes (struct qemud_server *server ATTRIBUTE_UNUS
|
||||
ret->names.names_len =
|
||||
virStoragePoolListVolumes (pool,
|
||||
ret->names.names_val, args->maxnames);
|
||||
- virStoragePoolFree(pool);
|
||||
if (ret->names.names_len == -1) {
|
||||
VIR_FREE(ret->names.names_val);
|
||||
remoteDispatchConnError(rerr, conn);
|
||||
+ virStoragePoolFree(pool);
|
||||
return -1;
|
||||
}
|
||||
+ virStoragePoolFree(pool);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -4560,11 +4561,12 @@ remoteDispatchStoragePoolNumOfVolumes (struct qemud_server *server ATTRIBUTE_UNU
|
||||
}
|
||||
|
||||
ret->num = virStoragePoolNumOfVolumes (pool);
|
||||
- virStoragePoolFree(pool);
|
||||
if (ret->num == -1) {
|
||||
remoteDispatchConnError(rerr, conn);
|
||||
+ virStoragePoolFree(pool);
|
||||
return -1;
|
||||
}
|
||||
+ virStoragePoolFree(pool);
|
||||
|
||||
return 0;
|
||||
}
|
||||
--
|
||||
1.7.3.4
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
From f970d802ab805f1a37af384f148f34e108714034 Mon Sep 17 00:00:00 2001
|
||||
From: Eric Blake <eblake@redhat.com>
|
||||
Date: Wed, 3 Nov 2010 15:20:24 -0600
|
||||
Subject: [PATCH] rpm: fix /var/lib/libvirt permissions
|
||||
|
||||
https://bugzilla.redhat.com/show_bug.cgi?id=649511
|
||||
|
||||
Regression of forcing 0700 permissions (which breaks guest startup
|
||||
because the qemu user can't see /var/lib/libvirt/*.monitor) was
|
||||
introduced in commit 66823690e, as part of libvirt 0.8.2.
|
||||
|
||||
* libvirt.spec.in (%files): Drop %{_localstatedir}/lib/libvirt,
|
||||
since libvirt depends on libvirt-client.
|
||||
(%files client): Guarantee 755 permissions on
|
||||
%(_localstatedir}/lib/libvirt, since the qemu user must be able to
|
||||
do pathname resolution to a subdirectory.
|
||||
---
|
||||
libvirt.spec.in | 3 +--
|
||||
1 files changed, 1 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/libvirt.spec.in b/libvirt.spec.in
|
||||
index 813e0c0..f77626e 100644
|
||||
--- a/libvirt.spec.in
|
||||
+++ b/libvirt.spec.in
|
||||
@@ -770,7 +770,6 @@ fi
|
||||
|
||||
%dir %{_localstatedir}/run/libvirt/
|
||||
|
||||
-%dir %{_localstatedir}/lib/libvirt/
|
||||
%dir %attr(0711, root, root) %{_localstatedir}/lib/libvirt/images/
|
||||
%dir %attr(0711, root, root) %{_localstatedir}/lib/libvirt/boot/
|
||||
%dir %attr(0700, root, root) %{_localstatedir}/cache/libvirt/
|
||||
@@ -862,7 +861,7 @@ fi
|
||||
|
||||
%{_sysconfdir}/rc.d/init.d/libvirt-guests
|
||||
%config(noreplace) %{_sysconfdir}/sysconfig/libvirt-guests
|
||||
-%dir %attr(0700, root, root) %{_localstatedir}/lib/libvirt
|
||||
+%dir %attr(0755, root, root) %{_localstatedir}/lib/libvirt/
|
||||
|
||||
%if %{with_sasl}
|
||||
%config(noreplace) %{_sysconfdir}/sasl2/libvirt.conf
|
||||
--
|
||||
1.7.3.4
|
||||
|
||||
@@ -1,95 +0,0 @@
|
||||
From: Guido Günther <agx@sigxcpu.org>
|
||||
Date: Mon, 14 Mar 2011 02:56:28 +0000 (+0800)
|
||||
Subject: Add missing checks for read only connections
|
||||
X-Git-Url: http://libvirt.org/git/?p=libvirt.git;a=commitdiff_plain;h=71753cb7f7a16ff800381c0b5ee4e99eea92fed3;hp=13c00dde3171b3a38d23cceb3f9151cb6cac3dad
|
||||
|
||||
Add missing checks for read only connections
|
||||
|
||||
As pointed on CVE-2011-1146, some API forgot to check the read-only
|
||||
status of the connection for entry point which modify the state
|
||||
of the system or may lead to a remote execution using user data.
|
||||
The entry points concerned are:
|
||||
- virConnectDomainXMLToNative
|
||||
- virNodeDeviceDettach
|
||||
- virNodeDeviceReAttach
|
||||
- virNodeDeviceReset
|
||||
- virDomainRevertToSnapshot
|
||||
- virDomainSnapshotDelete
|
||||
|
||||
* src/libvirt.c: fix the above set of entry points to error on read-only
|
||||
connections
|
||||
|
||||
Rebased to 0.8.2, mostly changed the call of the error routines
|
||||
---
|
||||
|
||||
--- src/libvirt.c.orig 2011-03-14 17:03:45.000000000 +0800
|
||||
+++ src/libvirt.c 2011-03-14 17:10:41.000000000 +0800
|
||||
@@ -3190,6 +3190,10 @@ char *virConnectDomainXMLToNative(virCon
|
||||
virDispatchError(NULL);
|
||||
return (NULL);
|
||||
}
|
||||
+ if (conn->flags & VIR_CONNECT_RO) {
|
||||
+ virLibConnError(NULL, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
|
||||
+ goto error;
|
||||
+ }
|
||||
|
||||
if (nativeFormat == NULL || domainXml == NULL) {
|
||||
virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
|
||||
@@ -9432,6 +9436,11 @@ virNodeDeviceDettach(virNodeDevicePtr de
|
||||
return (-1);
|
||||
}
|
||||
|
||||
+ if (dev->conn->flags & VIR_CONNECT_RO) {
|
||||
+ virLibConnError(dev->conn, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
|
||||
+ goto error;
|
||||
+ }
|
||||
+
|
||||
if (dev->conn->driver->nodeDeviceDettach) {
|
||||
int ret;
|
||||
ret = dev->conn->driver->nodeDeviceDettach (dev);
|
||||
@@ -9475,6 +9484,11 @@ virNodeDeviceReAttach(virNodeDevicePtr d
|
||||
return (-1);
|
||||
}
|
||||
|
||||
+ if (dev->conn->flags & VIR_CONNECT_RO) {
|
||||
+ virLibConnError(dev->conn, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
|
||||
+ goto error;
|
||||
+ }
|
||||
+
|
||||
if (dev->conn->driver->nodeDeviceReAttach) {
|
||||
int ret;
|
||||
ret = dev->conn->driver->nodeDeviceReAttach (dev);
|
||||
@@ -9520,6 +9534,11 @@ virNodeDeviceReset(virNodeDevicePtr dev)
|
||||
return (-1);
|
||||
}
|
||||
|
||||
+ if (dev->conn->flags & VIR_CONNECT_RO) {
|
||||
+ virLibConnError(dev->conn, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
|
||||
+ goto error;
|
||||
+ }
|
||||
+
|
||||
if (dev->conn->driver->nodeDeviceReset) {
|
||||
int ret;
|
||||
ret = dev->conn->driver->nodeDeviceReset (dev);
|
||||
@@ -12775,6 +12794,10 @@ virDomainRevertToSnapshot(virDomainSnaps
|
||||
}
|
||||
|
||||
conn = snapshot->domain->conn;
|
||||
+ if (conn->flags & VIR_CONNECT_RO) {
|
||||
+ virLibConnError(conn, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
|
||||
+ goto error;
|
||||
+ }
|
||||
|
||||
if (conn->driver->domainRevertToSnapshot) {
|
||||
int ret = conn->driver->domainRevertToSnapshot(snapshot, flags);
|
||||
@@ -12821,6 +12844,10 @@ virDomainSnapshotDelete(virDomainSnapsho
|
||||
}
|
||||
|
||||
conn = snapshot->domain->conn;
|
||||
+ if (conn->flags & VIR_CONNECT_RO) {
|
||||
+ virLibConnError(conn, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
|
||||
+ goto error;
|
||||
+ }
|
||||
|
||||
if (conn->driver->domainSnapshotDelete) {
|
||||
int ret = conn->driver->domainSnapshotDelete(snapshot, flags);
|
||||
File diff suppressed because it is too large
Load Diff
+1764
-1128
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user