Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5dbe1eb0 authored by Paul Moore's avatar Paul Moore Committed by James Morris
Browse files

SELinux: Allow NetLabel to directly cache SIDs



Now that the SELinux NetLabel "base SID" is always the netmsg initial SID we
can do a big optimization - caching the SID and not just the MLS attributes.
This not only saves a lot of per-packet memory allocations and copies but it
has a nice side effect of removing a chunk of code.

Signed-off-by: default avatarPaul Moore <paul.moore@hp.com>
Signed-off-by: default avatarJames Morris <jmorris@namei.org>
parent d621d35e
Loading
Loading
Loading
Loading
+1 −5
Original line number Diff line number Diff line
@@ -3468,11 +3468,7 @@ static int selinux_skb_peerlbl_sid(struct sk_buff *skb, u16 family, u32 *sid)
	u32 nlbl_type;

	selinux_skb_xfrm_sid(skb, &xfrm_sid);
	selinux_netlbl_skbuff_getsid(skb,
				     family,
				     SECINITSID_NETMSG,
				     &nlbl_type,
				     &nlbl_sid);
	selinux_netlbl_skbuff_getsid(skb, family, &nlbl_type, &nlbl_sid);

	if (security_net_peersid_resolve(nlbl_sid, nlbl_type,
					 xfrm_sid,
+0 −2
Original line number Diff line number Diff line
@@ -48,7 +48,6 @@ void selinux_netlbl_sk_security_clone(struct sk_security_struct *ssec,

int selinux_netlbl_skbuff_getsid(struct sk_buff *skb,
				 u16 family,
				 u32 base_sid,
				 u32 *type,
				 u32 *sid);

@@ -89,7 +88,6 @@ static inline void selinux_netlbl_sk_security_clone(

static inline int selinux_netlbl_skbuff_getsid(struct sk_buff *skb,
					       u16 family,
					       u32 base_sid,
					       u32 *type,
					       u32 *sid)
{
+0 −2
Original line number Diff line number Diff line
@@ -124,7 +124,6 @@ int security_genfs_sid(const char *fstype, char *name, u16 sclass,

#ifdef CONFIG_NETLABEL
int security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr,
				   u32 base_sid,
				   u32 *sid);

int security_netlbl_sid_to_secattr(u32 sid,
@@ -132,7 +131,6 @@ int security_netlbl_sid_to_secattr(u32 sid,
#else
static inline int security_netlbl_secattr_to_sid(
					    struct netlbl_lsm_secattr *secattr,
					    u32 base_sid,
					    u32 *sid)
{
	return -EIDRM;
+34 −21
Original line number Diff line number Diff line
@@ -35,6 +35,33 @@
#include "objsec.h"
#include "security.h"

/**
 * selinux_netlbl_sidlookup_cached - Cache a SID lookup
 * @skb: the packet
 * @secattr: the NetLabel security attributes
 * @sid: the SID
 *
 * Description:
 * Query the SELinux security server to lookup the correct SID for the given
 * security attributes.  If the query is successful, cache the result to speed
 * up future lookups.  Returns zero on success, negative values on failure.
 *
 */
static int selinux_netlbl_sidlookup_cached(struct sk_buff *skb,
					   struct netlbl_lsm_secattr *secattr,
					   u32 *sid)
{
	int rc;

	rc = security_netlbl_secattr_to_sid(secattr, sid);
	if (rc == 0 &&
	    (secattr->flags & NETLBL_SECATTR_CACHEABLE) &&
	    (secattr->flags & NETLBL_SECATTR_CACHE))
		netlbl_cache_add(skb, secattr);

	return rc;
}

/**
 * selinux_netlbl_sock_setsid - Label a socket using the NetLabel mechanism
 * @sk: the socket to label
@@ -144,7 +171,6 @@ void selinux_netlbl_sk_security_clone(struct sk_security_struct *ssec,
 * selinux_netlbl_skbuff_getsid - Get the sid of a packet using NetLabel
 * @skb: the packet
 * @family: protocol family
 * @base_sid: the SELinux SID to use as a context for MLS only attributes
 * @type: NetLabel labeling protocol type
 * @sid: the SID
 *
@@ -156,7 +182,6 @@ void selinux_netlbl_sk_security_clone(struct sk_security_struct *ssec,
 */
int selinux_netlbl_skbuff_getsid(struct sk_buff *skb,
				 u16 family,
				 u32 base_sid,
				 u32 *type,
				 u32 *sid)
{
@@ -170,13 +195,9 @@ int selinux_netlbl_skbuff_getsid(struct sk_buff *skb,

	netlbl_secattr_init(&secattr);
	rc = netlbl_skbuff_getattr(skb, family, &secattr);
	if (rc == 0 && secattr.flags != NETLBL_SECATTR_NONE) {
		rc = security_netlbl_secattr_to_sid(&secattr, base_sid, sid);
		if (rc == 0 &&
		    (secattr.flags & NETLBL_SECATTR_CACHEABLE) &&
		    (secattr.flags & NETLBL_SECATTR_CACHE))
			netlbl_cache_add(skb, &secattr);
	} else
	if (rc == 0 && secattr.flags != NETLBL_SECATTR_NONE)
		rc = selinux_netlbl_sidlookup_cached(skb, &secattr, sid);
	else
		*sid = SECSID_NULL;
	*type = secattr.type;
	netlbl_secattr_destroy(&secattr);
@@ -210,9 +231,7 @@ void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock)
	netlbl_secattr_init(&secattr);
	if (netlbl_sock_getattr(sk, &secattr) == 0 &&
	    secattr.flags != NETLBL_SECATTR_NONE &&
	    security_netlbl_secattr_to_sid(&secattr,
					   SECINITSID_NETMSG,
					   &nlbl_peer_sid) == 0)
	    security_netlbl_secattr_to_sid(&secattr, &nlbl_peer_sid) == 0)
		sksec->peer_sid = nlbl_peer_sid;
	netlbl_secattr_destroy(&secattr);

@@ -316,15 +335,9 @@ int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,

	netlbl_secattr_init(&secattr);
	rc = netlbl_skbuff_getattr(skb, family, &secattr);
	if (rc == 0 && secattr.flags != NETLBL_SECATTR_NONE) {
		rc = security_netlbl_secattr_to_sid(&secattr,
						    SECINITSID_NETMSG,
						    &nlbl_sid);
		if (rc == 0 &&
		    (secattr.flags & NETLBL_SECATTR_CACHEABLE) &&
		    (secattr.flags & NETLBL_SECATTR_CACHE))
			netlbl_cache_add(skb, &secattr);
	} else
	if (rc == 0 && secattr.flags != NETLBL_SECATTR_NONE)
		rc = selinux_netlbl_sidlookup_cached(skb, &secattr, &nlbl_sid);
	else
		nlbl_sid = SECINITSID_UNLABELED;
	netlbl_secattr_destroy(&secattr);
	if (rc != 0)
+20 −104
Original line number Diff line number Diff line
@@ -2547,50 +2547,10 @@ void selinux_audit_set_callback(int (*callback)(void))
}

#ifdef CONFIG_NETLABEL
/*
 * NetLabel cache structure
 */
#define NETLBL_CACHE(x)           ((struct selinux_netlbl_cache *)(x))
#define NETLBL_CACHE_T_NONE       0
#define NETLBL_CACHE_T_SID        1
#define NETLBL_CACHE_T_MLS        2
struct selinux_netlbl_cache {
	u32 type;
	union {
		u32 sid;
		struct mls_range mls_label;
	} data;
};

/**
 * security_netlbl_cache_free - Free the NetLabel cached data
 * @data: the data to free
 *
 * Description:
 * This function is intended to be used as the free() callback inside the
 * netlbl_lsm_cache structure.
 *
 */
static void security_netlbl_cache_free(const void *data)
{
	struct selinux_netlbl_cache *cache;

	if (data == NULL)
		return;

	cache = NETLBL_CACHE(data);
	switch (cache->type) {
	case NETLBL_CACHE_T_MLS:
		ebitmap_destroy(&cache->data.mls_label.level[0].cat);
		break;
	}
	kfree(data);
}

/**
 * security_netlbl_cache_add - Add an entry to the NetLabel cache
 * @secattr: the NetLabel packet security attributes
 * @ctx: the SELinux context
 * @sid: the SELinux SID
 *
 * Description:
 * Attempt to cache the context in @ctx, which was derived from the packet in
@@ -2599,60 +2559,46 @@ static void security_netlbl_cache_free(const void *data)
 *
 */
static void security_netlbl_cache_add(struct netlbl_lsm_secattr *secattr,
				      struct context *ctx)
				      u32 sid)
{
	struct selinux_netlbl_cache *cache = NULL;

	secattr->cache = netlbl_secattr_cache_alloc(GFP_ATOMIC);
	if (secattr->cache == NULL)
		return;
	u32 *sid_cache;

	cache = kzalloc(sizeof(*cache),	GFP_ATOMIC);
	if (cache == NULL)
	sid_cache = kmalloc(sizeof(*sid_cache), GFP_ATOMIC);
	if (sid_cache == NULL)
		return;

	cache->type = NETLBL_CACHE_T_MLS;
	if (ebitmap_cpy(&cache->data.mls_label.level[0].cat,
			&ctx->range.level[0].cat) != 0) {
		kfree(cache);
	secattr->cache = netlbl_secattr_cache_alloc(GFP_ATOMIC);
	if (secattr->cache == NULL) {
		kfree(sid_cache);
		return;
	}
	cache->data.mls_label.level[1].cat.highbit =
		cache->data.mls_label.level[0].cat.highbit;
	cache->data.mls_label.level[1].cat.node =
		cache->data.mls_label.level[0].cat.node;
	cache->data.mls_label.level[0].sens = ctx->range.level[0].sens;
	cache->data.mls_label.level[1].sens = ctx->range.level[0].sens;

	secattr->cache->free = security_netlbl_cache_free;
	secattr->cache->data = (void *)cache;
	*sid_cache = sid;
	secattr->cache->free = kfree;
	secattr->cache->data = sid_cache;
	secattr->flags |= NETLBL_SECATTR_CACHE;
}

/**
 * security_netlbl_secattr_to_sid - Convert a NetLabel secattr to a SELinux SID
 * @secattr: the NetLabel packet security attributes
 * @base_sid: the SELinux SID to use as a context for MLS only attributes
 * @sid: the SELinux SID
 *
 * Description:
 * Convert the given NetLabel security attributes in @secattr into a
 * SELinux SID.  If the @secattr field does not contain a full SELinux
 * SID/context then use the context in @base_sid as the foundation.  If
 * possibile the 'cache' field of @secattr is set and the CACHE flag is set;
 * this is to allow the @secattr to be used by NetLabel to cache the secattr to
 * SID conversion for future lookups.  Returns zero on success, negative
 * values on failure.
 * SID/context then use SECINITSID_NETMSG as the foundation.  If possibile the
 * 'cache' field of @secattr is set and the CACHE flag is set; this is to
 * allow the @secattr to be used by NetLabel to cache the secattr to SID
 * conversion for future lookups.  Returns zero on success, negative values on
 * failure.
 *
 */
int security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr,
				   u32 base_sid,
				   u32 *sid)
{
	int rc = -EIDRM;
	struct context *ctx;
	struct context ctx_new;
	struct selinux_netlbl_cache *cache;

	if (!ss_initialized) {
		*sid = SECSID_NULL;
@@ -2662,43 +2608,13 @@ int security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr,
	POLICY_RDLOCK;

	if (secattr->flags & NETLBL_SECATTR_CACHE) {
		cache = NETLBL_CACHE(secattr->cache->data);
		switch (cache->type) {
		case NETLBL_CACHE_T_SID:
			*sid = cache->data.sid;
		*sid = *(u32 *)secattr->cache->data;
		rc = 0;
			break;
		case NETLBL_CACHE_T_MLS:
			ctx = sidtab_search(&sidtab, base_sid);
			if (ctx == NULL)
				goto netlbl_secattr_to_sid_return;

			ctx_new.user = ctx->user;
			ctx_new.role = ctx->role;
			ctx_new.type = ctx->type;
			ctx_new.range.level[0].sens =
				cache->data.mls_label.level[0].sens;
			ctx_new.range.level[0].cat.highbit =
				cache->data.mls_label.level[0].cat.highbit;
			ctx_new.range.level[0].cat.node =
				cache->data.mls_label.level[0].cat.node;
			ctx_new.range.level[1].sens =
				cache->data.mls_label.level[1].sens;
			ctx_new.range.level[1].cat.highbit =
				cache->data.mls_label.level[1].cat.highbit;
			ctx_new.range.level[1].cat.node =
				cache->data.mls_label.level[1].cat.node;

			rc = sidtab_context_to_sid(&sidtab, &ctx_new, sid);
			break;
		default:
			goto netlbl_secattr_to_sid_return;
		}
	} else if (secattr->flags & NETLBL_SECATTR_SECID) {
		*sid = secattr->attr.secid;
		rc = 0;
	} else if (secattr->flags & NETLBL_SECATTR_MLS_LVL) {
		ctx = sidtab_search(&sidtab, base_sid);
		ctx = sidtab_search(&sidtab, SECINITSID_NETMSG);
		if (ctx == NULL)
			goto netlbl_secattr_to_sid_return;

@@ -2725,7 +2641,7 @@ int security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr,
		if (rc != 0)
			goto netlbl_secattr_to_sid_return_cleanup;

		security_netlbl_cache_add(secattr, &ctx_new);
		security_netlbl_cache_add(secattr, *sid);

		ebitmap_destroy(&ctx_new.range.level[0].cat);
	} else {