virCommand gets two new APIs: virCommandSetSELinuxLabel() and virCommandSetAppArmorProfile(), which both save a copy of a null-terminated string in the virCommand. During virCommandRun, if the string is non-NULL and we've been compiled with AppArmor and/or SELinux security driver support, the appropriate security library function is called for the child process, using the string that was previously set. In the case of SELinux, setexeccon_raw() is called, and for AppArmor, aa_change_profile() is called. This functionality has been added so that users of virCommand can use the upcoming virSecurityManagerSetChildProcessLabel() prior to running a child process, rather than needing to setup a hook function to be called (and in turn call virSecurityManagerSetProcessLabel()) *during* the setup of the child process. --- Change from V1: * V1 had a single API that did double duty for both SELinux and AppArmor (because I didn't realize both could be built in simultaneously). V1 treats each separately, with two different APIs. src/Makefile.am | 3 +- src/libvirt_private.syms | 2 + src/util/vircommand.c | 95 ++++++++++++++++++++++++++++++++++++++++++++++++ src/util/vircommand.h | 6 +++ 4 files changed, 105 insertions(+), 1 deletion(-) diff --git a/src/Makefile.am b/src/Makefile.am index 12319e0..0d2f2f8 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -765,7 +765,8 @@ libvirt_util_la_CFLAGS = $(CAPNG_CFLAGS) $(YAJL_CFLAGS) $(LIBNL_CFLAGS) \ $(DBUS_CFLAGS) $(LDEXP_LIBM) libvirt_util_la_LIBADD = $(CAPNG_LIBS) $(YAJL_LIBS) $(LIBNL_LIBS) \ $(THREAD_LIBS) $(AUDIT_LIBS) $(DEVMAPPER_LIBS) \ - $(LIB_CLOCK_GETTIME) $(DBUS_LIBS) $(MSCOM_LIBS) $(LIBXML_LIBS) + $(LIB_CLOCK_GETTIME) $(DBUS_LIBS) $(MSCOM_LIBS) $(LIBXML_LIBS) \ + $(SECDRIVER_LIBS) noinst_LTLIBRARIES += libvirt_conf.la diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 511a686..8241e6f 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -156,6 +156,7 @@ virCommandPreserveFD; virCommandRequireHandshake; virCommandRun; virCommandRunAsync; +virCommandSetAppArmorProfile; virCommandSetErrorBuffer; virCommandSetErrorFD; virCommandSetGID; @@ -165,6 +166,7 @@ virCommandSetOutputBuffer; virCommandSetOutputFD; virCommandSetPidFile; virCommandSetPreExecHook; +virCommandSetSELinuxLabel; virCommandSetUID; virCommandSetWorkingDirectory; virCommandToString; diff --git a/src/util/vircommand.c b/src/util/vircommand.c index 84d275f..9727809 100644 --- a/src/util/vircommand.c +++ b/src/util/vircommand.c @@ -33,6 +33,13 @@ # include <cap-ng.h> #endif +#if defined(WITH_SECDRIVER_SELINUX) +# include <selinux/selinux.h> +#endif +#if defined(WITH_SECDRIVER_APPARMOR) +# include <sys/apparmor.h> +#endif + #include "vircommand.h" #include "viralloc.h" #include "virerror.h" @@ -104,6 +111,12 @@ struct _virCommand { uid_t uid; gid_t gid; unsigned long long capabilities; +#if defined(WITH_SECDRIVER_SELINUX) + char *seLinuxLabel; +#endif +#if defined(WITH_SECDRIVER_APPARMOR) + char *appArmorProfile; +#endif }; static int virCommandHandshakeChild(virCommandPtr cmd); @@ -607,6 +620,32 @@ virExec(virCommandPtr cmd) goto fork_error; } +# if defined(WITH_SECDRIVER_SELINUX) + if (cmd->seLinuxLabel) { + VIR_DEBUG("Setting child security label to %s", cmd->seLinuxLabel); + if (setexeccon_raw(cmd->seLinuxLabel) == -1) { + virReportSystemError(errno, + _("unable to set SELinux security context " + "'%s' for '%s'"), + cmd->seLinuxLabel, cmd->args[0]); + if (security_getenforce() == 1) + goto fork_error; + } + } +# endif +# if defined(WITH_SECDRIVER_APPARMOR) + if (cmd->appArmorProfile) { + VIR_DEBUG("Setting child AppArmor profile to %s", cmd->appArmorProfile); + if (aa_change_profile(cmd->appArmorProfile) < 0) { + virReportSystemError(errno, + _("unable to set AppArmor profile '%s' " + "for '%s'"), + cmd->appArmorProfile, cmd->args[0]); + goto fork_error; + } + } +# endif + if (cmd->uid != (uid_t)-1 || cmd->gid != (gid_t)-1) { VIR_DEBUG("Setting child uid:gid to %d:%d", (int)cmd->uid, (int)cmd->gid); @@ -967,6 +1006,56 @@ virCommandAllowCap(virCommandPtr cmd, } +/** + * virCommandSetSELinuxLabel: + * @cmd: the command to modify + * @label: the SELinux label to use for the child process + * + * Saves a copy of @label to use when setting the SELinux context + * label (with setexeccon_raw()) after the child process has been + * started. If SELinux isn't compiled into libvirt, or if label is + * NULL, nothing will be done. + */ +void +virCommandSetSELinuxLabel(virCommandPtr cmd, + const char *label ATTRIBUTE_UNUSED) +{ + if (!cmd || cmd->has_error) + return; + +#if defined(WITH_SECDRIVER_SELINUX) + VIR_FREE(cmd->seLinuxLabel); + if (label && !(cmd->seLinuxLabel = strdup(label))) + cmd->has_error = ENOMEM; +#endif + return; +} + + +/** + * virCommandSetAppArmorProfile: + * @cmd: the command to modify + * @profile: the AppArmor profile to use + * + * Saves a copy of @profile to use when aa_change_profile() after the + * child process has been started. If AppArmor support isn't + * configured into libvirt, or if profile is NULL, nothing will be done. + */ +void +virCommandSetAppArmorProfile(virCommandPtr cmd, + const char *profile ATTRIBUTE_UNUSED) +{ + if (!cmd || cmd->has_error) + return; + +#if defined(WITH_SECDRIVER_APPARMOR) + VIR_FREE(cmd->appArmorProfile); + if (profile && !(cmd->appArmorProfile = strdup(profile))) + cmd->has_error = ENOMEM; +#endif + return; +} + /** * virCommandDaemonize: @@ -2715,6 +2804,12 @@ virCommandFree(virCommandPtr cmd) VIR_FREE(cmd->transfer); VIR_FREE(cmd->preserve); +#if defined(WITH_SECDRIVER_SELINUX) + VIR_FREE(cmd->seLinuxLabel); +#endif +#if defined(WITH_SECDRIVER_APPARMOR) + VIR_FREE(cmd->appArmorProfile); +#endif VIR_FREE(cmd); } diff --git a/src/util/vircommand.h b/src/util/vircommand.h index a4022fa..6c13795 100644 --- a/src/util/vircommand.h +++ b/src/util/vircommand.h @@ -70,6 +70,12 @@ void virCommandClearCaps(virCommandPtr cmd); void virCommandAllowCap(virCommandPtr cmd, int capability); +void virCommandSetSELinuxLabel(virCommandPtr cmd, + const char *label); + +void virCommandSetAppArmorProfile(virCommandPtr cmd, + const char *profile); + void virCommandDaemonize(virCommandPtr cmd); void virCommandNonblockingFDs(virCommandPtr cmd); -- 1.8.1 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list