[libvirt] [PATCH 5/6] security_selinux: Implement transaction APIs

Michal Privoznik mprivozn at redhat.com
Mon Dec 19 15:57:54 UTC 2016


Signed-off-by: Michal Privoznik <mprivozn at redhat.com>
---
 src/security/security_selinux.c | 193 +++++++++++++++++++++++++++++++++++++++-
 1 file changed, 190 insertions(+), 3 deletions(-)

diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c
index fec19b98c..af226bff6 100644
--- a/src/security/security_selinux.c
+++ b/src/security/security_selinux.c
@@ -78,6 +78,22 @@ struct _virSecuritySELinuxCallbackData {
     virDomainDefPtr def;
 };
 
+typedef struct _virSecuritySELinuxContextItem virSecuritySELinuxContextItem;
+typedef virSecuritySELinuxContextItem *virSecuritySELinuxContextItemPtr;
+struct _virSecuritySELinuxContextItem {
+    const char *path;
+    const char *tcon;
+    bool optional;
+};
+
+typedef struct _virSecuritySELinuxContextList virSecuritySELinuxContextList;
+typedef virSecuritySELinuxContextList *virSecuritySELinuxContextListPtr;
+struct _virSecuritySELinuxContextList {
+    bool privileged;
+    virSecuritySELinuxContextItemPtr *items;
+    size_t nItems;
+};
+
 #define SECURITY_SELINUX_VOID_DOI       "0"
 #define SECURITY_SELINUX_NAME "selinux"
 
@@ -87,6 +103,94 @@ virSecuritySELinuxRestoreTPMFileLabelInt(virSecurityManagerPtr mgr,
                                          virDomainTPMDefPtr tpm);
 
 
+virThreadLocal contextList;
+
+static int
+virSecuritySELinuxContextListAppend(virSecuritySELinuxContextListPtr list,
+                                    const char *path,
+                                    const char *tcon,
+                                    bool optional)
+{
+    virSecuritySELinuxContextItemPtr item;
+
+    if (VIR_ALLOC(item) < 0)
+        return -1;
+
+    item->path = path;
+    item->tcon = tcon;
+    item->optional = optional;
+
+    if (VIR_APPEND_ELEMENT(list->items, list->nItems, item) < 0) {
+        VIR_FREE(item);
+        return -1;
+    }
+
+    return 0;
+}
+
+static void
+virSecuritySELinuxContextListFree(void *opaque)
+{
+    virSecuritySELinuxContextListPtr list = opaque;
+    size_t i;
+
+    if (!list)
+        return;
+
+    for (i = 0; i < list->nItems; i++)
+        VIR_FREE(list->items[i]);
+    VIR_FREE(list);
+}
+
+
+static int
+virSecuritySELinuxTransactionAppend(const char *path,
+                                    const char *tcon,
+                                    bool optional)
+{
+    virSecuritySELinuxContextListPtr list;
+    int ret = -1;
+
+    list = virThreadLocalGet(&contextList);
+    if (!list)
+        return 0;
+
+    if (virSecuritySELinuxContextListAppend(list, path, tcon, optional) < 0)
+        goto cleanup;
+
+    ret = 0;
+ cleanup:
+    return ret;
+}
+
+
+static int virSecuritySELinuxSetFileconHelper(const char *path,
+                                              const char *tcon,
+                                              bool optional,
+                                              bool privileged);
+
+static int
+virSecuritySELinuxTransactionRun(pid_t pid ATTRIBUTE_UNUSED,
+                                 void *opaque)
+{
+    virSecuritySELinuxContextListPtr list = opaque;
+    size_t i;
+
+    ignore_value(virThreadLocalSet(&contextList, NULL));
+    for (i = 0; i < list->nItems; i++) {
+        virSecuritySELinuxContextItemPtr item = list->items[i];
+
+        if (virSecuritySELinuxSetFileconHelper(item->path,
+                                               item->tcon,
+                                               item->optional,
+                                               list->privileged) < 0)
+            return -1;
+    }
+
+    return 0;
+}
+
+
 /*
  * Returns 0 on success, 1 if already reserved, or -1 on fatal error
  */
