Ping, I'd appreciate if somebody would find the time to review as I'd like to backport to 4.0 in Ubuntu soon.

On Thu, Mar 1, 2018 at 3:53 PM, Christian Ehrhardt <christian.ehrhardt@canonical.com> wrote:
In certain cases a xml contains paths that do not yet exist, but
are valid as qemu will create them later on - for example
vhostuser mode=server sockets.

In any such cases so far the check to virFileExists failed and due to
that the paths stayed non-resolved in regard to symlinks.

But for apparmor those non-resolved rules are non functional as they
are evaluated after resolving any symlinks.

Therefore for non-existent files and partially non-existent paths
resolve as much as possible to get valid rules.

Example:
   <interface type='vhostuser'>
       <model type='virtio'/>
       <source type='unix'
               path='/var/run/symlinknet'
               mode='server'/>
   </interface>

Got rendered as:
  "/var/run/symlinknet" rw,

But correct with "/var/run" being a symlink to "/run" is:
  "/run/symlinknet" rw,

Signed-off-by: Christian Ehrhardt <christian.ehrhardt@canonical.com>
---
 src/security/virt-aa-helper.c | 45 ++++++++++++++++++++++++++++++++++++-------
 1 file changed, 38 insertions(+), 7 deletions(-)

diff --git a/src/security/virt-aa-helper.c b/src/security/virt-aa-helper.c
index ff0068c..91bc339 100644
--- a/src/security/virt-aa-helper.c
+++ b/src/security/virt-aa-helper.c
@@ -41,6 +41,7 @@
 #include "viralloc.h"
 #include "vircommand.h"
 #include "virlog.h"
+#include "dirname.h"
 #include "driver.h"

 #include "security_driver.h"
@@ -752,6 +753,9 @@ vah_add_path(virBufferPtr buf, const char *path, const char *perms, bool recursi
     bool explicit_deny_rule = true;
     char *sub = NULL;
     char *perms_new = NULL;
+    char *pathdir = NULL;
+    char *pathtmp = NULL;
+    char *pathreal = NULL;

     if (path == NULL)
         return rc;
@@ -766,14 +770,38 @@ vah_add_path(virBufferPtr buf, const char *path, const char *perms, bool recursi
         return 0;
     }

-    if (virFileExists(path)) {
-        if ((tmp = realpath(path, NULL)) == NULL) {
-            vah_error(NULL, 0, path);
-            vah_error(NULL, 0, _("could not find realpath for disk"));
-            return rc;
+    /* files might be created by qemu later on and not exist right now.
+     * But realpath needs a valid path to work on, therefore:
+     * 1. walk the path to find longest valid path
+     * 2. get the realpath of that valid path
+     * 3. re-combine the realpath with the remaining suffix
+     * Note: A totally non existent path is used as-is
+     */
+    if ((pathdir = mdir_name(path)) == NULL)
+        goto cleanup;
+    while (!virFileExists(pathdir)) {
+        if (VIR_STRDUP_QUIET(pathtmp, pathdir) < 0)
+            goto cleanup;
+        VIR_FREE(pathdir);
+        if ((pathdir = mdir_name(pathtmp)) == NULL)
+            goto cleanup;
+        VIR_FREE(pathtmp);
+    }
+
+    if (strlen(pathdir) == 1) {
+        /* nothing of the path does exist yet */
+        if (VIR_STRDUP_QUIET(tmp, path) < 0)
+            goto cleanup;
+    } else {
+        if (VIR_STRDUP_QUIET(pathtmp, path+strlen(pathdir)) < 0)
+            goto cleanup;
+        if ((pathreal = realpath(pathdir, NULL)) == NULL) {
+            vah_error(NULL, 0, pathdir);
+            vah_error(NULL, 0, _("could not find realpath"));
+            goto cleanup;
         }
-    } else if (VIR_STRDUP_QUIET(tmp, path) < 0) {
-        return rc;
+        if (virAsprintfQuiet(&tmp, "%s%s", pathreal, pathtmp) < 0)
+            goto cleanup;
     }

     if (VIR_STRDUP_QUIET(perms_new, perms) < 0)
@@ -814,6 +842,9 @@ vah_add_path(virBufferPtr buf, const char *path, const char *perms, bool recursi
     }

  cleanup:
+    VIR_FREE(pathdir);
+    VIR_FREE(pathtmp);
+    VIR_FREE(pathreal);
     VIR_FREE(perms_new);
     VIR_FREE(tmp);

--
2.7.4




--
Christian Ehrhardt
Software Engineer, Ubuntu Server
Canonical Ltd