sec-label: Add class to represent security labels

In accordance with SELinux, we include the null-terminator in the encoding
for now.
This commit is contained in:
Tobias Brunner 2021-12-20 11:23:37 +01:00
parent fe5f27336d
commit decfe44433
4 changed files with 328 additions and 3 deletions

View 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 \

View 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 \

View File

@ -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));
}

View File

@ -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_ @}*/