render / rpms / libvirt

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