]> git.ipfire.org Git - thirdparty/strongswan.git/commitdiff
sec-label: Add class to represent security labels
authorTobias Brunner <tobias@strongswan.org>
Mon, 20 Dec 2021 10:23:37 +0000 (11:23 +0100)
committerTobias Brunner <tobias@strongswan.org>
Thu, 14 Apr 2022 16:42:01 +0000 (18:42 +0200)
In accordance with SELinux, we include the null-terminator in the encoding
for now.

src/libstrongswan/Android.mk
src/libstrongswan/Makefile.am
src/libstrongswan/selectors/sec_label.c [new file with mode: 0644]
src/libstrongswan/selectors/sec_label.h [new file with mode: 0644]

index 660382da2ea6928316f6b9e9c3d6a81e69315ae7..c1001905ccd0ced95ad4733942db9c5e783fb5a5 100644 (file)
@@ -41,7 +41,8 @@ networking/streams/stream_tcp.c networking/streams/stream_service_tcp.c \
 pen/pen.c plugins/plugin_loader.c plugins/plugin_feature.c processing/jobs/job.c \
 processing/jobs/callback_job.c processing/processor.c processing/scheduler.c \
 processing/watcher.c resolver/resolver_manager.c resolver/rr_set.c \
-selectors/traffic_selector.c settings/settings.c settings/settings_types.c \
+selectors/sec_label.c selectors/traffic_selector.c \
+settings/settings.c settings/settings_types.c \
 settings/settings_parser.c settings/settings_lexer.c utils/cpu_feature.c \
 utils/utils.c utils/chunk.c utils/debug.c utils/enum.c utils/identification.c \
 utils/lexparser.c utils/optionsfrom.c utils/capabilities.c utils/backtrace.c \
index 5d230822b5a64ad46abfd84be42e4ce1c1c679db..37fe4b1e519ca8fc80d3a2aff041442e90258f12 100644 (file)
@@ -39,7 +39,8 @@ networking/streams/stream_tcp.c networking/streams/stream_service_tcp.c \
 pen/pen.c plugins/plugin_loader.c plugins/plugin_feature.c processing/jobs/job.c \
 processing/jobs/callback_job.c processing/processor.c processing/scheduler.c \
 processing/watcher.c resolver/resolver_manager.c resolver/rr_set.c \
-selectors/traffic_selector.c settings/settings.c settings/settings_types.c \
+selectors/sec_label.c selectors/traffic_selector.c \
+settings/settings.c settings/settings_types.c \
 settings/settings_parser.y settings/settings_lexer.l utils/cpu_feature.c \
 utils/utils.c utils/chunk.c utils/debug.c utils/enum.c utils/identification.c \
 utils/lexparser.c utils/optionsfrom.c utils/capabilities.c utils/backtrace.c \
@@ -112,7 +113,8 @@ resolver/resolver.h resolver/resolver_response.h resolver/rr_set.h \
 resolver/rr.h resolver/resolver_manager.h \
 plugins/plugin_loader.h plugins/plugin.h plugins/plugin_feature.h \
 processing/jobs/job.h processing/jobs/callback_job.h processing/processor.h \
-processing/scheduler.h processing/watcher.h selectors/traffic_selector.h \
+processing/scheduler.h processing/watcher.h \
+selectors/sec_label.h selectors/traffic_selector.h \
 settings/settings.h settings/settings_parser.h threading/thread_value.h \
 threading/thread.h threading/windows/thread.h \
 threading/mutex.h threading/condvar.h threading/spinlock.h threading/semaphore.h \
