diff --git a/src/qemu/qemu_dbus.c b/src/qemu/qemu_dbus.c index a6dc802637..2e4067e704 100644 --- a/src/qemu/qemu_dbus.c +++ b/src/qemu/qemu_dbus.c @@ -217,7 +217,7 @@ qemuDBusStart(virQEMUDriver *driver, virCommandDaemonize(cmd); virCommandAddArgFormat(cmd, "--config-file=%s", configfile); - if (qemuSecurityCommandRun(driver, vm, cmd, -1, -1, NULL) < 0) + if (qemuSecurityCommandRun(driver, vm, cmd, -1, -1, false, NULL) < 0) goto cleanup; if (virPidFileReadPath(pidfile, &cpid) < 0) { diff --git a/src/qemu/qemu_passt.c b/src/qemu/qemu_passt.c index 0afa8bdb3a..fd0076077e 100644 --- a/src/qemu/qemu_passt.c +++ b/src/qemu/qemu_passt.c @@ -281,7 +281,7 @@ qemuPasstStart(virDomainObj *vm, if (qemuExtDeviceLogCommand(driver, vm, cmd, "passt") < 0) return -1; - if (qemuSecurityCommandRun(driver, vm, cmd, -1, -1, NULL) < 0) + if (qemuSecurityCommandRun(driver, vm, cmd, -1, -1, false, NULL) < 0) goto error; return 0; diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index deebd03717..be418ad8e6 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -7747,7 +7747,7 @@ qemuProcessLaunch(virConnectPtr conn, VIR_DEBUG("Setting up security labelling"); if (qemuSecuritySetChildProcessLabel(driver->securityManager, - vm->def, cmd) < 0) + vm->def, false, cmd) < 0) goto cleanup; virCommandSetOutputFD(cmd, &logfile); diff --git a/src/qemu/qemu_security.c b/src/qemu/qemu_security.c index ee03e2225e..8bcef14d08 100644 --- a/src/qemu/qemu_security.c +++ b/src/qemu/qemu_security.c @@ -636,6 +636,7 @@ qemuSecurityCommandRun(virQEMUDriver *driver, virCommand *cmd, uid_t uid, gid_t gid, + bool useBinarySpecificLabel, int *exitstatus) { g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver); @@ -643,8 +644,10 @@ qemuSecurityCommandRun(virQEMUDriver *driver, int ret = -1; if (virSecurityManagerSetChildProcessLabel(driver->securityManager, - vm->def, cmd) < 0) + vm->def, useBinarySpecificLabel, + cmd) < 0) { return -1; + } if (uid != (uid_t) -1) virCommandSetUID(cmd, uid); diff --git a/src/qemu/qemu_security.h b/src/qemu/qemu_security.h index dc8e67cc81..10f11771b4 100644 --- a/src/qemu/qemu_security.h +++ b/src/qemu/qemu_security.h @@ -115,6 +115,7 @@ int qemuSecurityCommandRun(virQEMUDriver *driver, virCommand *cmd, uid_t uid, gid_t gid, + bool useBinarySpecificLabel, int *exitstatus); /* Please note that for these APIs there is no wrapper yet. Do NOT blindly add diff --git a/src/qemu/qemu_slirp.c b/src/qemu/qemu_slirp.c index 9697542cd3..fdf0823d03 100644 --- a/src/qemu/qemu_slirp.c +++ b/src/qemu/qemu_slirp.c @@ -325,7 +325,7 @@ qemuSlirpStart(virDomainObj *vm, if (qemuExtDeviceLogCommand(driver, vm, cmd, "slirp") < 0) goto error; - if (qemuSecurityCommandRun(driver, vm, cmd, -1, -1, NULL) < 0) + if (qemuSecurityCommandRun(driver, vm, cmd, -1, -1, false, NULL) < 0) goto error; rc = virPidFileReadPath(pidfile, &pid); diff --git a/src/qemu/qemu_tpm.c b/src/qemu/qemu_tpm.c index f4344de663..788e81a655 100644 --- a/src/qemu/qemu_tpm.c +++ b/src/qemu/qemu_tpm.c @@ -963,8 +963,9 @@ qemuTPMEmulatorStart(virQEMUDriver *driver, return -1; if (qemuSecurityCommandRun(driver, vm, cmd, cfg->swtpm_user, - cfg->swtpm_group, NULL) < 0) + cfg->swtpm_group, false, NULL) < 0) { goto error; + } if (virPidFileReadPath(pidfile, &pid) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", diff --git a/src/qemu/qemu_vhost_user_gpu.c b/src/qemu/qemu_vhost_user_gpu.c index 5b49ef4e28..ced41b0466 100644 --- a/src/qemu/qemu_vhost_user_gpu.c +++ b/src/qemu/qemu_vhost_user_gpu.c @@ -152,7 +152,7 @@ int qemuExtVhostUserGPUStart(virQEMUDriver *driver, virCommandAddArgFormat(cmd, "--render-node=%s", video->accel->rendernode); } - if (qemuSecurityCommandRun(driver, vm, cmd, -1, -1, NULL) < 0) + if (qemuSecurityCommandRun(driver, vm, cmd, -1, -1, false, NULL) < 0) goto error; rc = virPidFileReadPath(pidfile, &pid); diff --git a/src/security/security_apparmor.c b/src/security/security_apparmor.c index b63b248975..b5642c9a28 100644 --- a/src/security/security_apparmor.c +++ b/src/security/security_apparmor.c @@ -570,6 +570,7 @@ AppArmorSetSecurityProcessLabel(virSecurityManager *mgr G_GNUC_UNUSED, static int AppArmorSetSecurityChildProcessLabel(virSecurityManager *mgr G_GNUC_UNUSED, virDomainDef *def, + bool useBinarySpecificLabel G_GNUC_UNUSED, virCommand *cmd) { g_autofree char *profile_name = NULL; diff --git a/src/security/security_dac.c b/src/security/security_dac.c index 9be8f458d1..ca3f4d2dc5 100644 --- a/src/security/security_dac.c +++ b/src/security/security_dac.c @@ -2273,6 +2273,7 @@ virSecurityDACSetProcessLabel(virSecurityManager *mgr, static int virSecurityDACSetChildProcessLabel(virSecurityManager *mgr, virDomainDef *def, + bool useBinarySpecificLabel G_GNUC_UNUSED, virCommand *cmd) { virSecurityDACData *priv = virSecurityManagerGetPrivateData(mgr); diff --git a/src/security/security_driver.h b/src/security/security_driver.h index fe6982ceca..aa1fb2125d 100644 --- a/src/security/security_driver.h +++ b/src/security/security_driver.h @@ -96,6 +96,7 @@ typedef int (*virSecurityDomainSetProcessLabel) (virSecurityManager *mgr, virDomainDef *def); typedef int (*virSecurityDomainSetChildProcessLabel) (virSecurityManager *mgr, virDomainDef *def, + bool useBinarySpecificLabel, virCommand *cmd); typedef int (*virSecurityDomainSecurityVerify) (virSecurityManager *mgr, virDomainDef *def); diff --git a/src/security/security_manager.c b/src/security/security_manager.c index 2f8e89cb04..b0578d7209 100644 --- a/src/security/security_manager.c +++ b/src/security/security_manager.c @@ -885,10 +885,14 @@ virSecurityManagerSetProcessLabel(virSecurityManager *mgr, int virSecurityManagerSetChildProcessLabel(virSecurityManager *mgr, virDomainDef *vm, + bool useBinarySpecificLabel, virCommand *cmd) { - if (mgr->drv->domainSetSecurityChildProcessLabel) - return mgr->drv->domainSetSecurityChildProcessLabel(mgr, vm, cmd); + if (mgr->drv->domainSetSecurityChildProcessLabel) { + return mgr->drv->domainSetSecurityChildProcessLabel(mgr, vm, + useBinarySpecificLabel, + cmd); + } virReportUnsupportedError(); return -1; diff --git a/src/security/security_manager.h b/src/security/security_manager.h index 4afdcc167b..97add3294d 100644 --- a/src/security/security_manager.h +++ b/src/security/security_manager.h @@ -145,6 +145,7 @@ int virSecurityManagerSetProcessLabel(virSecurityManager *mgr, virDomainDef *def); int virSecurityManagerSetChildProcessLabel(virSecurityManager *mgr, virDomainDef *def, + bool useBinarySpecificLabel, virCommand *cmd); int virSecurityManagerVerify(virSecurityManager *mgr, virDomainDef *def); diff --git a/src/security/security_nop.c b/src/security/security_nop.c index 0dbc547feb..1413f43d57 100644 --- a/src/security/security_nop.c +++ b/src/security/security_nop.c @@ -152,6 +152,7 @@ virSecurityDomainSetProcessLabelNop(virSecurityManager *mgr G_GNUC_UNUSED, static int virSecurityDomainSetChildProcessLabelNop(virSecurityManager *mgr G_GNUC_UNUSED, virDomainDef *vm G_GNUC_UNUSED, + bool useBinarySpecificLabel G_GNUC_UNUSED, virCommand *cmd G_GNUC_UNUSED) { return 0; diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c index cd1d9d14f7..7f409af525 100644 --- a/src/security/security_selinux.c +++ b/src/security/security_selinux.c @@ -560,6 +560,52 @@ virSecuritySELinuxContextAddRange(const char *src, return ret; } + +static char * +virSecuritySELinuxContextSetFromFile(const char *origLabel, + const char *binaryPath) +{ + g_autofree char *currentCon = NULL; + g_autofree char *binaryCon = NULL; + g_autofree char *naturalLabel = NULL; + g_autofree char *updatedLabel = NULL; + + /* First learn what would be the context set + * if binaryPath was exec'ed from this process. + */ + if (getcon(¤tCon) < 0) { + virReportSystemError(errno, "%s", + _("unable to get SELinux context for current process")); + return NULL; + } + + if (getfilecon(binaryPath, &binaryCon) < 0) { + virReportSystemError(errno, _("unable to get SELinux context for '%s'"), + binaryPath); + return NULL; + } + + if (security_compute_create(currentCon, binaryCon, + string_to_security_class("process"), + &naturalLabel) < 0) { + virReportSystemError(errno, + _("unable create new SELinux label based on label '%s' and file '%s'"), + origLabel, binaryPath); + return NULL; + } + + /* now get the type from the original label + * (which already has proper MCS set) and add it to + * the new label + */ + updatedLabel = virSecuritySELinuxContextAddRange(origLabel, naturalLabel); + + VIR_DEBUG("original label: '%s' binary: '%s' binary-specific label: '%s'", + origLabel, binaryPath, NULLSTR(updatedLabel)); + return g_steal_pointer(&updatedLabel); +} + + static char * virSecuritySELinuxGenNewContext(const char *basecontext, const char *mcs, @@ -2986,10 +3032,13 @@ virSecuritySELinuxSetProcessLabel(virSecurityManager *mgr G_GNUC_UNUSED, static int virSecuritySELinuxSetChildProcessLabel(virSecurityManager *mgr G_GNUC_UNUSED, virDomainDef *def, + bool useBinarySpecificLabel G_GNUC_UNUSED, virCommand *cmd) { /* TODO: verify DOI */ virSecurityLabelDef *secdef; + g_autofree char *tmpLabel = NULL; + const char *label = NULL; secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME); if (!secdef || !secdef->label) @@ -3006,8 +3055,30 @@ virSecuritySELinuxSetChildProcessLabel(virSecurityManager *mgr G_GNUC_UNUSED, return -1; } + /* pick either the common label used by most binaries exec'ed by + * libvirt, or the specific label of this binary. + */ + if (useBinarySpecificLabel) { + const char *binaryPath = virCommandGetBinaryPath(cmd); + + if (!binaryPath) + return -1; /* error was already logged */ + + tmpLabel = virSecuritySELinuxContextSetFromFile(secdef->label, + binaryPath); + if (!tmpLabel) + return -1; + + label = tmpLabel; + + } else { + + label = secdef->label; + + } + /* save in cmd to be set after fork/before child process is exec'ed */ - virCommandSetSELinuxLabel(cmd, secdef->label); + virCommandSetSELinuxLabel(cmd, label); return 0; } diff --git a/src/security/security_stack.c b/src/security/security_stack.c index 560f797030..369b5dd3a6 100644 --- a/src/security/security_stack.c +++ b/src/security/security_stack.c @@ -458,6 +458,7 @@ virSecurityStackSetProcessLabel(virSecurityManager *mgr, static int virSecurityStackSetChildProcessLabel(virSecurityManager *mgr, virDomainDef *vm, + bool useBinarySpecificLabel, virCommand *cmd) { virSecurityStackData *priv = virSecurityManagerGetPrivateData(mgr); @@ -465,8 +466,10 @@ virSecurityStackSetChildProcessLabel(virSecurityManager *mgr, int rc = 0; for (; item; item = item->next) { - if (virSecurityManagerSetChildProcessLabel(item->securityManager, vm, cmd) < 0) + if (virSecurityManagerSetChildProcessLabel(item->securityManager, vm, + useBinarySpecificLabel, cmd) < 0) { rc = -1; + } } return rc;