util: add security label setting to virCommand

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.
This commit is contained in:
Laine Stump 2013-02-01 14:32:37 -05:00
parent 4a56e80fa5
commit 6c3f3d0d89
4 changed files with 105 additions and 1 deletions

View File

@ -765,7 +765,8 @@ libvirt_util_la_CFLAGS = $(CAPNG_CFLAGS) $(YAJL_CFLAGS) $(LIBNL_CFLAGS) \
$(DBUS_CFLAGS) $(LDEXP_LIBM) $(DBUS_CFLAGS) $(LDEXP_LIBM)
libvirt_util_la_LIBADD = $(CAPNG_LIBS) $(YAJL_LIBS) $(LIBNL_LIBS) \ libvirt_util_la_LIBADD = $(CAPNG_LIBS) $(YAJL_LIBS) $(LIBNL_LIBS) \
$(THREAD_LIBS) $(AUDIT_LIBS) $(DEVMAPPER_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 noinst_LTLIBRARIES += libvirt_conf.la

View File

@ -156,6 +156,7 @@ virCommandPreserveFD;
virCommandRequireHandshake; virCommandRequireHandshake;
virCommandRun; virCommandRun;
virCommandRunAsync; virCommandRunAsync;
virCommandSetAppArmorProfile;
virCommandSetErrorBuffer; virCommandSetErrorBuffer;
virCommandSetErrorFD; virCommandSetErrorFD;
virCommandSetGID; virCommandSetGID;
@ -165,6 +166,7 @@ virCommandSetOutputBuffer;
virCommandSetOutputFD; virCommandSetOutputFD;
virCommandSetPidFile; virCommandSetPidFile;
virCommandSetPreExecHook; virCommandSetPreExecHook;
virCommandSetSELinuxLabel;
virCommandSetUID; virCommandSetUID;
virCommandSetWorkingDirectory; virCommandSetWorkingDirectory;
virCommandToString; virCommandToString;

View File

@ -33,6 +33,13 @@
# include <cap-ng.h> # include <cap-ng.h>
#endif #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 "vircommand.h"
#include "viralloc.h" #include "viralloc.h"
#include "virerror.h" #include "virerror.h"
@ -103,6 +110,12 @@ struct _virCommand {
uid_t uid; uid_t uid;
gid_t gid; gid_t gid;
unsigned long long capabilities; 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); static int virCommandHandshakeChild(virCommandPtr cmd);
@ -606,6 +619,32 @@ virExec(virCommandPtr cmd)
goto fork_error; 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) { if (cmd->uid != (uid_t)-1 || cmd->gid != (gid_t)-1) {
VIR_DEBUG("Setting child uid:gid to %d:%d", VIR_DEBUG("Setting child uid:gid to %d:%d",
(int)cmd->uid, (int)cmd->gid); (int)cmd->uid, (int)cmd->gid);
@ -965,6 +1004,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: * virCommandDaemonize:
@ -2525,6 +2614,12 @@ virCommandFree(virCommandPtr cmd)
VIR_FREE(cmd->transfer); VIR_FREE(cmd->transfer);
VIR_FREE(cmd->preserve); 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); VIR_FREE(cmd);
} }

View File

@ -70,6 +70,12 @@ void virCommandClearCaps(virCommandPtr cmd);
void virCommandAllowCap(virCommandPtr cmd, void virCommandAllowCap(virCommandPtr cmd,
int capability); int capability);
void virCommandSetSELinuxLabel(virCommandPtr cmd,
const char *label);
void virCommandSetAppArmorProfile(virCommandPtr cmd,
const char *profile);
void virCommandDaemonize(virCommandPtr cmd); void virCommandDaemonize(virCommandPtr cmd);
void virCommandNonblockingFDs(virCommandPtr cmd); void virCommandNonblockingFDs(virCommandPtr cmd);