[libvirt] [PATCH v1 07/10] lock_daemon: Implement seclabel APIs

Michal Privoznik mprivozn at redhat.com
Wed Sep 10 13:26:13 UTC 2014


The most interesting part where all the hard work takes place.

For storing triplets of strings a two dimensional table would be
the most intuitive approach. Or, if the triplet is rearranged
into pair of one string and a pair, a hash table can be used. But
hey, we already have those! Excellent. In other words,

        <path, model, seclabel>

is turned into:

        <path, <model, seclabel>>

The @path is then the key that the hash table is filled with. The
inner pair is turned into linked list (hash table in a hash table
would be awful really). Moreover, we need to store yet another
item: reference counter.

While virtlockd holds internal state in a JSON file between, this
feature is honored too.

Signed-off-by: Michal Privoznik <mprivozn at redhat.com>
---
 src/locking/lock_daemon.c | 375 ++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 361 insertions(+), 14 deletions(-)

diff --git a/src/locking/lock_daemon.c b/src/locking/lock_daemon.c
index b39a63a..66fbe03 100644
--- a/src/locking/lock_daemon.c
+++ b/src/locking/lock_daemon.c
@@ -58,12 +58,30 @@
 VIR_LOG_INIT("locking.lock_daemon");
 
 #define VIR_LOCK_DAEMON_NUM_LOCKSPACES 3
+#define VIR_LOCK_DAEMON_NUM_SECLABELS 8
 
 struct _virLockDaemon {
     virMutex lock;
     virNetServerPtr srv;
     virHashTablePtr lockspaces;
     virLockSpacePtr defaultLockspace;
+    virHashTablePtr seclabels;
+};
+
+typedef struct _virSeclabel virSeclabel;
+typedef virSeclabel *virSeclabelPtr;
+struct _virSeclabel {
+    char *model;
+    char *seclabel;
+    unsigned int refcount;
+};
+
+typedef struct _virSeclabelList virSeclabelList;
+typedef virSeclabelList *virSeclabelListPtr;
+struct _virSeclabelList {
+    virSeclabelPtr item;
+    virSeclabelListPtr prev;
+    virSeclabelListPtr next;
 };
 
 virLockDaemonPtr lockDaemon = NULL;
@@ -121,6 +139,7 @@ virLockDaemonFree(virLockDaemonPtr lockd)
     virObjectUnref(lockd->srv);
     virHashFree(lockd->lockspaces);
     virLockSpaceFree(lockd->defaultLockspace);
+    virHashFree(lockd->seclabels);
 
     VIR_FREE(lockd);
 }
@@ -132,6 +151,178 @@ static void virLockDaemonLockSpaceDataFree(void *data,
     virLockSpaceFree(data);
 }
 
