selinux: Add plugin to install trap policies with generic labels
After establishing an IKE_SA, we check if any of its child configs define generic SELinux labels and install trap policies for them if necessary narrowed to the current (virtual) IPs.
This commit is contained in:
@@ -1524,6 +1524,7 @@ ADD_PLUGIN([kernel-iph], [c charon])
|
||||
ADD_PLUGIN([kernel-pfkey], [c charon starter nm cmd])
|
||||
ADD_PLUGIN([kernel-pfroute], [c charon starter nm cmd])
|
||||
ADD_PLUGIN([kernel-netlink], [c charon starter nm cmd])
|
||||
ADD_PLUGIN([selinux], [c charon starter nm cmd])
|
||||
ADD_PLUGIN([resolve], [c charon cmd])
|
||||
ADD_PLUGIN([save-keys], [c])
|
||||
ADD_PLUGIN([socket-default], [c charon nm cmd])
|
||||
@@ -1770,6 +1771,7 @@ AM_CONDITIONAL(USE_RESOLVE, test x$resolve = xtrue)
|
||||
AM_CONDITIONAL(USE_ATTR, test x$attr = xtrue)
|
||||
AM_CONDITIONAL(USE_ATTR_SQL, test x$attr_sql = xtrue)
|
||||
AM_CONDITIONAL(USE_COUNTERS, test x$counters = xtrue)
|
||||
AM_CONDITIONAL(USE_SELINUX, test x$selinux = xtrue)
|
||||
|
||||
# other options
|
||||
# ---------------
|
||||
@@ -2073,6 +2075,7 @@ AC_CONFIG_FILES([
|
||||
src/libcharon/plugins/resolve/Makefile
|
||||
src/libcharon/plugins/attr/Makefile
|
||||
src/libcharon/plugins/attr_sql/Makefile
|
||||
src/libcharon/plugins/selinux/Makefile
|
||||
src/libcharon/tests/Makefile
|
||||
src/libtpmtss/Makefile
|
||||
src/libtpmtss/plugins/tpm/Makefile
|
||||
|
||||
@@ -726,6 +726,13 @@ if MONOLITHIC
|
||||
endif
|
||||
endif
|
||||
|
||||
if USE_SELINUX
|
||||
SUBDIRS += plugins/selinux
|
||||
if MONOLITHIC
|
||||
libcharon_la_LIBADD += plugins/selinux/libstrongswan-selinux.la
|
||||
endif
|
||||
endif
|
||||
|
||||
if USE_ATTR_SQL
|
||||
SUBDIRS += plugins/attr_sql
|
||||
if MONOLITHIC
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
AM_CPPFLAGS = \
|
||||
-I$(top_srcdir)/src/libstrongswan \
|
||||
-I$(top_srcdir)/src/libcharon
|
||||
|
||||
AM_CFLAGS = \
|
||||
$(PLUGIN_CFLAGS)
|
||||
|
||||
if MONOLITHIC
|
||||
noinst_LTLIBRARIES = libstrongswan-selinux.la
|
||||
else
|
||||
plugin_LTLIBRARIES = libstrongswan-selinux.la
|
||||
endif
|
||||
|
||||
libstrongswan_selinux_la_SOURCES = \
|
||||
selinux_plugin.h selinux_plugin.c \
|
||||
selinux_listener.h selinux_listener.c
|
||||
|
||||
libstrongswan_selinux_la_LDFLAGS = -module -avoid-version
|
||||
@@ -0,0 +1,261 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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.
|
||||
*/
|
||||
|
||||
#include "selinux_listener.h"
|
||||
|
||||
#include <daemon.h>
|
||||
#include <collections/array.h>
|
||||
#include <collections/hashtable.h>
|
||||
|
||||
typedef struct private_selinux_listener_t private_selinux_listener_t;
|
||||
|
||||
/**
|
||||
* Private data.
|
||||
*/
|
||||
struct private_selinux_listener_t {
|
||||
|
||||
/**
|
||||
* Public interface.
|
||||
*/
|
||||
selinux_listener_t public;
|
||||
|
||||
/**
|
||||
* IKE_SAs with attached trap policies, ike_sa_id_t => entry_t.
|
||||
*/
|
||||
hashtable_t *sas;
|
||||
};
|
||||
|
||||
/**
|
||||
* Entry to keep track of trap policies.
|
||||
*/
|
||||
typedef struct {
|
||||
|
||||
/**
|
||||
* IKE_SA ID.
|
||||
*/
|
||||
ike_sa_id_t *id;
|
||||
|
||||
/**
|
||||
* Installed trap policies.
|
||||
*/
|
||||
array_t *traps;
|
||||
|
||||
} entry_t;
|
||||
|
||||
/**
|
||||
* Destroy the given entry.
|
||||
*/
|
||||
static void destroy_entry(entry_t *entry)
|
||||
{
|
||||
entry->id->destroy(entry->id);
|
||||
array_destroy(entry->traps);
|
||||
free(entry);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hashtable hash function
|
||||
*/
|
||||
static u_int hash(const void *key)
|
||||
{
|
||||
ike_sa_id_t *id = (ike_sa_id_t*)key;
|
||||
uint64_t spi_i = id->get_initiator_spi(id),
|
||||
spi_r = id->get_responder_spi(id);
|
||||
return chunk_hash_inc(chunk_from_thing(spi_i),
|
||||
chunk_hash(chunk_from_thing(spi_r)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Hashtable equals function
|
||||
*/
|
||||
static bool equals(const void *a_pub, const void *b)
|
||||
{
|
||||
ike_sa_id_t *a = (ike_sa_id_t*)a_pub;
|
||||
return a->equals(a, (ike_sa_id_t*)b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Install a trap policy for the generic SELinux label.
|
||||
*/
|
||||
static bool install_generic_trap(ike_sa_t *ike_sa, child_sa_t *child_sa)
|
||||
{
|
||||
linked_list_t *local, *remote;
|
||||
sec_label_t *label;
|
||||
bool success;
|
||||
|
||||
label = child_sa->get_label(child_sa);
|
||||
DBG1(DBG_IKE, "installing trap %s{%d} with generic security label '%s'",
|
||||
child_sa->get_name(child_sa), child_sa->get_unique_id(child_sa),
|
||||
label->get_string(label));
|
||||
|
||||
local = ike_sa_get_dynamic_hosts(ike_sa, TRUE);
|
||||
remote = ike_sa_get_dynamic_hosts(ike_sa, FALSE);
|
||||
success = charon->traps->install_external(charon->traps,
|
||||
ike_sa->get_peer_cfg(ike_sa),
|
||||
child_sa, local, remote);
|
||||
local->destroy(local);
|
||||
remote->destroy(remote);
|
||||
return success;
|
||||
}
|
||||
|
||||
METHOD(listener_t, ike_updown, bool,
|
||||
private_selinux_listener_t *this, ike_sa_t *ike_sa, bool up)
|
||||
{
|
||||
enumerator_t *enumerator;
|
||||
peer_cfg_t *peer_cfg;
|
||||
child_cfg_t *child_cfg;
|
||||
child_sa_t *child_sa;
|
||||
entry_t *entry;
|
||||
|
||||
if (up)
|
||||
{
|
||||
child_sa_create_t child = {
|
||||
.if_id_in_def = ike_sa->get_if_id(ike_sa, TRUE),
|
||||
.if_id_out_def = ike_sa->get_if_id(ike_sa, FALSE),
|
||||
};
|
||||
|
||||
INIT(entry,
|
||||
.id = ike_sa->get_id(ike_sa),
|
||||
);
|
||||
entry->id = entry->id->clone(entry->id);
|
||||
|
||||
peer_cfg = ike_sa->get_peer_cfg(ike_sa);
|
||||
enumerator = peer_cfg->create_child_cfg_enumerator(peer_cfg);
|
||||
while (enumerator->enumerate(enumerator, &child_cfg))
|
||||
{
|
||||
if (child_cfg->get_label(child_cfg) &&
|
||||
child_cfg->get_label_mode(child_cfg) == SEC_LABEL_MODE_SELINUX)
|
||||
{
|
||||
child_sa = child_sa_create(ike_sa->get_my_host(ike_sa),
|
||||
ike_sa->get_other_host(ike_sa),
|
||||
child_cfg, &child);
|
||||
if (install_generic_trap(ike_sa, child_sa))
|
||||
{
|
||||
array_insert_create(&entry->traps, ARRAY_TAIL, child_sa);
|
||||
}
|
||||
else
|
||||
{
|
||||
child_sa->destroy(child_sa);
|
||||
}
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
|
||||
if (array_count(entry->traps))
|
||||
{
|
||||
this->sas->put(this->sas, entry->id, entry);
|
||||
}
|
||||
else
|
||||
{
|
||||
destroy_entry(entry);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
entry = this->sas->remove(this->sas, ike_sa->get_id(ike_sa));
|
||||
if (entry)
|
||||
{
|
||||
while (array_remove(entry->traps, ARRAY_TAIL, &child_sa))
|
||||
{
|
||||
sec_label_t *label = child_sa->get_label(child_sa);
|
||||
|
||||
DBG1(DBG_IKE, "uninstalling trap %s{%d} with generic security "
|
||||
"label '%s'", child_sa->get_name(child_sa),
|
||||
child_sa->get_unique_id(child_sa),
|
||||
label->get_string(label));
|
||||
charon->traps->remove_external(charon->traps, child_sa);
|
||||
child_sa->destroy(child_sa);
|
||||
}
|
||||
destroy_entry(entry);
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
METHOD(listener_t, ike_rekey, bool,
|
||||
private_selinux_listener_t *this, ike_sa_t *old, ike_sa_t *new)
|
||||
{
|
||||
entry_t *entry;
|
||||
|
||||
entry = this->sas->remove(this->sas, old->get_id(old));
|
||||
if (entry)
|
||||
{
|
||||
entry->id->destroy(entry->id);
|
||||
entry->id = new->get_id(new);
|
||||
entry->id = entry->id->clone(entry->id);
|
||||
this->sas->put(this->sas, entry->id, entry);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
METHOD(listener_t, ike_update, bool,
|
||||
private_selinux_listener_t *this, ike_sa_t *ike_sa,
|
||||
host_t *local, host_t *remote)
|
||||
{
|
||||
entry_t *entry;
|
||||
child_sa_t *child_sa;
|
||||
linked_list_t *vips;
|
||||
int i;
|
||||
|
||||
entry = this->sas->get(this->sas, ike_sa->get_id(ike_sa));
|
||||
if (entry)
|
||||
{
|
||||
vips = linked_list_create_from_enumerator(
|
||||
ike_sa->create_virtual_ip_enumerator(ike_sa, local));
|
||||
for (i = 0; i < array_count(entry->traps); i++)
|
||||
{
|
||||
array_get(entry->traps, i, &child_sa);
|
||||
child_sa->update(child_sa, local, remote, vips,
|
||||
ike_sa->has_condition(ike_sa, COND_NAT_ANY));
|
||||
}
|
||||
vips->destroy(vips);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
METHOD(selinux_listener_t, destroy, void,
|
||||
private_selinux_listener_t *this)
|
||||
{
|
||||
this->sas->destroy(this->sas);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header
|
||||
*/
|
||||
selinux_listener_t *selinux_listener_create()
|
||||
{
|
||||
private_selinux_listener_t *this;
|
||||
|
||||
INIT(this,
|
||||
.public = {
|
||||
.listener = {
|
||||
.ike_updown = _ike_updown,
|
||||
.ike_rekey = _ike_rekey,
|
||||
.ike_update = _ike_update,
|
||||
},
|
||||
.destroy = _destroy,
|
||||
},
|
||||
.sas = hashtable_create(hash, equals, 32),
|
||||
);
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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 selinux_listener selinux_listener
|
||||
* @{ @ingroup selinux
|
||||
*/
|
||||
|
||||
#ifndef SELINUX_LISTENER_H_
|
||||
#define SELINUX_LISTENER_H_
|
||||
|
||||
#include <bus/listeners/listener.h>
|
||||
|
||||
typedef struct selinux_listener_t selinux_listener_t;
|
||||
|
||||
/**
|
||||
* Listener to manage trap policies for generic SELinux labels.
|
||||
*/
|
||||
struct selinux_listener_t {
|
||||
|
||||
/**
|
||||
* Implements listener_t interface.
|
||||
*/
|
||||
listener_t listener;
|
||||
|
||||
/**
|
||||
* Destroy a selinux_listener_t.
|
||||
*/
|
||||
void (*destroy)(selinux_listener_t *this);
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a listener instance.
|
||||
*/
|
||||
selinux_listener_t *selinux_listener_create();
|
||||
|
||||
#endif /** SELINUX_LISTENER_H_ @}*/
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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.
|
||||
*/
|
||||
|
||||
#include "selinux_plugin.h"
|
||||
#include "selinux_listener.h"
|
||||
|
||||
#include <daemon.h>
|
||||
|
||||
typedef struct private_selinux_plugin_t private_selinux_plugin_t;
|
||||
|
||||
/**
|
||||
* Private data
|
||||
*/
|
||||
struct private_selinux_plugin_t {
|
||||
|
||||
/**
|
||||
* Public interface
|
||||
*/
|
||||
selinux_plugin_t public;
|
||||
|
||||
/**
|
||||
* Listener
|
||||
*/
|
||||
selinux_listener_t *listener;
|
||||
};
|
||||
|
||||
METHOD(plugin_t, get_name, char*,
|
||||
private_selinux_plugin_t *this)
|
||||
{
|
||||
return "selinux";
|
||||
}
|
||||
|
||||
/**
|
||||
* Register handler
|
||||
*/
|
||||
static bool plugin_cb(private_selinux_plugin_t *this,
|
||||
plugin_feature_t *feature, bool reg, void *cb_data)
|
||||
{
|
||||
if (reg)
|
||||
{
|
||||
charon->bus->add_listener(charon->bus, &this->listener->listener);
|
||||
}
|
||||
else
|
||||
{
|
||||
charon->bus->remove_listener(charon->bus, &this->listener->listener);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
METHOD(plugin_t, get_features, int,
|
||||
private_selinux_plugin_t *this, plugin_feature_t *features[])
|
||||
{
|
||||
static plugin_feature_t f[] = {
|
||||
PLUGIN_CALLBACK((plugin_feature_callback_t)plugin_cb, NULL),
|
||||
PLUGIN_PROVIDE(CUSTOM, "selinux"),
|
||||
};
|
||||
*features = f;
|
||||
return countof(f);
|
||||
}
|
||||
|
||||
METHOD(plugin_t, destroy, void,
|
||||
private_selinux_plugin_t *this)
|
||||
{
|
||||
this->listener->destroy(this->listener);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header
|
||||
*/
|
||||
plugin_t *selinux_plugin_create()
|
||||
{
|
||||
private_selinux_plugin_t *this;
|
||||
|
||||
INIT(this,
|
||||
.public = {
|
||||
.plugin = {
|
||||
.get_name = _get_name,
|
||||
.get_features = _get_features,
|
||||
.destroy = _destroy,
|
||||
},
|
||||
},
|
||||
.listener = selinux_listener_create(),
|
||||
);
|
||||
|
||||
return &this->public.plugin;
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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 selinux selinux
|
||||
* @ingroup cplugins
|
||||
*
|
||||
* @defgroup selinux_plugin selinux_plugin
|
||||
* @{ @ingroup selinux
|
||||
*/
|
||||
|
||||
#ifndef SELINUX_PLUGIN_H_
|
||||
#define SELINUX_PLUGIN_H_
|
||||
|
||||
#include <plugins/plugin.h>
|
||||
|
||||
typedef struct selinux_plugin_t selinux_plugin_t;
|
||||
|
||||
/**
|
||||
* Plugin managing trap policies with generic SELinux labels.
|
||||
*/
|
||||
struct selinux_plugin_t {
|
||||
|
||||
/**
|
||||
* Implements plugin interface
|
||||
*/
|
||||
plugin_t plugin;
|
||||
};
|
||||
|
||||
#endif /** SELINUX_PLUGIN_H_ @}*/
|
||||
Reference in New Issue
Block a user