forked from rpms/libvirt
313 lines
14 KiB
Diff
313 lines
14 KiB
Diff
From d9369eae049c780ebd130a13eedfaaf3586242eb Mon Sep 17 00:00:00 2001
|
|
Message-Id: <d9369eae049c780ebd130a13eedfaaf3586242eb@dist-git>
|
|
From: Michal Privoznik <mprivozn@redhat.com>
|
|
Date: Mon, 9 Mar 2020 14:58:57 +0100
|
|
Subject: [PATCH] qemu: Tell secdrivers which images are top parent
|
|
|
|
When preparing images for block jobs we modify their seclabels so
|
|
that QEMU can open them. However, as mentioned in the previous
|
|
commit, secdrivers base some it their decisions whether the image
|
|
they are working on is top of of the backing chain. Fortunately,
|
|
in places where we call secdrivers we know this and the
|
|
information can be passed to secdrivers.
|
|
|
|
The problem is the following: after the first blockcommit from
|
|
the base to one of the parents the XATTRs on the base image are
|
|
not cleared and therefore the second attempt to do another
|
|
blockcommit fails. This is caused by blockcommit code calling
|
|
qemuSecuritySetImageLabel() over the base image, possibly
|
|
multiple times (to ensure RW/RO access). A naive fix would be to
|
|
call the restore function. But this is not possible, because that
|
|
would deny QEMU the access to the base image. Fortunately, we
|
|
can use the fact that seclabels are remembered only for the top
|
|
of the backing chain and not for the rest of the backing chain.
|
|
And thanks to the previous commit we can tell secdrivers which
|
|
images are top of the backing chain.
|
|
|
|
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1803551
|
|
|
|
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
|
|
Reviewed-by: Peter Krempa <pkrempa@redhat.com>
|
|
(cherry picked from commit 13eb6c14682004d0dc692554475125db0f161da7)
|
|
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
|
|
Message-Id: <a8d9171d9f88b325480c17969e074d62d3eeba3b.1583760062.git.mprivozn@redhat.com>
|
|
Reviewed-by: Jiri Denemark <jdenemar@redhat.com>
|
|
---
|
|
src/qemu/qemu_backup.c | 4 ++--
|
|
src/qemu/qemu_blockjob.c | 6 ++++--
|
|
src/qemu/qemu_checkpoint.c | 6 ++++--
|
|
src/qemu/qemu_domain.c | 24 ++++++++++++++++++++----
|
|
src/qemu/qemu_domain.h | 3 ++-
|
|
src/qemu/qemu_driver.c | 23 +++++++++++++++++------
|
|
src/qemu/qemu_process.c | 2 +-
|
|
src/qemu/qemu_security.c | 6 +++++-
|
|
src/qemu/qemu_security.h | 3 ++-
|
|
9 files changed, 57 insertions(+), 20 deletions(-)
|
|
|
|
diff --git a/src/qemu/qemu_backup.c b/src/qemu/qemu_backup.c
|
|
index 2cc6ff7a42..8b66ee8d1f 100644
|
|
--- a/src/qemu/qemu_backup.c
|
|
+++ b/src/qemu/qemu_backup.c
|
|
@@ -469,8 +469,8 @@ qemuBackupDiskPrepareOneStorage(virDomainObjPtr vm,
|
|
dd->created = true;
|
|
}
|
|
|
|
- if (qemuDomainStorageSourceAccessAllow(priv->driver, vm, dd->store, false,
|
|
- true) < 0)
|
|
+ if (qemuDomainStorageSourceAccessAllow(priv->driver, vm, dd->store,
|
|
+ false, true, true) < 0)
|
|
return -1;
|
|
|
|
dd->labelled = true;
|
|
diff --git a/src/qemu/qemu_blockjob.c b/src/qemu/qemu_blockjob.c
|
|
index 71df0d1ab2..e894e1634d 100644
|
|
--- a/src/qemu/qemu_blockjob.c
|
|
+++ b/src/qemu/qemu_blockjob.c
|
|
@@ -1105,9 +1105,11 @@ qemuBlockJobProcessEventCompletedCommit(virQEMUDriverPtr driver,
|
|
return;
|
|
|
|
/* revert access to images */
|
|
- qemuDomainStorageSourceAccessAllow(driver, vm, job->data.commit.base, true, false);
|
|
+ qemuDomainStorageSourceAccessAllow(driver, vm, job->data.commit.base,
|
|
+ true, false, false);
|
|
if (job->data.commit.topparent != job->disk->src)
|
|
- qemuDomainStorageSourceAccessAllow(driver, vm, job->data.commit.topparent, true, false);
|
|
+ qemuDomainStorageSourceAccessAllow(driver, vm, job->data.commit.topparent,
|
|
+ true, false, true);
|
|
|
|
baseparent->backingStore = NULL;
|
|
job->data.commit.topparent->backingStore = job->data.commit.base;
|
|
diff --git a/src/qemu/qemu_checkpoint.c b/src/qemu/qemu_checkpoint.c
|
|
index c06bfe6a21..fe54af74ec 100644
|
|
--- a/src/qemu/qemu_checkpoint.c
|
|
+++ b/src/qemu/qemu_checkpoint.c
|
|
@@ -298,7 +298,8 @@ qemuCheckpointDiscardBitmaps(virDomainObjPtr vm,
|
|
for (next = reopenimages; next; next = next->next) {
|
|
virStorageSourcePtr src = next->data;
|
|
|
|
- if (qemuDomainStorageSourceAccessAllow(driver, vm, src, false, false) < 0)
|
|
+ if (qemuDomainStorageSourceAccessAllow(driver, vm, src,
|
|
+ false, false, false) < 0)
|
|
goto relabel;
|
|
|
|
relabelimages = g_slist_prepend(relabelimages, src);
|
|
@@ -313,7 +314,8 @@ qemuCheckpointDiscardBitmaps(virDomainObjPtr vm,
|
|
for (next = relabelimages; next; next = next->next) {
|
|
virStorageSourcePtr src = next->data;
|
|
|
|
- ignore_value(qemuDomainStorageSourceAccessAllow(driver, vm, src, true, false));
|
|
+ ignore_value(qemuDomainStorageSourceAccessAllow(driver, vm, src,
|
|
+ true, false, false));
|
|
}
|
|
|
|
return rc;
|
|
diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
|
|
index 3cbe7ef6e1..14bab896bc 100644
|
|
--- a/src/qemu/qemu_domain.c
|
|
+++ b/src/qemu/qemu_domain.c
|
|
@@ -11770,6 +11770,8 @@ typedef enum {
|
|
QEMU_DOMAIN_STORAGE_SOURCE_ACCESS_SKIP_REVOKE = 1 << 4,
|
|
/* VM already has access to the source and we are just modifying it */
|
|
QEMU_DOMAIN_STORAGE_SOURCE_ACCESS_MODIFY_ACCESS = 1 << 5,
|
|
+ /* whether the image is the top image of the backing chain (e.g. disk source) */
|
|
+ QEMU_DOMAIN_STORAGE_SOURCE_ACCESS_CHAIN_TOP = 1 << 6,
|
|
} qemuDomainStorageSourceAccessFlags;
|
|
|
|
|
|
@@ -11847,6 +11849,7 @@ qemuDomainStorageSourceAccessModify(virQEMUDriverPtr driver,
|
|
bool force_ro = flags & QEMU_DOMAIN_STORAGE_SOURCE_ACCESS_FORCE_READ_ONLY;
|
|
bool force_rw = flags & QEMU_DOMAIN_STORAGE_SOURCE_ACCESS_FORCE_READ_WRITE;
|
|
bool revoke = flags & QEMU_DOMAIN_STORAGE_SOURCE_ACCESS_REVOKE;
|
|
+ bool chain_top = flags & QEMU_DOMAIN_STORAGE_SOURCE_ACCESS_CHAIN_TOP;
|
|
int rc;
|
|
bool was_readonly = src->readonly;
|
|
bool revoke_cgroup = false;
|
|
@@ -11893,7 +11896,7 @@ qemuDomainStorageSourceAccessModify(virQEMUDriverPtr driver,
|
|
revoke_namespace = true;
|
|
}
|
|
|
|
- if (qemuSecuritySetImageLabel(driver, vm, src, chain) < 0)
|
|
+ if (qemuSecuritySetImageLabel(driver, vm, src, chain, chain_top) < 0)
|
|
goto revoke;
|
|
|
|
revoke_label = true;
|
|
@@ -11956,7 +11959,8 @@ qemuDomainStorageSourceChainAccessAllow(virQEMUDriverPtr driver,
|
|
virDomainObjPtr vm,
|
|
virStorageSourcePtr src)
|
|
{
|
|
- qemuDomainStorageSourceAccessFlags flags = QEMU_DOMAIN_STORAGE_SOURCE_ACCESS_CHAIN;
|
|
+ qemuDomainStorageSourceAccessFlags flags = QEMU_DOMAIN_STORAGE_SOURCE_ACCESS_CHAIN |
|
|
+ QEMU_DOMAIN_STORAGE_SOURCE_ACCESS_CHAIN_TOP;
|
|
|
|
return qemuDomainStorageSourceAccessModify(driver, vm, src, flags);
|
|
}
|
|
@@ -11968,7 +11972,8 @@ qemuDomainStorageSourceChainAccessRevoke(virQEMUDriverPtr driver,
|
|
virStorageSourcePtr src)
|
|
{
|
|
qemuDomainStorageSourceAccessFlags flags = QEMU_DOMAIN_STORAGE_SOURCE_ACCESS_REVOKE |
|
|
- QEMU_DOMAIN_STORAGE_SOURCE_ACCESS_CHAIN;
|
|
+ QEMU_DOMAIN_STORAGE_SOURCE_ACCESS_CHAIN |
|
|
+ QEMU_DOMAIN_STORAGE_SOURCE_ACCESS_CHAIN_TOP;
|
|
|
|
return qemuDomainStorageSourceAccessModify(driver, vm, src, flags);
|
|
}
|
|
@@ -11998,6 +12003,7 @@ qemuDomainStorageSourceAccessRevoke(virQEMUDriverPtr driver,
|
|
* @elem: source structure to set access for
|
|
* @readonly: setup read-only access if true
|
|
* @newSource: @elem describes a storage source which @vm can't access yet
|
|
+ * @chainTop: @elem is top parent of backing chain
|
|
*
|
|
* Allow a VM access to a single element of a disk backing chain; this helper
|
|
* ensures that the lock manager, cgroup device controller, and security manager
|
|
@@ -12005,13 +12011,20 @@ qemuDomainStorageSourceAccessRevoke(virQEMUDriverPtr driver,
|
|
*
|
|
* When modifying permissions of @elem which @vm can already access (is in the
|
|
* backing chain) @newSource needs to be set to false.
|
|
+ *
|
|
+ * The @chainTop flag must be set if the @elem image is the topmost image of a
|
|
+ * given backing chain or meant to become the topmost image (for e.g.
|
|
+ * snapshots, or blockcopy or even in the end for active layer block commit,
|
|
+ * where we discard the top of the backing chain so one of the intermediates
|
|
+ * (the base) becomes the top of the chain).
|
|
*/
|
|
int
|
|
qemuDomainStorageSourceAccessAllow(virQEMUDriverPtr driver,
|
|
virDomainObjPtr vm,
|
|
virStorageSourcePtr elem,
|
|
bool readonly,
|
|
- bool newSource)
|
|
+ bool newSource,
|
|
+ bool chainTop)
|
|
{
|
|
qemuDomainStorageSourceAccessFlags flags = QEMU_DOMAIN_STORAGE_SOURCE_ACCESS_SKIP_REVOKE;
|
|
|
|
@@ -12023,6 +12036,9 @@ qemuDomainStorageSourceAccessAllow(virQEMUDriverPtr driver,
|
|
if (!newSource)
|
|
flags |= QEMU_DOMAIN_STORAGE_SOURCE_ACCESS_MODIFY_ACCESS;
|
|
|
|
+ if (chainTop)
|
|
+ flags |= QEMU_DOMAIN_STORAGE_SOURCE_ACCESS_CHAIN_TOP;
|
|
+
|
|
return qemuDomainStorageSourceAccessModify(driver, vm, elem, flags);
|
|
}
|
|
|
|
diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h
|
|
index 83150e4e6d..9d143b575d 100644
|
|
--- a/src/qemu/qemu_domain.h
|
|
+++ b/src/qemu/qemu_domain.h
|
|
@@ -895,7 +895,8 @@ int qemuDomainStorageSourceAccessAllow(virQEMUDriverPtr driver,
|
|
virDomainObjPtr vm,
|
|
virStorageSourcePtr elem,
|
|
bool readonly,
|
|
- bool newSource);
|
|
+ bool newSource,
|
|
+ bool chainTop);
|
|
|
|
int qemuDomainPrepareStorageSourceBlockdev(virDomainDiskDefPtr disk,
|
|
virStorageSourcePtr src,
|
|
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
|
|
index d346446444..26f100177b 100644
|
|
--- a/src/qemu/qemu_driver.c
|
|
+++ b/src/qemu/qemu_driver.c
|
|
@@ -15467,7 +15467,8 @@ qemuDomainSnapshotDiskPrepareOne(virQEMUDriverPtr driver,
|
|
}
|
|
|
|
/* set correct security, cgroup and locking options on the new image */
|
|
- if (qemuDomainStorageSourceAccessAllow(driver, vm, dd->src, false, true) < 0)
|
|
+ if (qemuDomainStorageSourceAccessAllow(driver, vm, dd->src,
|
|
+ false, true, true) < 0)
|
|
return -1;
|
|
|
|
dd->prepared = true;
|
|
@@ -18815,11 +18816,19 @@ qemuDomainBlockCommit(virDomainPtr dom,
|
|
* operation succeeds, but doing that requires tracking the
|
|
* operation in XML across libvirtd restarts. */
|
|
clean_access = true;
|
|
- if (qemuDomainStorageSourceAccessAllow(driver, vm, baseSource, false, false) < 0 ||
|
|
- (top_parent && top_parent != disk->src &&
|
|
- qemuDomainStorageSourceAccessAllow(driver, vm, top_parent, false, false) < 0))
|
|
+ if (qemuDomainStorageSourceAccessAllow(driver, vm, baseSource,
|
|
+ false, false, false) < 0)
|
|
goto endjob;
|
|
|
|
+ if (top_parent && top_parent != disk->src) {
|
|
+ /* While top_parent is topmost image, we don't need to remember its
|
|
+ * owner as it will be overwritten upon finishing the commit. Hence,
|
|
+ * pass chainTop = false. */
|
|
+ if (qemuDomainStorageSourceAccessAllow(driver, vm, top_parent,
|
|
+ false, false, false) < 0)
|
|
+ goto endjob;
|
|
+ }
|
|
+
|
|
if (!(job = qemuBlockJobDiskNewCommit(vm, disk, top_parent, topSource,
|
|
baseSource,
|
|
flags & VIR_DOMAIN_BLOCK_COMMIT_DELETE,
|
|
@@ -18877,9 +18886,11 @@ qemuDomainBlockCommit(virDomainPtr dom,
|
|
virErrorPtr orig_err;
|
|
virErrorPreserveLast(&orig_err);
|
|
/* Revert access to read-only, if possible. */
|
|
- qemuDomainStorageSourceAccessAllow(driver, vm, baseSource, true, false);
|
|
+ qemuDomainStorageSourceAccessAllow(driver, vm, baseSource,
|
|
+ true, false, false);
|
|
if (top_parent && top_parent != disk->src)
|
|
- qemuDomainStorageSourceAccessAllow(driver, vm, top_parent, true, false);
|
|
+ qemuDomainStorageSourceAccessAllow(driver, vm, top_parent,
|
|
+ true, false, false);
|
|
|
|
virErrorRestore(&orig_err);
|
|
}
|
|
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
|
|
index 0476f18517..dffff04554 100644
|
|
--- a/src/qemu/qemu_process.c
|
|
+++ b/src/qemu/qemu_process.c
|
|
@@ -7823,7 +7823,7 @@ qemuProcessRefreshLegacyBlockjob(void *payload,
|
|
(qemuDomainNamespaceSetupDisk(vm, disk->mirror) < 0 ||
|
|
qemuSetupImageChainCgroup(vm, disk->mirror) < 0 ||
|
|
qemuSecuritySetImageLabel(priv->driver, vm, disk->mirror,
|
|
- true) < 0))
|
|
+ true, true) < 0))
|
|
goto cleanup;
|
|
}
|
|
}
|
|
diff --git a/src/qemu/qemu_security.c b/src/qemu/qemu_security.c
|
|
index 2aa2b5b9c6..484fc34552 100644
|
|
--- a/src/qemu/qemu_security.c
|
|
+++ b/src/qemu/qemu_security.c
|
|
@@ -98,7 +98,8 @@ int
|
|
qemuSecuritySetImageLabel(virQEMUDriverPtr driver,
|
|
virDomainObjPtr vm,
|
|
virStorageSourcePtr src,
|
|
- bool backingChain)
|
|
+ bool backingChain,
|
|
+ bool chainTop)
|
|
{
|
|
qemuDomainObjPrivatePtr priv = vm->privateData;
|
|
pid_t pid = -1;
|
|
@@ -108,6 +109,9 @@ qemuSecuritySetImageLabel(virQEMUDriverPtr driver,
|
|
if (backingChain)
|
|
labelFlags |= VIR_SECURITY_DOMAIN_IMAGE_LABEL_BACKING_CHAIN;
|
|
|
|
+ if (chainTop)
|
|
+ labelFlags |= VIR_SECURITY_DOMAIN_IMAGE_PARENT_CHAIN_TOP;
|
|
+
|
|
if (qemuDomainNamespaceEnabled(vm, QEMU_DOMAIN_NS_MOUNT))
|
|
pid = vm->pid;
|
|
|
|
diff --git a/src/qemu/qemu_security.h b/src/qemu/qemu_security.h
|
|
index a8c648ece1..c8516005ac 100644
|
|
--- a/src/qemu/qemu_security.h
|
|
+++ b/src/qemu/qemu_security.h
|
|
@@ -36,7 +36,8 @@ void qemuSecurityRestoreAllLabel(virQEMUDriverPtr driver,
|
|
int qemuSecuritySetImageLabel(virQEMUDriverPtr driver,
|
|
virDomainObjPtr vm,
|
|
virStorageSourcePtr src,
|
|
- bool backingChain);
|
|
+ bool backingChain,
|
|
+ bool chainTop);
|
|
|
|
int qemuSecurityRestoreImageLabel(virQEMUDriverPtr driver,
|
|
virDomainObjPtr vm,
|
|
--
|
|
2.25.1
|
|
|