+
+static void
+virSeclabelFree(virSeclabelPtr label)
+{
+    if (!label)
+        return;
+
+    VIR_FREE(label->model);
+    VIR_FREE(label->seclabel);
+    VIR_FREE(label);
+}
+
+
+static void
+virSeclabelListFree(virSeclabelListPtr list)
+{
+    while (list) {
+        virSeclabelListPtr tmp = list->next;
+        virSeclabelFree(list->item);
+        VIR_FREE(list);
+        list = tmp;
+    }
+}
+
+
+static virSeclabelListPtr
+virSeclabelListFind(virSeclabelListPtr list,
+                    const char *model)
+{
+    while (list && list->item) {
+        if (STREQ(list->item->model, model))
+            return list;
+        list = list->next;
+    }
+    return NULL;
+}
+
+
+static virSeclabelListPtr
+virSeclabelListAdd(virSeclabelListPtr list,
+                   const char *model,
+                   const char *seclabel)
+{
+    virSeclabelPtr tmp = NULL;
+    virSeclabelListPtr item = NULL;
+    virSeclabelListPtr ret = NULL;
+
+    if (!list)
+        return NULL;
+
+    while (list && list->next) {
+        if (STREQ(list->item->model, model))
+            return list;
+        list = list->next;
+    }
+
+    /* The model does not exist yet. Append at the end of the list */
+    if (VIR_ALLOC(tmp) < 0 ||
+        VIR_STRDUP(tmp->model, model) < 0 ||
+        VIR_STRDUP(tmp->seclabel, seclabel) < 0)
+        goto cleanup;
+
+    if (!list->item) {
+        /* Handle special case */
+        list->item = tmp;
+        item = list;
+    } else {
+        if (VIR_ALLOC(item) < 0)
+            goto cleanup;
+
+        item->item = tmp;
+        list->next = item;
+        item->prev = list;
+    }
+
+    ret = item;
+    item = NULL;
+    tmp = NULL;
+
+ cleanup:
+    virSeclabelListFree(item);
+    virSeclabelFree(tmp);
+    return ret;
+}
+
+
+static void
+virLockDaemonSeclabelDataFree(void *data,
+                              const void *key ATTRIBUTE_UNUSED)
+{
+    virSeclabelListFree(data);
+}
+
+
+static virJSONValuePtr
+virSeclabelPreExecRestart(virSeclabelListPtr list)
+{
+    virJSONValuePtr object = virJSONValueNewArray();
+
+    if (!object)
+        return NULL;
+
+    while (list) {
+        virSeclabelPtr seclabel = list->item;
+        virJSONValuePtr child = virJSONValueNewObject();
+
+        if (!child ||
+            virJSONValueArrayAppend(object, child) < 0) {
+            virJSONValueFree(child);
+            goto error;
+        }
+
+        if (virJSONValueObjectAppendString(child, "model", seclabel->model) < 0 ||
+            virJSONValueObjectAppendString(child, "seclabel", seclabel->seclabel) < 0 ||
+            virJSONValueObjectAppendNumberUint(child, "refcount", seclabel->refcount) < 0)
+            goto error;
+
+        list = list->next;
+    }
+
+    return object;
+
+ error:
+    virJSONValueFree(object);
+    return NULL;
+}
+
+
+static virSeclabelListPtr
+virSeclabelPostExecRestart(virJSONValuePtr object)
+{
+    virSeclabelListPtr list;
+    ssize_t i, n;
+
+    if (VIR_ALLOC(list) < 0)
+        goto error;
+
+    if ((n = virJSONValueArraySize(object)) < 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("Malformed seclabel list"));
+        goto error;
+    }
+
+    for (i = 0; i < n; i++) {
+        virJSONValuePtr child = virJSONValueArrayGet(object, i);
+        const char *model;
+        const char *seclabel;
+        unsigned int refcount;
+        virSeclabelListPtr item;
+
+        if (!(model = virJSONValueObjectGetString(child, "model")) ||
+            !(seclabel = virJSONValueObjectGetString(child, "seclabel")) ||
+            virJSONValueObjectGetNumberUint(child, "refcount", &refcount) < 0) {
+            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                           _("Malformed seclabel list"));
+            goto error;
+        }
+
+        if (!(item = virSeclabelListAdd(list, model, seclabel)))
+            goto error;
+
+        item->item->refcount = refcount;
+    }
+
+    return list;
+
+ error:
+    virSeclabelListFree(list);
+    return NULL;
+}
+
+
 static virLockDaemonPtr
 virLockDaemonNew(virLockDaemonConfigPtr config, bool privileged)
 {
@@ -163,6 +354,10 @@ virLockDaemonNew(virLockDaemonConfigPtr config, bool privileged)
     if (!(lockd->defaultLockspace = virLockSpaceNew(NULL)))
         goto error;
 
+    if (!(lockd->seclabels = virHashCreate(VIR_LOCK_DAEMON_NUM_SECLABELS,
+                                           virLockDaemonSeclabelDataFree)))
+        goto error;
+
     return lockd;
 
  error:
@@ -176,7 +371,7 @@ virLockDaemonNewPostExecRestart(virJSONValuePtr object, bool privileged)
 {
     virLockDaemonPtr lockd;
     virJSONValuePtr child;
-    virJSONValuePtr lockspaces;
+    virJSONValuePtr lockspaces, seclabels;
     size_t i;
     int n;
 
@@ -194,6 +389,10 @@ virLockDaemonNewPostExecRestart(virJSONValuePtr object, bool privileged)
                                             virLockDaemonLockSpaceDataFree)))
         goto error;
 
