[libvirt] [PATCH v3 02/18] security: Include security_util

Michal Privoznik mprivozn at redhat.com
Wed Dec 12 12:40:46 UTC 2018


This file implements wrappers over XATTR getter/setter. It
ensures the proper XATTR namespace is used.

Signed-off-by: Michal Privoznik <mprivozn at redhat.com>
---
 src/security/Makefile.inc.am |   2 +
 src/security/security_util.c | 256 +++++++++++++++++++++++++++++++++++
 src/security/security_util.h |  32 +++++
 3 files changed, 290 insertions(+)
 create mode 100644 src/security/security_util.c
 create mode 100644 src/security/security_util.h

diff --git a/src/security/Makefile.inc.am b/src/security/Makefile.inc.am
index f88b82df7b..0ade97d355 100644
--- a/src/security/Makefile.inc.am
+++ b/src/security/Makefile.inc.am
@@ -14,6 +14,8 @@ SECURITY_DRIVER_SOURCES = \
 	security/security_dac.c \
 	security/security_manager.h \
 	security/security_manager.c \
+	security/security_util.h \
+	security/security_util.c \
 	$(NULL)
 
 SECURITY_DRIVER_SELINUX_SOURCES = \
diff --git a/src/security/security_util.c b/src/security/security_util.c
new file mode 100644
index 0000000000..194343c407
--- /dev/null
+++ b/src/security/security_util.c
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+
+#include "viralloc.h"
+#include "virfile.h"
+#include "virstring.h"
+#include "virerror.h"
+
+#include "security_util.h"
+
+#define VIR_FROM_THIS VIR_FROM_SECURITY
+
+/* There are four namespaces available on Linux (xattr(7)):
+ *
+ *  user - can be modified by anybody,
+ *  system - used by ACLs
+ *  security - used by SELinux
+ *  trusted - accessibly by CAP_SYS_ADMIN processes only
+ *
+ * Looks like the last one is way to go.
+ * Unfortunately, FreeBSD only supports:
+ *
+ *  user - can be modified by anybody,
+ *  system - accessible by CAP_SYS_ADMIN processes only
+ *
+ * Note that 'system' on FreeBSD corresponds to 'trusted' on
+ * Linux. So far the only point where FreeBSD and Linux can meet
+ * is NFS which still doesn't support XATTRs. Therefore we can
+ * use different namespace on each system. If NFS gains support
+ * for XATTRs then we have to find a way to deal with the
+ * different namespaces. But that is a problem for future me.
+ */
+#if defined(__linux__)
+# define XATTR_NAMESPACE "trusted"
+#elif defined(__FreeBSD__)
+# define XATTR_NAMESPACE "system"
+#endif
+
+static char *
+virSecurityGetAttrName(const char *name ATTRIBUTE_UNUSED)
+{
+    char *ret = NULL;
+#ifdef XATTR_NAMESPACE
+    ignore_value(virAsprintf(&ret, XATTR_NAMESPACE".libvirt.security.%s", name));
+#else
+    errno = ENOSYS;
+    virReportSystemError(errno, "%s",
+                         _("Extended attributes are not supported on this system"));
+#endif
+    return ret;
+}
+
+
+static char *
+virSecurityGetRefCountAttrName(const char *name ATTRIBUTE_UNUSED)
+{
+    char *ret = NULL;
+#ifdef XATTR_NAMESPACE
+    ignore_value(virAsprintf(&ret, XATTR_NAMESPACE".libvirt.security.ref_%s", name));
+#else
+    errno = ENOSYS;
+    virReportSystemError(errno, "%s",
+                         _("Extended attributes are not supported on this system"));
+#endif
+    return ret;
+}
+
+
+/**
+ * virSecurityGetRememberedLabel:
+ * @name: security driver name
+ * @path: file name
+ * @label: label
+ *
+ * For given @path and security driver (@name) fetch remembered
+ * @label. The caller must not restore label if an error is
+ * indicated or if @label is NULL upon return.
+ *
+ * The idea is that the first time
+ * virSecuritySetRememberedLabel() is called over @path the
+ * @label is recorded and refcounter is set to 1. Each subsequent
+ * call to virSecuritySetRememberedLabel() increases the counter.
+ * Counterpart to this is virSecurityGetRememberedLabel() which
+ * decreases the counter and reads the @label only if the counter
+ * reached value of zero. For any other call (i.e. when the
+ * counter is not zero), virSecurityGetRememberedLabel() set
+ * @label to NULL (to notify the caller that the refcount is not
+ * zero) and returns zero.
+ *
+ * Returns: 0 on success,
+ *         -1 otherwise (with error reported)
+ */
+int
+virSecurityGetRememberedLabel(const char *name,
+                              const char *path,
+                              char **label)
+{
+    char *ref_name = NULL;
+    char *attr_name = NULL;
+    char *value = NULL;
+    unsigned int refcount = 0;
+    int ret = -1;
+
+    *label = NULL;
+
+    if (!(ref_name = virSecurityGetRefCountAttrName(name)))
+        goto cleanup;
+
+    if (virFileGetXAttr(path, ref_name, &value) < 0) {
+        if (errno == ENOSYS || errno == ENODATA || errno == ENOTSUP) {
+            ret = 0;
+        } else {
+            virReportSystemError(errno,
+                                 _("Unable to get XATTR %s on %s"),
+                                 ref_name,
+                                 path);
+        }
+        goto cleanup;
+    }
+
+    if (virStrToLong_ui(value, NULL, 10, &refcount) < 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("malformed refcount %s on %s"),
+                       value, path);
+        goto cleanup;
+    }
+
+    VIR_FREE(value);
+
+    refcount--;
+
+    if (refcount > 0) {
+        if (virAsprintf(&value, "%u", refcount) < 0)
+            goto cleanup;
+
+        if (virFileSetXAttr(path, ref_name, value) < 0)
+            goto cleanup;
+    } else {
+        if (virFileRemoveXAttr(path, ref_name) < 0)
+            goto cleanup;
+
+        if (!(attr_name = virSecurityGetAttrName(name)))
+            goto cleanup;
+
+        if (virFileGetXAttr(path, attr_name, label) < 0)
+            goto cleanup;
+
+        if (virFileRemoveXAttr(path, attr_name) < 0)
+            goto cleanup;
+    }
+
+    ret = 0;
+ cleanup:
+    VIR_FREE(value);
+    VIR_FREE(attr_name);
+    VIR_FREE(ref_name);
+    return ret;
+}
+
+
+/**
+ * virSecuritySetRememberedLabel:
+ * @name: security driver name
+ * @path: file name
+ * @label: label
+ *
+ * For given @path and security driver (@name), if called the
+ * first time over @path, set the @label to remember (i.e. the
+ * original owner of the @path). Any subsequent call over @path
+ * will increment refcounter. It is strongly recommended that the
+ * caller checks for the return value and if it is greater than 1
+ * (meaning that some domain is already using @path) the current
+ * label is required instead of setting a new one.
+ *
+ * See also virSecurityGetRememberedLabel.
+ *
+ * Returns: the new refcount value on success,
+ *         -1 otherwise (with error reported)
+ */
+int
+virSecuritySetRememberedLabel(const char *name,
+                              const char *path,
+                              const char *label)
+{
+    char *ref_name = NULL;
+    char *attr_name = NULL;
+    char *value = NULL;
+    unsigned int refcount = 0;
+    int ret = -1;
+
+    if (!(ref_name = virSecurityGetRefCountAttrName(name)))
+        goto cleanup;
+
+    if (virFileGetXAttr(path, ref_name, &value) < 0) {
+        if (errno == ENOSYS || errno == ENOTSUP) {
+            ret = 0;
+            goto cleanup;
+        } else if (errno != ENODATA) {
+            virReportSystemError(errno,
+                                 _("Unable to get XATTR %s on %s"),
+                                 ref_name,
+                                 path);
+            goto cleanup;
+        }
+    }
+
+    if (value &&
+        virStrToLong_ui(value, NULL, 10, &refcount) < 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("malformed refcount %s on %s"),
+                       value, path);
+        goto cleanup;
+    }
+
+    VIR_FREE(value);
+
+    refcount++;
+
+    if (refcount == 1) {
+        if (!(attr_name = virSecurityGetAttrName(name)))
+            goto cleanup;
+
+        if (virFileSetXAttr(path, attr_name, label) < 0)
+            goto cleanup;
+    }
+
+    if (virAsprintf(&value, "%u", refcount) < 0)
+        goto cleanup;
+
+    if (virFileSetXAttr(path, ref_name, value) < 0)
+        goto cleanup;
+
+    ret = refcount;
+ cleanup:
+    VIR_FREE(value);
+    VIR_FREE(attr_name);
+    VIR_FREE(ref_name);
+    return ret;
+}
diff --git a/src/security/security_util.h b/src/security/security_util.h
new file mode 100644
index 0000000000..a6e67f4390
--- /dev/null
+++ b/src/security/security_util.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __SECURITY_UTIL_H__
+# define __SECURITY_UTIL_H__
+
+int
+virSecurityGetRememberedLabel(const char *name,
+                              const char *path,
+                              char **label);
+
+int
+virSecuritySetRememberedLabel(const char *name,
+                              const char *path,
+                              const char *label);
+
+#endif /* __SECURITY_UTIL_H__ */
-- 
2.19.2




More information about the libvir-list mailing list