diff --git a/src/libstrongswan/selectors/sec_label.c b/src/libstrongswan/selectors/sec_label.c
new file mode 100644 (file)
index 0000000..1b85942
--- /dev/null
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2021 Tobias Brunner, codelabs GmbH
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#ifdef USE_SELINUX
+#include <selinux/selinux.h>
+#endif
+
+#include "sec_label.h"
+
+typedef struct private_sec_label_t private_sec_label_t;
+
+/**
+ * Private data.
+ */
+struct private_sec_label_t {
+
+       /**
+        * Public interface
+        */
+       sec_label_t public;
+
+       /**
+        * Encoded label value
+        */
+       chunk_t encoding;
+
+       /**
+        * String representation of the label
+        */
+       char *str;
+};
+
+static sec_label_t *create_sec_label(chunk_t encoding, char *str);
+
+METHOD(sec_label_t, get_encoding, chunk_t,
+       private_sec_label_t *this)
+{
+       return this->encoding;
+}
+
+METHOD(sec_label_t, get_string, char*,
+       private_sec_label_t *this)
+{
+       return this->str;
+}
+
+METHOD(sec_label_t, clone_, sec_label_t*,
+       private_sec_label_t *this)
+{
+       return create_sec_label(chunk_clone(this->encoding), strdup(this->str));
+}
+
+METHOD(sec_label_t, equals, bool,
+       private_sec_label_t *this, sec_label_t *other_pub)
+{
+       private_sec_label_t *other = (private_sec_label_t*)other_pub;
+
+       if (!other_pub)
+       {
+               return FALSE;
+       }
+       return chunk_equals_const(this->encoding, other->encoding);
+}
+
+METHOD(sec_label_t, matches, bool,
+       private_sec_label_t *this, sec_label_t *other_pub)
+{
+       if (!other_pub)
+       {
+               return FALSE;
+       }
+#ifdef USE_SELINUX
+       if (is_selinux_enabled())
+       {       /* if disabled, the following matches anything against anything */
+               private_sec_label_t *other = (private_sec_label_t*)other_pub;
+               return selinux_check_access(other->str, this->str, "association",
+                                                                       "polmatch", NULL) == 0;
+       }
+#endif
+       return equals(this, other_pub);
+}
+
+METHOD(sec_label_t, hash, u_int,
+       private_sec_label_t *this, u_int inc)
+{
+       return chunk_hash_inc(this->encoding, inc);
+}
+
+METHOD(sec_label_t, destroy, void,
+       private_sec_label_t *this)
+{
+       chunk_free(&this->encoding);
+       free(this->str);
+       free(this);
+}
+
+/**
+ * Internal constructor, data is adopted
+ */
+static sec_label_t *create_sec_label(chunk_t encoding, char *str)
+{
+       private_sec_label_t *this;
+
+       INIT(this,
+               .public = {
+                       .get_encoding = _get_encoding,
+                       .get_string = _get_string,
+                       .clone = _clone_,
+                       .matches = _matches,
+                       .equals = _equals,
+                       .hash = _hash,
+                       .destroy = _destroy,
+               },
+               .encoding = encoding,
+               .str = str,
+       );
+       return &this->public;
+}
+
+/*
+ * Described in header
+ */
+sec_label_t *sec_label_from_encoding(const chunk_t value)
+{
+       chunk_t cloned, sanitized = chunk_empty;
+       char *str;
+
+       if (!value.len || (value.len == 1 && !value.ptr[0]))
+       {
+               DBG1(DBG_LIB, "invalid empty security label");
+               return NULL;
+       }
+       else if (value.ptr[value.len-1])
+       {
+               DBG1(DBG_LIB, "adding null-terminator to security label");
+               cloned = chunk_cat("cc", value, chunk_from_chars(0x00));
+       }
+       else
+       {
+               cloned = chunk_clone(value);
+       }
+
+       /* create a sanitized version while ignoring the null-terminator */
+       if (!chunk_printable(chunk_create(cloned.ptr, cloned.len-1), &sanitized, '?'))
+       {
+#ifdef USE_SELINUX
+               /* don't accept labels with non-printable characters if we use SELinux */
+               DBG1(DBG_LIB, "invalid security label with non-printable characters %B",
+                        &value);
+               chunk_free(&sanitized);
+               chunk_free(&cloned);
+               return NULL;
+#endif
+       }
+       if (asprintf(&str, "%.*s", (int)sanitized.len, sanitized.ptr) <= 0)
+       {
+               chunk_free(&sanitized);
+               chunk_free(&cloned);
+               return NULL;
+       }
+       chunk_free(&sanitized);
+
+       return create_sec_label(cloned, str);
+}
+
+/*
+ * Described in header
+ */
+sec_label_t *sec_label_from_string(const char *value)
+{
+       if (!value)
+       {
+               return NULL;
+       }
+       return sec_label_from_encoding(chunk_create((char*)value, strlen(value)+1));
+}
diff --git a/src/libstrongswan/selectors/sec_label.h b/src/libstrongswan/selectors/sec_label.h
new file mode 100644 (file)
index 0000000..55feec4
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2021 Tobias Brunner, codelabs GmbH
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/**
+ * @defgroup sec_label sec_label
+ * @{ @ingroup ipsec
+ */
+
+#ifndef SEC_LABEL_H_
+#define SEC_LABEL_H_
+
+typedef struct sec_label_t sec_label_t;
+
+#include <library.h>
+
+/**
+ * Representation of a security label used on policies/SAs.
+ *
+ * For example, with SELinux this could be a value like
+ * system_u:object_r:ipsec_spd_t:s0.
+ */
+struct sec_label_t {
+
+       /**
+        * Return a binary encoding of the security label as used for IKE.
+        *
+        * @return                      binary encoding (internal data)
+        */
+       chunk_t (*get_encoding)(sec_label_t *this);
+
+       /**
+        * Return a string representation of this security label.
+        *
+        * @return                      string representation (internal data)
+        */
+       char *(*get_string)(sec_label_t *this);
+
+       /**
+        * Clone this security label.
+        *
+        * @return                      clone of it
+        */
+       sec_label_t *(*clone)(sec_label_t *this);
+
+       /**
+        * Match two security labels.
+        *
+        * For SELinux this checks if this security label permits other in terms
+        * of association { polmatch }.
+        *
+        * @param other         security label to match against this
+        * @return                      TRUE if matching, FALSE otherwise
+        */
+       bool (*matches)(sec_label_t *this, sec_label_t *other);
+
+       /**
+        * Compare two security labels for equality.
+        *
+        * @param other         security label to compare with this
+        * @return                      TRUE if equal, FALSE otherwise
+        */
+       bool (*equals)(sec_label_t *this, sec_label_t *other);
+
+       /**
+        * Create a hash value for the security label.
+        *
+        * @param inc           optional value for incremental hashing
+        * @return                      calculated hash value for the security label
+        */
+       u_int (*hash)(sec_label_t *this, u_int inc);
+
+       /**
+        * Destroys the object.
+        */
+       void (*destroy)(sec_label_t *this);
+};
+
+/**
+ * Try to parse a sec_label_t from the given binary encoding.
+ *
+ * @param value                        encoding to parse
+ * @return                             security label instance, NULL if invalid
+ */
+sec_label_t *sec_label_from_encoding(const chunk_t value);
+
+/**
+ * Try to parse a sec_label_t from the given string.
+ *
+ * @param value                        string to parse
+ * @return                             security label instance, NULL if invalid
+ */
+sec_label_t *sec_label_from_string(const char *value);
+
+/**
+ * Compare two security labels for equality, accept if both are NULL.
+ *
+ * @param a                            first label
+ * @param b                            second label
+ * @return                             TRUE if labels are equal or both NULL
+ */
+static inline bool sec_labels_equal(sec_label_t *a, sec_label_t *b)
+{
+       return (!a && !b) || (a && a->equals(a, b));
+}
+
+#endif /** SEC_LABEL_H_ @}*/