Blame SOURCES/libvirt-qemu-caps-Use-CAP_DAC_OVERRIDE-for-probing-to-avoid-permission-issues.patch

9c6c51
From 0b90fc0c5d4bd3eecbf8b51ff996116bc137d199 Mon Sep 17 00:00:00 2001
9c6c51
Message-Id: <0b90fc0c5d4bd3eecbf8b51ff996116bc137d199@dist-git>
9c6c51
From: Erik Skultety <eskultet@redhat.com>
9c6c51
Date: Fri, 1 Feb 2019 17:21:58 +0100
9c6c51
Subject: [PATCH] qemu: caps: Use CAP_DAC_OVERRIDE for probing to avoid
9c6c51
 permission issues
9c6c51
MIME-Version: 1.0
9c6c51
Content-Type: text/plain; charset=UTF-8
9c6c51
Content-Transfer-Encoding: 8bit
9c6c51
9c6c51
This is mainly about /dev/sev and its default permissions 0600. Of
9c6c51
course, rule of 'tinfoil' would be that we can't trust anything, but the
9c6c51
probing code in QEMU is considered safe from security's perspective + we
9c6c51
can't create an udev rule for this at the moment, because ioctls and
9c6c51
file system permissions aren't cross-checked in kernel and therefore a
9c6c51
user with read permissions could issue a 'privileged' operation on SEV
9c6c51
which is currently only limited to root.
9c6c51
9c6c51
https://bugzilla.redhat.com/show_bug.cgi?id=1665400
9c6c51
9c6c51
Signed-off-by: Erik Skultety <eskultet@redhat.com>
9c6c51
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
9c6c51
(cherry picked from commit a2d3dea9d41dba313d9566120a8ec9d358567bd0)
9c6c51
9c6c51
Signed-off-by: Erik Skultety <eskultet@redhat.com>
9c6c51
Reviewed-by: Ján Tomko <jtomko@redhat.com>
9c6c51
---
9c6c51
 src/qemu/qemu_capabilities.c | 11 +++++++++++
9c6c51
 src/util/virutil.c           | 31 +++++++++++++++++++++++++++++--
9c6c51
 2 files changed, 40 insertions(+), 2 deletions(-)
9c6c51
9c6c51
diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c
9c6c51
index ba8c717e22..f71cd08f4d 100644
9c6c51
--- a/src/qemu/qemu_capabilities.c
9c6c51
+++ b/src/qemu/qemu_capabilities.c
9c6c51
@@ -55,6 +55,10 @@
9c6c51
 #include <stdarg.h>
9c6c51
 #include <sys/utsname.h>
9c6c51
 
9c6c51
+#if WITH_CAPNG
9c6c51
+# include <cap-ng.h>
9c6c51
+#endif
9c6c51
+
9c6c51
 #define VIR_FROM_THIS VIR_FROM_QEMU
9c6c51
 
9c6c51
 VIR_LOG_INIT("qemu.qemu_capabilities");
9c6c51
@@ -4474,6 +4478,13 @@ virQEMUCapsInitQMPCommandRun(virQEMUCapsInitQMPCommandPtr cmd,
9c6c51
                                     NULL);
9c6c51
     virCommandAddEnvPassCommon(cmd->cmd);
9c6c51
     virCommandClearCaps(cmd->cmd);
9c6c51
+
9c6c51
+#if WITH_CAPNG
9c6c51
+    /* QEMU might run into permission issues, e.g. /dev/sev (0600), override
9c6c51
+     * them just for the purpose of probing */
9c6c51
+    virCommandAllowCap(cmd->cmd, CAP_DAC_OVERRIDE);
9c6c51
+#endif
9c6c51
+
9c6c51
     virCommandSetGID(cmd->cmd, cmd->runGid);
9c6c51
     virCommandSetUID(cmd->cmd, cmd->runUid);
9c6c51
 
9c6c51
diff --git a/src/util/virutil.c b/src/util/virutil.c
9c6c51
index a908422feb..88e17e2c0f 100644
9c6c51
--- a/src/util/virutil.c
9c6c51
+++ b/src/util/virutil.c
9c6c51
@@ -1474,8 +1474,10 @@ virSetUIDGIDWithCaps(uid_t uid, gid_t gid, gid_t *groups, int ngroups,
9c6c51
 {
9c6c51
     size_t i;
9c6c51
     int capng_ret, ret = -1;
9c6c51
-    bool need_setgid = false, need_setuid = false;
9c6c51
+    bool need_setgid = false;
9c6c51
+    bool need_setuid = false;
9c6c51
     bool need_setpcap = false;
9c6c51
+    const char *capstr = NULL;
9c6c51
 
9c6c51
     /* First drop all caps (unless the requested uid is "unchanged" or
9c6c51
      * root and clearExistingCaps wasn't requested), then add back
9c6c51
@@ -1484,14 +1486,18 @@ virSetUIDGIDWithCaps(uid_t uid, gid_t gid, gid_t *groups, int ngroups,
9c6c51
      */
9c6c51
 
9c6c51
     if (clearExistingCaps || (uid != (uid_t)-1 && uid != 0))
9c6c51
-       capng_clear(CAPNG_SELECT_BOTH);
9c6c51
+        capng_clear(CAPNG_SELECT_BOTH);
9c6c51
 
9c6c51
     for (i = 0; i <= CAP_LAST_CAP; i++) {
9c6c51
+        capstr = capng_capability_to_name(i);
9c6c51
+
9c6c51
         if (capBits & (1ULL << i)) {
9c6c51
             capng_update(CAPNG_ADD,
9c6c51
                          CAPNG_EFFECTIVE|CAPNG_INHERITABLE|
9c6c51
                          CAPNG_PERMITTED|CAPNG_BOUNDING_SET,
9c6c51
                          i);
9c6c51
+
9c6c51
+            VIR_DEBUG("Added '%s' to child capabilities' set", capstr);
9c6c51
         }
9c6c51
     }
9c6c51
 
9c6c51
@@ -1551,6 +1557,27 @@ virSetUIDGIDWithCaps(uid_t uid, gid_t gid, gid_t *groups, int ngroups,
9c6c51
         goto cleanup;
9c6c51
     }
9c6c51
 
9c6c51
+# ifdef PR_CAP_AMBIENT
9c6c51
+    /* we couldn't do this in the loop earlier above, because the capabilities
9c6c51
+     * were not applied yet, since in order to add a capability into the AMBIENT
9c6c51
+     * set, it has to be present in both the PERMITTED and INHERITABLE sets
9c6c51
+     * (capabilities(7))
9c6c51
+     */
9c6c51
+    for (i = 0; i <= CAP_LAST_CAP; i++) {
9c6c51
+        capstr = capng_capability_to_name(i);
9c6c51
+
9c6c51
+        if (capBits & (1ULL << i)) {
9c6c51
+            if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, i, 0, 0) < 0) {
9c6c51
+                virReportSystemError(errno,
9c6c51
+                                     _("prctl failed to enable '%s' in the "
9c6c51
+                                       "AMBIENT set"),
9c6c51
+                                     capstr);
9c6c51
+                goto cleanup;
9c6c51
+            }
9c6c51
+        }
9c6c51
+    }
9c6c51
+# endif
9c6c51
+
9c6c51
     /* Set bounding set while we have CAP_SETPCAP.  Unfortunately we cannot
9c6c51
      * do this if we failed to get the capability above, so ignore the
9c6c51
      * return value.
9c6c51
-- 
9c6c51
2.20.1
9c6c51