This patch attempts to run virtiofsd with libvirtd's label and the category of the currently ran domain, which obviously does nothing without a corresponding policy.
Per: https://www.redhat.com/archives/libvir-list/2020-February/msg00108.html a new type might be needed. TODO: file a SELinux policy bug --- src/libvirt_private.syms | 1 + src/qemu/qemu_security.c | 40 +++++++++++++++++++ src/qemu/qemu_security.h | 7 ++++ src/qemu/qemu_virtiofs.c | 4 +- src/security/security_dac.c | 20 ++++++++++ src/security/security_driver.h | 2 + src/security/security_manager.c | 12 ++++++ src/security/security_manager.h | 4 ++ src/security/security_nop.c | 1 + src/security/security_selinux.c | 69 +++++++++++++++++++++++++++++++++ src/security/security_stack.c | 19 +++++++++ 11 files changed, 178 insertions(+), 1 deletion(-) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 49eb8ab7cb..aaba15297a 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1504,6 +1504,7 @@ virSecurityManagerSetSavedStateLabel; virSecurityManagerSetSocketLabel; virSecurityManagerSetTapFDLabel; virSecurityManagerSetTPMLabels; +virSecurityManagerSetVirtioFSProcessLabel; virSecurityManagerStackAddNested; virSecurityManagerTransactionAbort; virSecurityManagerTransactionCommit; diff --git a/src/qemu/qemu_security.c b/src/qemu/qemu_security.c index 2aa2b5b9c6..834556c910 100644 --- a/src/qemu/qemu_security.c +++ b/src/qemu/qemu_security.c @@ -475,6 +475,46 @@ qemuSecurityStartVhostUserGPU(virQEMUDriverPtr driver, } +/* + * qemuSecurityStartVhostUserGPU: + * + * @driver: the QEMU driver + * @vm: the domain object + * @cmd: the command to run + * @existstatus: pointer to int returning exit status of process + * @cmdret: pointer to int returning result of virCommandRun + * + * Start the vhost-user-gpu process with approriate labels. + * This function returns -1 on security setup error, 0 if all the + * setup was done properly. In case the virCommand failed to run + * 0 is returned but cmdret is set appropriately with the process + * exitstatus also set. + */ +int +qemuSecurityStartVirtioFS(virQEMUDriverPtr driver, + virDomainObjPtr vm, + virCommandPtr cmd, + int *exitstatus, + int *cmdret) +{ + if (virSecurityManagerSetVirtioFSProcessLabel(driver->securityManager, + vm->def, cmd) < 0) + return -1; + + if (virSecurityManagerPreFork(driver->securityManager) < 0) + return -1; + + *cmdret = virCommandRun(cmd, exitstatus); + + virSecurityManagerPostFork(driver->securityManager); + + if (*cmdret < 0) + return -1; + + return 0; +} + + /* * qemuSecurityStartTPMEmulator: * diff --git a/src/qemu/qemu_security.h b/src/qemu/qemu_security.h index a8c648ece1..dbb3bdbc9b 100644 --- a/src/qemu/qemu_security.h +++ b/src/qemu/qemu_security.h @@ -84,6 +84,13 @@ int qemuSecurityStartVhostUserGPU(virQEMUDriverPtr driver, int *exitstatus, int *cmdret); +int qemuSecurityStartVirtioFS(virQEMUDriverPtr driver, + virDomainObjPtr vm, + virCommandPtr cmd, + int *exitstatus, + int *cmdret); + + int qemuSecurityStartTPMEmulator(virQEMUDriverPtr driver, virDomainObjPtr vm, virCommandPtr cmd, diff --git a/src/qemu/qemu_virtiofs.c b/src/qemu/qemu_virtiofs.c index b53e5b0806..17afe27535 100644 --- a/src/qemu/qemu_virtiofs.c +++ b/src/qemu/qemu_virtiofs.c @@ -34,6 +34,7 @@ #define VIR_FROM_THIS VIR_FROM_QEMU +VIR_LOG_INIT("qemu.virtiofs"); char * qemuVirtioFSCreatePidFilename(virQEMUDriverConfigPtr cfg, @@ -227,7 +228,8 @@ qemuVirtioFSStart(virLogManagerPtr logManager, if (qemuExtDeviceLogCommand(driver, vm, cmd, "virtiofsd") < 0) goto cleanup; - rc = virCommandRun(cmd, NULL); + if (qemuSecurityStartVirtioFS(driver, vm, cmd, NULL, &rc) < 0) + goto error; if (rc < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", diff --git a/src/security/security_dac.c b/src/security/security_dac.c index d75b18170b..64e00b0127 100644 --- a/src/security/security_dac.c +++ b/src/security/security_dac.c @@ -2263,6 +2263,24 @@ virSecurityDACSetChildProcessLabel(virSecurityManagerPtr mgr, if (virSecurityDACGetIds(secdef, priv, &user, &group, NULL, NULL) < 0) return -1; + VIR_DEBUG("Setting child to drop privileges to %u:%u", + (unsigned int)user, (unsigned int)group); + + virCommandSetUID(cmd, user); + virCommandSetGID(cmd, group); + return 0; +} + + +static int +virSecurityDACSetVirtioFSProcessLabel(virSecurityManagerPtr mgr G_GNUC_UNUSED, + virDomainDefPtr def G_GNUC_UNUSED, + virCommandPtr cmd) +{ + /* only running as root:root is supported */ + uid_t user = 0; + gid_t group = 0; + VIR_DEBUG("Setting child to drop privileges to %u:%u", (unsigned int)user, (unsigned int)group); @@ -2581,4 +2599,6 @@ virSecurityDriver virSecurityDriverDAC = { .domainSetSecurityChardevLabel = virSecurityDACSetChardevLabel, .domainRestoreSecurityChardevLabel = virSecurityDACRestoreChardevLabel, + + .domainSetSecurityVirtioFSProcessLabel = virSecurityDACSetVirtioFSProcessLabel, }; diff --git a/src/security/security_driver.h b/src/security/security_driver.h index 3353955813..d145922198 100644 --- a/src/security/security_driver.h +++ b/src/security/security_driver.h @@ -217,6 +217,8 @@ struct _virSecurityDriver { virSecurityDomainSetTPMLabels domainSetSecurityTPMLabels; virSecurityDomainRestoreTPMLabels domainRestoreSecurityTPMLabels; + + virSecurityDomainSetChildProcessLabel domainSetSecurityVirtioFSProcessLabel; }; virSecurityDriverPtr virSecurityDriverLookup(const char *name, diff --git a/src/security/security_manager.c b/src/security/security_manager.c index fe9def7fb9..13e6380ed6 100644 --- a/src/security/security_manager.c +++ b/src/security/security_manager.c @@ -945,6 +945,18 @@ virSecurityManagerSetChildProcessLabel(virSecurityManagerPtr mgr, } +int virSecurityManagerSetVirtioFSProcessLabel(virSecurityManagerPtr mgr, + virDomainDefPtr def, + virCommandPtr cmd) +{ + if (mgr->drv->domainSetSecurityVirtioFSProcessLabel) + return mgr->drv->domainSetSecurityVirtioFSProcessLabel(mgr, def, cmd); + + virReportUnsupportedError(); + return -1; +} + + int virSecurityManagerVerify(virSecurityManagerPtr mgr, virDomainDefPtr def) diff --git a/src/security/security_manager.h b/src/security/security_manager.h index f835356b7e..0465f99203 100644 --- a/src/security/security_manager.h +++ b/src/security/security_manager.h @@ -137,6 +137,10 @@ int virSecurityManagerSetProcessLabel(virSecurityManagerPtr mgr, int virSecurityManagerSetChildProcessLabel(virSecurityManagerPtr mgr, virDomainDefPtr def, virCommandPtr cmd); +int virSecurityManagerSetVirtioFSProcessLabel(virSecurityManagerPtr mgr, + virDomainDefPtr def, + virCommandPtr cmd); + int virSecurityManagerVerify(virSecurityManagerPtr mgr, virDomainDefPtr def); int virSecurityManagerSetImageFDLabel(virSecurityManagerPtr mgr, diff --git a/src/security/security_nop.c b/src/security/security_nop.c index c1856eb421..f783bfa7ee 100644 --- a/src/security/security_nop.c +++ b/src/security/security_nop.c @@ -328,4 +328,5 @@ virSecurityDriver virSecurityDriverNop = { .domainSetSecurityChardevLabel = virSecurityDomainSetChardevLabelNop, .domainRestoreSecurityChardevLabel = virSecurityDomainRestoreChardevLabelNop, + .domainSetSecurityVirtioFSProcessLabel = virSecurityDomainSetChildProcessLabelNop, }; diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c index 3f6968a57a..853f5beb67 100644 --- a/src/security/security_selinux.c +++ b/src/security/security_selinux.c @@ -2941,6 +2941,73 @@ virSecuritySELinuxSetChildProcessLabel(virSecurityManagerPtr mgr G_GNUC_UNUSED, return 0; } +static int +virSecuritySELinuxSetVirtioFSProcessLabel(virSecurityManagerPtr mgr G_GNUC_UNUSED, + virDomainDefPtr def, + virCommandPtr cmd) +{ + virSecurityLabelDefPtr secdef; + security_context_t daemon_ctx; + g_auto(GStrv) daemon_label = NULL; + g_auto(GStrv) domain_label = NULL; + g_autofree char *frankenlabel = NULL; + + VIR_ERROR("WE got here"); + + secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME); + if (!secdef || !secdef->label) + return 0; + + if (getcon_raw(&daemon_ctx) == -1) { + virReportSystemError(errno, "%s", + _("unable to get security context")); + return -1; + } + + VIR_ERROR("domain_label=%s daemon_label=%s", secdef->label, (char *)daemon_ctx); + + daemon_label = g_strsplit((char *)daemon_ctx, ":", 6); + domain_label = g_strsplit((char *)secdef->label, ":", 6); + + freecon(daemon_ctx); + + if (STRNEQ(SECURITY_SELINUX_NAME, secdef->model)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("security label driver mismatch: " + "'%s' model configured for domain, but " + "hypervisor driver is '%s'."), + secdef->model, SECURITY_SELINUX_NAME); + if (security_getenforce() == 1) + return -1; + } + + if (!domain_label || !daemon_label || + g_strv_length(domain_label) != 5 || g_strv_length(daemon_label) != 5) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("malformed security label")); + return -1; + } + + frankenlabel = g_strdup_printf("%s:%s:%s:%s:%s", + daemon_label[0], + daemon_label[1], + daemon_label[2], + domain_label[3], + domain_label[4]); + + VIR_ERROR("frankenlabel=%s", frankenlabel); + + if (strlen(frankenlabel) >= VIR_SECURITY_LABEL_BUFLEN) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("security label exceeds maximum length: %d"), + VIR_SECURITY_LABEL_BUFLEN - 1); + return -1; + } + + virCommandSetSELinuxLabel(cmd, frankenlabel); + return 0; +} + static int virSecuritySELinuxSetDaemonSocketLabel(virSecurityManagerPtr mgr G_GNUC_UNUSED, virDomainDefPtr def) @@ -3576,4 +3643,6 @@ virSecurityDriver virSecurityDriverSELinux = { .domainSetSecurityTPMLabels = virSecuritySELinuxSetTPMLabels, .domainRestoreSecurityTPMLabels = virSecuritySELinuxRestoreTPMLabels, + + .domainSetSecurityVirtioFSProcessLabel = virSecuritySELinuxSetVirtioFSProcessLabel, }; diff --git a/src/security/security_stack.c b/src/security/security_stack.c index 073876daff..28982b4ba1 100644 --- a/src/security/security_stack.c +++ b/src/security/security_stack.c @@ -476,6 +476,23 @@ virSecurityStackSetChildProcessLabel(virSecurityManagerPtr mgr, return rc; } +static int +virSecurityStackSetVirtioFSProcessLabel(virSecurityManagerPtr mgr, + virDomainDefPtr vm, + virCommandPtr cmd) +{ + virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr); + virSecurityStackItemPtr item = priv->itemsHead; + int rc = 0; + + for (; item; item = item->next) { + if (virSecurityManagerSetVirtioFSProcessLabel(item->securityManager, vm, cmd) < 0) + rc = -1; + } + + return rc; +} + static int virSecurityStackGetProcessLabel(virSecurityManagerPtr mgr, virDomainDefPtr vm, @@ -991,4 +1008,6 @@ virSecurityDriver virSecurityDriverStack = { .domainSetSecurityTPMLabels = virSecurityStackSetTPMLabels, .domainRestoreSecurityTPMLabels = virSecurityStackRestoreTPMLabels, + + .domainSetSecurityVirtioFSProcessLabel = virSecurityStackSetVirtioFSProcessLabel, }; -- 2.24.1