+    if (!(lockd->seclabels = virHashCreate(VIR_LOCK_DAEMON_NUM_SECLABELS,
+                                           virLockDaemonSeclabelDataFree)))
+        goto error;
+
     if (!(child = virJSONValueObjectGet(object, "defaultLockspace"))) {
         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                        _("Missing defaultLockspace data from JSON file"));
@@ -231,6 +430,38 @@ virLockDaemonNewPostExecRestart(virJSONValuePtr object, bool privileged)
         }
     }
 
+    if ((seclabels = virJSONValueObjectGet(object, "seclabels"))) {
+        /* Parse iff seclabels attribute is present */
+        if ((n = virJSONValueArraySize(seclabels)) < 0) {
+            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                           _("Malformed seclabels data from JSON file"));
+            goto error;
+        }
+
+        for (i = 0; i < n; i++) {
+            virSeclabelListPtr list;
+            virJSONValuePtr seclabel_list;
+            const char *path;
+
+            child = virJSONValueArrayGet(seclabels, i);
+
+            if (!(path = virJSONValueObjectGetString(child, "path")) ||
+                !(seclabel_list = virJSONValueObjectGet(child, "seclabel"))) {
+                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                               _("Malformed seclabels data from JSON file"));
+                goto error;
+            }
+
+            if (!(list = virSeclabelPostExecRestart(seclabel_list)))
+                goto error;
+
+            if (virHashAddEntry(lockd->seclabels, path, list) < 0) {
+                virSeclabelListFree(list);
+                goto error;
+            }
+        }
+    }
+
     if (!(child = virJSONValueObjectGet(object, "server"))) {
         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                        _("Missing server data from JSON file"));