@@ -560,6 +664,14 @@ static int
 virSecuritySELinuxInitialize(virSecurityManagerPtr mgr)
 {
     VIR_DEBUG("SELinuxInitialize %s", virSecurityManagerGetDriver(mgr));
+
+    if (virThreadLocalInit(&contextList,
+                           virSecuritySELinuxContextListFree) < 0) {
+        virReportSystemError(errno, "%s",
+                             _("Unable to initialize thread local variable"));
+        return -1;
+    }
+
     if (STREQ(virSecurityManagerGetDriver(mgr),  "LXC")) {
         return virSecuritySELinuxLXCInitialize(mgr);
     } else {
@@ -843,6 +955,68 @@ virSecuritySELinuxGetDOI(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED)
     return SECURITY_SELINUX_VOID_DOI;
 }
 
+static int
+virSecuritySELinuxTransactionStart(virSecurityManagerPtr mgr)
+{
+    bool privileged = virSecurityManagerGetPrivileged(mgr);
+    virSecuritySELinuxContextListPtr list;
+
+    list = virThreadLocalGet(&contextList);
+    if (list) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("Another relabel transaction is already started"));
+        return -1;
+    }
+
+    if (VIR_ALLOC(list) < 0)
+        return -1;
+
+    list->privileged = privileged;
+
+    if (virThreadLocalSet(&contextList, list) < 0) {
+        virReportSystemError(errno, "%s",
+                             _("Unable to set thread local variable"));
+        VIR_FREE(list);
+        return -1;
+    }
+
+    return 0;
+}
+
+static int
+virSecuritySELinuxTransactionCommit(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
+                                    pid_t pid)
+{
+    virSecuritySELinuxContextListPtr list;
+    int ret = 0;
+
+    list = virThreadLocalGet(&contextList);
+    if (!list)
+        return 0;
+
+    if (virProcessRunInMountNamespace(pid,
+                                      virSecuritySELinuxTransactionRun,
+                                      list) < 0)
+        ret = -1;
+
+    ignore_value(virThreadLocalSet(&contextList, NULL));
+    virSecuritySELinuxContextListFree(list);
+    return ret;
+}
+
+static void
+virSecuritySELinuxTransactionAbort(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED)
+{
+    virSecuritySELinuxContextListPtr list;
+
+    list = virThreadLocalGet(&contextList);
+    if (!list)
+        return;
+
+    ignore_value(virThreadLocalSet(&contextList, NULL));
+    virSecuritySELinuxContextListFree(list);
+}
+
 static int
 virSecuritySELinuxGetProcessLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
                                   virDomainDefPtr def ATTRIBUTE_UNUSED,
@@ -885,10 +1059,19 @@ virSecuritySELinuxGetProcessLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
  * return 1 if labelling was not possible.  Otherwise, require a label
  * change, and return 0 for success, -1 for failure.  */
 static int
-virSecuritySELinuxSetFileconHelper(const char *path, char *tcon,
+virSecuritySELinuxSetFileconHelper(const char *path, const char *tcon,
                                    bool optional, bool privileged)
 {
     security_context_t econ;
+    int rc;
+
+    /* Be aware that this function might run in a separate process.
+     * Therefore, any driver state changes would be thrown away. */
+
+    if ((rc = virSecuritySELinuxTransactionAppend(path, tcon, optional)) < 0)
+        return -1;
+    else if (rc > 0)
+        return 0;
 
     VIR_INFO("Setting SELinux context on '%s' to '%s'", path, tcon);
 
@@ -945,7 +1128,7 @@ virSecuritySELinuxSetFileconHelper(const char *path, char *tcon,
 
 static int
 virSecuritySELinuxSetFileconOptional(virSecurityManagerPtr mgr,
-                                     const char *path, char *tcon)
+                                     const char *path, const char *tcon)
 {
     bool privileged = virSecurityManagerGetPrivileged(mgr);
     return virSecuritySELinuxSetFileconHelper(path, tcon, true, privileged);
@@ -953,7 +1136,7 @@ virSecuritySELinuxSetFileconOptional(virSecurityManagerPtr mgr,
 
 static int
 virSecuritySELinuxSetFilecon(virSecurityManagerPtr mgr,
-                             const char *path, char *tcon)
+                             const char *path, const char *tcon)
 {
     bool privileged = virSecurityManagerGetPrivileged(mgr);
     return virSecuritySELinuxSetFileconHelper(path, tcon, false, privileged);
@@ -2667,6 +2850,10 @@ virSecurityDriver virSecurityDriverSELinux = {
     .getModel                           = virSecuritySELinuxGetModel,
     .getDOI                             = virSecuritySELinuxGetDOI,
 
+    .transactionStart                   = virSecuritySELinuxTransactionStart,
+    .transactionCommit                  = virSecuritySELinuxTransactionCommit,
+    .transactionAbort                   = virSecuritySELinuxTransactionAbort,
+
     .domainSecurityVerify               = virSecuritySELinuxVerify,
 
     .domainSetSecurityDiskLabel         = virSecuritySELinuxSetDiskLabel,
-- 
2.11.0




More information about the libvir-list mailing list