[libvirt] [PATCH 09/15] util: add security label setting to virCommand

Laine Stump laine at laine.org
Thu Feb 7 21:37:50 UTC 2013


virCommand gets the new API virCommandSetSecLabel(), which saves a
copy of a null-terminated string in the virCommand. During
virCommandRun, if the seclabel is non-NULL and we've been compiled
with a security driver, the appropriate security library function is
called to set the label for the child process. 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.
---
 src/Makefile.am          |  3 ++-
 src/libvirt_private.syms |  1 +
 src/util/vircommand.c    | 55 ++++++++++++++++++++++++++++++++++++++++++++++++
 src/util/vircommand.h    |  3 +++
 4 files changed, 61 insertions(+), 1 deletion(-)

diff --git a/src/Makefile.am b/src/Makefile.am
index 2e68e96..41cef96 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -763,7 +763,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 83d83ad..4ac2d52 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -166,6 +166,7 @@ virCommandSetOutputBuffer;
 virCommandSetOutputFD;
 virCommandSetPidFile;
 virCommandSetPreExecHook;
+virCommandSetSecLabel;
 virCommandSetUID;
 virCommandSetWorkingDirectory;
 virCommandToString;
diff --git a/src/util/vircommand.c b/src/util/vircommand.c
index 65838d1..3eb8465 100644
--- a/src/util/vircommand.c
+++ b/src/util/vircommand.c
@@ -33,6 +33,12 @@
 # include <cap-ng.h>
 #endif
 
+#if defined(WITH_SECDRIVER_SELINUX)
+# include <selinux/selinux.h>
+#elif defined(WITH_SECDRIVER_APPARMOR)
+# include <sys/apparmor.h>
+#endif
+
 #include "vircommand.h"
 #include "viralloc.h"
 #include "virerror.h"
@@ -104,6 +110,7 @@ struct _virCommand {
     uid_t uid;
     gid_t gid;
     unsigned long long capabilities;
+    char *seclabel;
 };
 
 static int virCommandHandshakeChild(virCommandPtr cmd);
@@ -607,6 +614,29 @@ virExec(virCommandPtr cmd)
            goto fork_error;
     }
 
+    if (cmd->seclabel) {
+        VIR_DEBUG("Setting child security label to %s", cmd->seclabel);
+# if defined(WITH_SECDRIVER_SELINUX)
+        if (setexeccon_raw(cmd->seclabel) == -1) {
+            virReportSystemError(errno,
+                                 _("unable to set security context '%s' "
+                                   "for '%s'"),
+                                 cmd->seclabel, cmd->args[0]);
+            if (security_getenforce() == 1)
+                goto fork_error;
+        }
+# elif defined(WITH_SECDRIVER_APPARMOR)
+        if (aa_change_profile(cmd->seclabel) < 0) {
+            virReportSystemError(errno,
+                                 _("unable to set AppArmor profile '%s' "
+                                   "for '%s'"),
+                                 cmd->seclabel, cmd->args[0]);
+            goto fork_error;
+        }
+# endif
+
+    }
+
     if (cmd->uid > 0 || cmd->gid > 0) {
         VIR_DEBUG("Setting child uid:gid to %u:%u", cmd->uid, cmd->gid);
         if (virSetUIDGID(cmd->uid, cmd->gid) < 0)
@@ -964,6 +994,30 @@ virCommandAllowCap(virCommandPtr cmd,
 }
 
 
+/**
+ * virCommandSetSecLabel:
+ * @cmd: the command to modify
+ * @label: the label to use
+ *
+ * Saves a copy of @label to use when calling the appropriate security
+ * driver after the child process has been started. In the case of
+ * SELinux, this label will be sent to setexeccon_raw(), and in the
+ * case of AppArmor, it will be sent to aa_change_profile(). If
+ * neither of these is configured into libvirt, or if label is NULL,
+ * nothing will be done.
+ */
+void
+virCommandSetSecLabel(virCommandPtr cmd, const char *label)
+{
+    if (!cmd || cmd->has_error)
+        return;
+
+    VIR_FREE(cmd->seclabel);
+    if (label && !(cmd->seclabel = strdup(label)))
+        cmd->has_error = ENOMEM;
+    return;
+}
+
 
 /**
  * virCommandDaemonize:
@@ -2712,6 +2766,7 @@ virCommandFree(virCommandPtr cmd)
 
     VIR_FREE(cmd->transfer);
     VIR_FREE(cmd->preserve);
+    VIR_FREE(cmd->seclabel);
 
     VIR_FREE(cmd);
 }
diff --git a/src/util/vircommand.h b/src/util/vircommand.h
index ac940f0..6d76d42 100644
--- a/src/util/vircommand.h
+++ b/src/util/vircommand.h
@@ -70,6 +70,9 @@ void virCommandClearCaps(virCommandPtr cmd);
 void virCommandAllowCap(virCommandPtr cmd,
                         int capability);
 
+void virCommandSetSecLabel(virCommandPtr cmd,
+                           const char *label);
+
 void virCommandDaemonize(virCommandPtr cmd);
 
 void virCommandNonblockingFDs(virCommandPtr cmd);
-- 
1.8.1




More information about the libvir-list mailing list