@@ -279,24 +510,109 @@ virLockSpacePtr virLockDaemonFindLockSpace(virLockDaemonPtr lockd,
 
 
 int
-virLockDaemonRememberSeclabel(virLockDaemonPtr lockd ATTRIBUTE_UNUSED,
-                              const char *path ATTRIBUTE_UNUSED,
-                              const char *model ATTRIBUTE_UNUSED,
-                              const char *seclabel ATTRIBUTE_UNUSED)
+virLockDaemonRememberSeclabel(virLockDaemonPtr lockd,
+                              const char *path,
+                              const char *model,
+                              const char *seclabel)
 {
-    /* Implement me */
-    return -1;
+    int ret = -1;
+    virSeclabelListPtr list = NULL;
+    virSeclabelListPtr tmp = NULL;
+    bool list_created = false;
+
+    virMutexLock(&lockd->lock);
+
+    if (!(list = virHashLookup(lockd->seclabels, path))) {
+        if (VIR_ALLOC(list) < 0)
+            goto cleanup;
+
+        if (virHashAddEntry(lockd->seclabels, path, list) < 0)
+            goto cleanup;
+
+        list_created = true;
+    }
+
+    tmp = list;
+    if (!(tmp = virSeclabelListFind(list, model))) {
+        /* seclabel for @model doesn't exit yet */
+        if (!(tmp = virSeclabelListAdd(list, model, seclabel)))
+            goto cleanup;
+    }
+
+    /* Update refcount */
+    ret = ++tmp->item->refcount;
+
+ cleanup:
+    virMutexUnlock(&lockd->lock);
+    if (ret < 0 && list_created) {
+        virHashRemoveEntry(lockd->seclabels, path);
+        virSeclabelListFree(list);
+    }
+    return ret;
 }
 
 
 int
-virLockDaemonRecallSeclabel(virLockDaemonPtr lockd ATTRIBUTE_UNUSED,
-                              const char *path ATTRIBUTE_UNUSED,
-                              const char *model ATTRIBUTE_UNUSED,
-                              char **seclabel ATTRIBUTE_UNUSED)
+virLockDaemonRecallSeclabel(virLockDaemonPtr lockd,
+                              const char *path,
+                              const char *model,
+                              char **seclabel)
 {
-    /* Implement me */
-    return -1;
+    int ret = -1;
+    virSeclabelListPtr list = NULL;
+    virSeclabelPtr label = NULL;
+
+    virMutexLock(&lockd->lock);
+
+    if (!(list = virHashLookup(lockd->seclabels, path))) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("unable to find path '%s' in seclabels hashtable"),
+                       path);
+        goto cleanup;
+    }
+
+    if (!(list = virSeclabelListFind(list, model))) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("unable to find entry for path "
+                         "'%s' and security model '%s'"),
+                       path, model);
+        goto cleanup;
+    }
+
+    label = list->item;
+
+    if (seclabel && VIR_STRDUP(*seclabel, label->seclabel) < 0)
+        goto cleanup;
+
+    /* Now decrement refcount */
+    if (!label->refcount) {
+        /* Huh funny. This should never happen (TM) */
+        VIR_WARN("path '%s' had no refcounts", path);
+    } else {
+        label->refcount--;
+    }
+
+    if (!(ret = label->refcount)) {
+        /* Okay, this is the last reference, adjust the linked list of
+         * seclabels */
+        if (list->prev)
+            list->prev->next = list->next;
+        if (list->next)
+            list->next->prev = list->prev;
+
+        if (!list->next && !list->prev) {
+            /* The last seclabel for @path, remove it. */
+            virHashRemoveEntry(lockd->seclabels, path);
+        } else {
+            /* There's another seclabel for @path, remove only this item. */
+            list->next = list->prev = NULL;
+            virSeclabelListFree(list);
+        }
+    }
+
+ cleanup:
+    virMutexUnlock(&lockd->lock);
+    return ret;
 }
 
 
@@ -1034,7 +1350,7 @@ virLockDaemonPreExecRestart(const char *state_file,
     virJSONValuePtr object;
     char *magic;
     virHashKeyValuePairPtr pairs = NULL, tmp;
-    virJSONValuePtr lockspaces;
+    virJSONValuePtr lockspaces, seclabels;
 
     VIR_DEBUG("Running pre-restart exec");
 
@@ -1080,6 +1396,37 @@ virLockDaemonPreExecRestart(const char *state_file,
         tmp++;
     }
 
+    if (!(seclabels = virJSONValueNewArray()) ||
+        virJSONValueObjectAppend(object, "seclabels", seclabels) < 0) {
+        virJSONValueFree(seclabels);
+        goto cleanup;
+    }
+
+    VIR_FREE(pairs);
+    tmp = pairs = virHashGetItems(lockDaemon->seclabels, NULL);
+    while (tmp && tmp->key) {
+        virSeclabelListPtr list = (virSeclabelListPtr)tmp->value;
+        virJSONValuePtr seclabel_list;
+
+        if (!(seclabel_list = virSeclabelPreExecRestart(list)))
+            goto cleanup;
+
+        if (!(child = virJSONValueNewObject()) ||
+            virJSONValueObjectAppendString(child, "path", tmp->key) < 0 ||
+            virJSONValueObjectAppend(child, "seclabel", seclabel_list) < 0) {
+            virJSONValueFree(seclabel_list);
+            virJSONValueFree(child);
+            goto cleanup;
+        }
+
+        if (virJSONValueArrayAppend(seclabels, child) < 0) {
+            virJSONValueFree(child);
+            goto cleanup;
+        }
+
+        tmp++;
+    }
+
     if (!(magic = virLockDaemonGetExecRestartMagic()))
         goto cleanup;
 
-- 
1.8.5.5




More information about the libvir-list mailing list