From: Christian Ehrhardt <christian.ehrhardt@canonical.com>
Date: Wed, 13 Jan 2021 12:32:18 +0100
Subject: apparmor: let image label setting loop over backing files

When adding a rule for an image file and that image file has a chain
of backing files then we need to add a rule for each of those files.

To get that iterate over the backing file chain the same way as
dac/selinux already do and add a label for each.

Fixes: https://gitlab.com/libvirt/libvirt/-/issues/118

Reviewed-by: Peter Krempa <pkrempa@redhat.com>
Reviewed-by: Jim Fehlig <jfehlig@suse.com>
Signed-off-by: Christian Ehrhardt <christian.ehrhardt@canonical.com>
(cherry picked from commit d51ad0008dc2df0257f69e767ab3e3c5fd1457ff)
---
 src/security/security_apparmor.c | 39 +++++++++++++++++++++++++++------------
 1 file changed, 27 insertions(+), 12 deletions(-)

diff --git a/src/security/security_apparmor.c b/src/security/security_apparmor.c
index 1b035cc..f547601 100644
--- a/src/security/security_apparmor.c
+++ b/src/security/security_apparmor.c
@@ -755,22 +755,13 @@ AppArmorRestoreInputLabel(virSecurityManagerPtr mgr,
 
 /* Called when hotplugging */
 static int
-AppArmorSetSecurityImageLabel(virSecurityManagerPtr mgr,
-                              virDomainDefPtr def,
-                              virStorageSourcePtr src,
-                              virSecurityDomainImageLabelFlags flags G_GNUC_UNUSED)
+AppArmorSetSecurityImageLabelInternal(virSecurityManagerPtr mgr,
+                                      virDomainDefPtr def,
+                                      virStorageSourcePtr src)
 {
-    virSecurityLabelDefPtr secdef;
     g_autofree char *vfioGroupDev = NULL;
     const char *path;
 
-    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_APPARMOR_NAME);
-    if (!secdef || !secdef->relabel)
-        return 0;
-
-    if (!secdef->imagelabel)
-        return 0;
-
     if (src->type == VIR_STORAGE_TYPE_NVME) {
         const virStorageSourceNVMeDef *nvme = src->nvme;
 
@@ -796,6 +787,30 @@ AppArmorSetSecurityImageLabel(virSecurityManagerPtr mgr,
     return reload_profile(mgr, def, path, true);
 }
 
+static int
+AppArmorSetSecurityImageLabel(virSecurityManagerPtr mgr,
+                              virDomainDefPtr def,
+                              virStorageSourcePtr src,
+                              virSecurityDomainImageLabelFlags flags G_GNUC_UNUSED)
+{
+    virSecurityLabelDefPtr secdef;
+    virStorageSourcePtr n;
+
+    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_APPARMOR_NAME);
+    if (!secdef || !secdef->relabel)
+        return 0;
+
+    if (!secdef->imagelabel)
+        return 0;
+
+    for (n = src; virStorageSourceIsBacking(n); n = n->backingStore) {
+        if (AppArmorSetSecurityImageLabelInternal(mgr, def, n) < 0)
+            return -1;
+    }
+
+    return 0;
+}
+
 static int
 AppArmorSecurityVerify(virSecurityManagerPtr mgr G_GNUC_UNUSED,
                        virDomainDefPtr def)
