|
@@ -13,6 +13,11 @@
|
|
*
|
|
*
|
|
* Added conditional policy language extensions
|
|
* Added conditional policy language extensions
|
|
*
|
|
*
|
|
|
|
+ * Updated: Hewlett-Packard <paul.moore@hp.com>
|
|
|
|
+ *
|
|
|
|
+ * Added support for NetLabel
|
|
|
|
+ *
|
|
|
|
+ * Copyright (C) 2006 Hewlett-Packard Development Company, L.P.
|
|
* Copyright (C) 2004-2006 Trusted Computer Solutions, Inc.
|
|
* Copyright (C) 2004-2006 Trusted Computer Solutions, Inc.
|
|
* Copyright (C) 2003 - 2004 Tresys Technology, LLC
|
|
* Copyright (C) 2003 - 2004 Tresys Technology, LLC
|
|
* Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com>
|
|
* Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com>
|
|
@@ -29,6 +34,8 @@
|
|
#include <linux/sched.h>
|
|
#include <linux/sched.h>
|
|
#include <linux/audit.h>
|
|
#include <linux/audit.h>
|
|
#include <linux/mutex.h>
|
|
#include <linux/mutex.h>
|
|
|
|
+#include <net/sock.h>
|
|
|
|
+#include <net/netlabel.h>
|
|
|
|
|
|
#include "flask.h"
|
|
#include "flask.h"
|
|
#include "avc.h"
|
|
#include "avc.h"
|
|
@@ -40,6 +47,8 @@
|
|
#include "services.h"
|
|
#include "services.h"
|
|
#include "conditional.h"
|
|
#include "conditional.h"
|
|
#include "mls.h"
|
|
#include "mls.h"
|
|
|
|
+#include "objsec.h"
|
|
|
|
+#include "selinux_netlabel.h"
|
|
|
|
|
|
extern void selnl_notify_policyload(u32 seqno);
|
|
extern void selnl_notify_policyload(u32 seqno);
|
|
unsigned int policydb_loaded_version;
|
|
unsigned int policydb_loaded_version;
|
|
@@ -1241,6 +1250,7 @@ int security_load_policy(void *data, size_t len)
|
|
selinux_complete_init();
|
|
selinux_complete_init();
|
|
avc_ss_reset(seqno);
|
|
avc_ss_reset(seqno);
|
|
selnl_notify_policyload(seqno);
|
|
selnl_notify_policyload(seqno);
|
|
|
|
+ selinux_netlbl_cache_invalidate();
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -1295,6 +1305,7 @@ int security_load_policy(void *data, size_t len)
|
|
|
|
|
|
avc_ss_reset(seqno);
|
|
avc_ss_reset(seqno);
|
|
selnl_notify_policyload(seqno);
|
|
selnl_notify_policyload(seqno);
|
|
|
|
+ selinux_netlbl_cache_invalidate();
|
|
|
|
|
|
return 0;
|
|
return 0;
|
|
|
|
|
|
@@ -2133,3 +2144,480 @@ void selinux_audit_set_callback(int (*callback)(void))
|
|
{
|
|
{
|
|
aurule_callback = callback;
|
|
aurule_callback = callback;
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+#ifdef CONFIG_NETLABEL
|
|
|
|
+/*
|
|
|
|
+ * This is the structure we store inside the NetLabel cache block.
|
|
|
|
+ */
|
|
|
|
+#define NETLBL_CACHE(x) ((struct netlbl_cache *)(x))
|
|
|
|
+#define NETLBL_CACHE_T_NONE 0
|
|
|
|
+#define NETLBL_CACHE_T_SID 1
|
|
|
|
+#define NETLBL_CACHE_T_MLS 2
|
|
|
|
+struct netlbl_cache {
|
|
|
|
+ u32 type;
|
|
|
|
+ union {
|
|
|
|
+ u32 sid;
|
|
|
|
+ struct mls_range mls_label;
|
|
|
|
+ } data;
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * selinux_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 selinux_netlbl_cache_free(const void *data)
|
|
|
|
+{
|
|
|
|
+ struct netlbl_cache *cache = NETLBL_CACHE(data);
|
|
|
|
+ switch (cache->type) {
|
|
|
|
+ case NETLBL_CACHE_T_MLS:
|
|
|
|
+ ebitmap_destroy(&cache->data.mls_label.level[0].cat);
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ kfree(data);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * selinux_netlbl_cache_add - Add an entry to the NetLabel cache
|
|
|
|
+ * @skb: the packet
|
|
|
|
+ * @ctx: the SELinux context
|
|
|
|
+ *
|
|
|
|
+ * Description:
|
|
|
|
+ * Attempt to cache the context in @ctx, which was derived from the packet in
|
|
|
|
+ * @skb, in the NetLabel subsystem cache.
|
|
|
|
+ *
|
|
|
|
+ */
|
|
|
|
+static void selinux_netlbl_cache_add(struct sk_buff *skb, struct context *ctx)
|
|
|
|
+{
|
|
|
|
+ struct netlbl_cache *cache = NULL;
|
|
|
|
+ struct netlbl_lsm_secattr secattr;
|
|
|
|
+
|
|
|
|
+ netlbl_secattr_init(&secattr);
|
|
|
|
+
|
|
|
|
+ cache = kzalloc(sizeof(*cache), GFP_ATOMIC);
|
|
|
|
+ if (cache == NULL)
|
|
|
|
+ goto netlbl_cache_add_failure;
|
|
|
|
+ secattr.cache.free = selinux_netlbl_cache_free;
|
|
|
|
+ secattr.cache.data = (void *)cache;
|
|
|
|
+
|
|
|
|
+ cache->type = NETLBL_CACHE_T_MLS;
|
|
|
|
+ if (ebitmap_cpy(&cache->data.mls_label.level[0].cat,
|
|
|
|
+ &ctx->range.level[0].cat) != 0)
|
|
|
|
+ goto netlbl_cache_add_failure;
|
|
|
|
+ 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;
|
|
|
|
+
|
|
|
|
+ if (netlbl_cache_add(skb, &secattr) != 0)
|
|
|
|
+ goto netlbl_cache_add_failure;
|
|
|
|
+
|
|
|
|
+ return;
|
|
|
|
+
|
|
|
|
+netlbl_cache_add_failure:
|
|
|
|
+ netlbl_secattr_destroy(&secattr, 1);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * selinux_netlbl_cache_invalidate - Invalidate the NetLabel cache
|
|
|
|
+ *
|
|
|
|
+ * Description:
|
|
|
|
+ * Invalidate the NetLabel security attribute mapping cache.
|
|
|
|
+ *
|
|
|
|
+ */
|
|
|
|
+void selinux_netlbl_cache_invalidate(void)
|
|
|
|
+{
|
|
|
|
+ netlbl_cache_invalidate();
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * selinux_netlbl_secattr_to_sid - Convert a NetLabel secattr to a SELinux SID
|
|
|
|
+ * @skb: the network packet
|
|
|
|
+ * @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 packet 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 @skb
|
|
|
|
+ * is not NULL attempt to cache as much data as possibile. Returns zero on
|
|
|
|
+ * success, negative values on failure.
|
|
|
|
+ *
|
|
|
|
+ */
|
|
|
|
+static int selinux_netlbl_secattr_to_sid(struct sk_buff *skb,
|
|
|
|
+ struct netlbl_lsm_secattr *secattr,
|
|
|
|
+ u32 base_sid,
|
|
|
|
+ u32 *sid)
|
|
|
|
+{
|
|
|
|
+ int rc = -EIDRM;
|
|
|
|
+ struct context *ctx;
|
|
|
|
+ struct context ctx_new;
|
|
|
|
+ struct netlbl_cache *cache;
|
|
|
|
+
|
|
|
|
+ POLICY_RDLOCK;
|
|
|
|
+
|
|
|
|
+ if (secattr->cache.data) {
|
|
|
|
+ cache = NETLBL_CACHE(secattr->cache.data);
|
|
|
|
+ switch (cache->type) {
|
|
|
|
+ case NETLBL_CACHE_T_SID:
|
|
|
|
+ *sid = cache->data.sid;
|
|
|
|
+ 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->mls_lvl_vld) {
|
|
|
|
+ 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;
|
|
|
|
+ mls_import_lvl(&ctx_new, secattr->mls_lvl, secattr->mls_lvl);
|
|
|
|
+ if (secattr->mls_cat) {
|
|
|
|
+ if (mls_import_cat(&ctx_new,
|
|
|
|
+ secattr->mls_cat,
|
|
|
|
+ secattr->mls_cat_len,
|
|
|
|
+ NULL,
|
|
|
|
+ 0) != 0)
|
|
|
|
+ goto netlbl_secattr_to_sid_return;
|
|
|
|
+ ctx_new.range.level[1].cat.highbit =
|
|
|
|
+ ctx_new.range.level[0].cat.highbit;
|
|
|
|
+ ctx_new.range.level[1].cat.node =
|
|
|
|
+ ctx_new.range.level[0].cat.node;
|
|
|
|
+ } else {
|
|
|
|
+ ebitmap_init(&ctx_new.range.level[0].cat);
|
|
|
|
+ ebitmap_init(&ctx_new.range.level[1].cat);
|
|
|
|
+ }
|
|
|
|
+ if (mls_context_isvalid(&policydb, &ctx_new) != 1)
|
|
|
|
+ goto netlbl_secattr_to_sid_return_cleanup;
|
|
|
|
+
|
|
|
|
+ rc = sidtab_context_to_sid(&sidtab, &ctx_new, sid);
|
|
|
|
+ if (rc != 0)
|
|
|
|
+ goto netlbl_secattr_to_sid_return_cleanup;
|
|
|
|
+
|
|
|
|
+ if (skb != NULL)
|
|
|
|
+ selinux_netlbl_cache_add(skb, &ctx_new);
|
|
|
|
+ ebitmap_destroy(&ctx_new.range.level[0].cat);
|
|
|
|
+ } else {
|
|
|
|
+ *sid = SECINITSID_UNLABELED;
|
|
|
|
+ rc = 0;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+netlbl_secattr_to_sid_return:
|
|
|
|
+ POLICY_RDUNLOCK;
|
|
|
|
+ return rc;
|
|
|
|
+netlbl_secattr_to_sid_return_cleanup:
|
|
|
|
+ ebitmap_destroy(&ctx_new.range.level[0].cat);
|
|
|
|
+ goto netlbl_secattr_to_sid_return;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * selinux_netlbl_skbuff_getsid - Get the sid of a packet using NetLabel
|
|
|
|
+ * @skb: the packet
|
|
|
|
+ * @base_sid: the SELinux SID to use as a context for MLS only attributes
|
|
|
|
+ * @sid: the SID
|
|
|
|
+ *
|
|
|
|
+ * Description:
|
|
|
|
+ * Call the NetLabel mechanism to get the security attributes of the given
|
|
|
|
+ * packet and use those attributes to determine the correct context/SID to
|
|
|
|
+ * assign to the packet. Returns zero on success, negative values on failure.
|
|
|
|
+ *
|
|
|
|
+ */
|
|
|
|
+static int selinux_netlbl_skbuff_getsid(struct sk_buff *skb,
|
|
|
|
+ u32 base_sid,
|
|
|
|
+ u32 *sid)
|
|
|
|
+{
|
|
|
|
+ int rc;
|
|
|
|
+ struct netlbl_lsm_secattr secattr;
|
|
|
|
+
|
|
|
|
+ netlbl_secattr_init(&secattr);
|
|
|
|
+ rc = netlbl_skbuff_getattr(skb, &secattr);
|
|
|
|
+ if (rc == 0)
|
|
|
|
+ rc = selinux_netlbl_secattr_to_sid(skb,
|
|
|
|
+ &secattr,
|
|
|
|
+ base_sid,
|
|
|
|
+ sid);
|
|
|
|
+ netlbl_secattr_destroy(&secattr, 0);
|
|
|
|
+
|
|
|
|
+ return rc;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * selinux_netlbl_socket_setsid - Label a socket using the NetLabel mechanism
|
|
|
|
+ * @sock: the socket to label
|
|
|
|
+ * @sid: the SID to use
|
|
|
|
+ *
|
|
|
|
+ * Description:
|
|
|
|
+ * Attempt to label a socket using the NetLabel mechanism using the given
|
|
|
|
+ * SID. Returns zero values on success, negative values on failure.
|
|
|
|
+ *
|
|
|
|
+ */
|
|
|
|
+static int selinux_netlbl_socket_setsid(struct socket *sock, u32 sid)
|
|
|
|
+{
|
|
|
|
+ int rc = -ENOENT;
|
|
|
|
+ struct sk_security_struct *sksec = sock->sk->sk_security;
|
|
|
|
+ struct netlbl_lsm_secattr secattr;
|
|
|
|
+ struct context *ctx;
|
|
|
|
+
|
|
|
|
+ if (!ss_initialized)
|
|
|
|
+ return 0;
|
|
|
|
+
|
|
|
|
+ POLICY_RDLOCK;
|
|
|
|
+
|
|
|
|
+ ctx = sidtab_search(&sidtab, sid);
|
|
|
|
+ if (ctx == NULL)
|
|
|
|
+ goto netlbl_socket_setsid_return;
|
|
|
|
+
|
|
|
|
+ netlbl_secattr_init(&secattr);
|
|
|
|
+ secattr.domain = kstrdup(policydb.p_type_val_to_name[ctx->type - 1],
|
|
|
|
+ GFP_ATOMIC);
|
|
|
|
+ mls_export_lvl(ctx, &secattr.mls_lvl, NULL);
|
|
|
|
+ secattr.mls_lvl_vld = 1;
|
|
|
|
+ mls_export_cat(ctx,
|
|
|
|
+ &secattr.mls_cat,
|
|
|
|
+ &secattr.mls_cat_len,
|
|
|
|
+ NULL,
|
|
|
|
+ NULL);
|
|
|
|
+
|
|
|
|
+ rc = netlbl_socket_setattr(sock, &secattr);
|
|
|
|
+ if (rc == 0)
|
|
|
|
+ sksec->nlbl_state = NLBL_LABELED;
|
|
|
|
+
|
|
|
|
+ netlbl_secattr_destroy(&secattr, 0);
|
|
|
|
+
|
|
|
|
+netlbl_socket_setsid_return:
|
|
|
|
+ POLICY_RDUNLOCK;
|
|
|
|
+ return rc;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * selinux_netlbl_socket_post_create - Label a socket using NetLabel
|
|
|
|
+ * @sock: the socket to label
|
|
|
|
+ * @sock_family: the socket family
|
|
|
|
+ * @sid: the SID to use
|
|
|
|
+ *
|
|
|
|
+ * Description:
|
|
|
|
+ * Attempt to label a socket using the NetLabel mechanism using the given
|
|
|
|
+ * SID. Returns zero values on success, negative values on failure.
|
|
|
|
+ *
|
|
|
|
+ */
|
|
|
|
+int selinux_netlbl_socket_post_create(struct socket *sock,
|
|
|
|
+ int sock_family,
|
|
|
|
+ u32 sid)
|
|
|
|
+{
|
|
|
|
+ struct inode_security_struct *isec = SOCK_INODE(sock)->i_security;
|
|
|
|
+ struct sk_security_struct *sksec = sock->sk->sk_security;
|
|
|
|
+
|
|
|
|
+ if (sock_family != PF_INET)
|
|
|
|
+ return 0;
|
|
|
|
+
|
|
|
|
+ sksec->sclass = isec->sclass;
|
|
|
|
+ sksec->nlbl_state = NLBL_REQUIRE;
|
|
|
|
+ return selinux_netlbl_socket_setsid(sock, sid);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * selinux_netlbl_sock_graft - Netlabel the new socket
|
|
|
|
+ * @sk: the new connection
|
|
|
|
+ * @sock: the new socket
|
|
|
|
+ *
|
|
|
|
+ * Description:
|
|
|
|
+ * The connection represented by @sk is being grafted onto @sock so set the
|
|
|
|
+ * socket's NetLabel to match the SID of @sk.
|
|
|
|
+ *
|
|
|
|
+ */
|
|
|
|
+void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock)
|
|
|
|
+{
|
|
|
|
+ struct inode_security_struct *isec = SOCK_INODE(sock)->i_security;
|
|
|
|
+ struct sk_security_struct *sksec = sk->sk_security;
|
|
|
|
+
|
|
|
|
+ if (sk->sk_family != PF_INET)
|
|
|
|
+ return;
|
|
|
|
+
|
|
|
|
+ sksec->nlbl_state = NLBL_REQUIRE;
|
|
|
|
+ sksec->peer_sid = sksec->sid;
|
|
|
|
+ sksec->sclass = isec->sclass;
|
|
|
|
+
|
|
|
|
+ /* Try to set the NetLabel on the socket to save time later, if we fail
|
|
|
|
+ * here we will pick up the pieces in later calls to
|
|
|
|
+ * selinux_netlbl_inode_permission(). */
|
|
|
|
+ selinux_netlbl_socket_setsid(sock, sksec->sid);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * selinux_netlbl_inet_conn_request - Handle a new connection request
|
|
|
|
+ * @skb: the packet
|
|
|
|
+ * @sock_sid: the SID of the parent socket
|
|
|
|
+ *
|
|
|
|
+ * Description:
|
|
|
|
+ * If present, use the security attributes of the packet in @skb and the
|
|
|
|
+ * parent sock's SID to arrive at a SID for the new child sock. Returns the
|
|
|
|
+ * SID of the connection or SECSID_NULL on failure.
|
|
|
|
+ *
|
|
|
|
+ */
|
|
|
|
+u32 selinux_netlbl_inet_conn_request(struct sk_buff *skb, u32 sock_sid)
|
|
|
|
+{
|
|
|
|
+ int rc;
|
|
|
|
+ u32 peer_sid;
|
|
|
|
+
|
|
|
|
+ rc = selinux_netlbl_skbuff_getsid(skb, sock_sid, &peer_sid);
|
|
|
|
+ if (rc != 0)
|
|
|
|
+ return SECSID_NULL;
|
|
|
|
+
|
|
|
|
+ if (peer_sid == SECINITSID_UNLABELED)
|
|
|
|
+ return SECSID_NULL;
|
|
|
|
+
|
|
|
|
+ return peer_sid;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * __selinux_netlbl_inode_permission - Label a socket using NetLabel
|
|
|
|
+ * @inode: the file descriptor's inode
|
|
|
|
+ * @mask: the permission mask
|
|
|
|
+ *
|
|
|
|
+ * Description:
|
|
|
|
+ * Try to label a socket with the inode's SID using NetLabel. Returns zero on
|
|
|
|
+ * success, negative values on failure.
|
|
|
|
+ *
|
|
|
|
+ */
|
|
|
|
+int __selinux_netlbl_inode_permission(struct inode *inode, int mask)
|
|
|
|
+{
|
|
|
|
+ int rc;
|
|
|
|
+ struct socket *sock = SOCKET_I(inode);
|
|
|
|
+ struct sk_security_struct *sksec = sock->sk->sk_security;
|
|
|
|
+
|
|
|
|
+ lock_sock(sock->sk);
|
|
|
|
+ rc = selinux_netlbl_socket_setsid(sock, sksec->sid);
|
|
|
|
+ release_sock(sock->sk);
|
|
|
|
+
|
|
|
|
+ return rc;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * selinux_netlbl_sock_rcv_skb - Do an inbound access check using NetLabel
|
|
|
|
+ * @sksec: the sock's sk_security_struct
|
|
|
|
+ * @skb: the packet
|
|
|
|
+ * @ad: the audit data
|
|
|
|
+ *
|
|
|
|
+ * Description:
|
|
|
|
+ * Fetch the NetLabel security attributes from @skb and perform an access check
|
|
|
|
+ * against the receiving socket. Returns zero on success, negative values on
|
|
|
|
+ * error.
|
|
|
|
+ *
|
|
|
|
+ */
|
|
|
|
+int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,
|
|
|
|
+ struct sk_buff *skb,
|
|
|
|
+ struct avc_audit_data *ad)
|
|
|
|
+{
|
|
|
|
+ int rc;
|
|
|
|
+ u32 netlbl_sid;
|
|
|
|
+ u32 recv_perm;
|
|
|
|
+
|
|
|
|
+ rc = selinux_netlbl_skbuff_getsid(skb, sksec->sid, &netlbl_sid);
|
|
|
|
+ if (rc != 0)
|
|
|
|
+ return rc;
|
|
|
|
+
|
|
|
|
+ if (netlbl_sid == SECINITSID_UNLABELED)
|
|
|
|
+ return 0;
|
|
|
|
+
|
|
|
|
+ switch (sksec->sclass) {
|
|
|
|
+ case SECCLASS_UDP_SOCKET:
|
|
|
|
+ recv_perm = UDP_SOCKET__RECV_MSG;
|
|
|
|
+ break;
|
|
|
|
+ case SECCLASS_TCP_SOCKET:
|
|
|
|
+ recv_perm = TCP_SOCKET__RECV_MSG;
|
|
|
|
+ break;
|
|
|
|
+ default:
|
|
|
|
+ recv_perm = RAWIP_SOCKET__RECV_MSG;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ rc = avc_has_perm(sksec->sid,
|
|
|
|
+ netlbl_sid,
|
|
|
|
+ sksec->sclass,
|
|
|
|
+ recv_perm,
|
|
|
|
+ ad);
|
|
|
|
+ if (rc == 0)
|
|
|
|
+ return 0;
|
|
|
|
+
|
|
|
|
+ netlbl_skbuff_err(skb, rc);
|
|
|
|
+ return rc;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * selinux_netlbl_socket_peersid - Return the peer SID of a connected socket
|
|
|
|
+ * @sock: the socket
|
|
|
|
+ *
|
|
|
|
+ * Description:
|
|
|
|
+ * Examine @sock to find the connected peer's SID. Returns the SID on success
|
|
|
|
+ * or SECSID_NULL on error.
|
|
|
|
+ *
|
|
|
|
+ */
|
|
|
|
+u32 selinux_netlbl_socket_getpeersec_stream(struct socket *sock)
|
|
|
|
+{
|
|
|
|
+ struct sk_security_struct *sksec = sock->sk->sk_security;
|
|
|
|
+
|
|
|
|
+ if (sksec->peer_sid == SECINITSID_UNLABELED)
|
|
|
|
+ return SECSID_NULL;
|
|
|
|
+
|
|
|
|
+ return sksec->peer_sid;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * selinux_netlbl_socket_getpeersec_dgram - Return the SID of a NetLabel packet
|
|
|
|
+ * @skb: the packet
|
|
|
|
+ *
|
|
|
|
+ * Description:
|
|
|
|
+ * Examine @skb to find the SID assigned to it by NetLabel. Returns the SID on
|
|
|
|
+ * success, SECSID_NULL on error.
|
|
|
|
+ *
|
|
|
|
+ */
|
|
|
|
+u32 selinux_netlbl_socket_getpeersec_dgram(struct sk_buff *skb)
|
|
|
|
+{
|
|
|
|
+ int peer_sid;
|
|
|
|
+ struct sock *sk = skb->sk;
|
|
|
|
+ struct inode_security_struct *isec;
|
|
|
|
+
|
|
|
|
+ if (sk == NULL || sk->sk_socket == NULL)
|
|
|
|
+ return SECSID_NULL;
|
|
|
|
+
|
|
|
|
+ isec = SOCK_INODE(sk->sk_socket)->i_security;
|
|
|
|
+ if (selinux_netlbl_skbuff_getsid(skb, isec->sid, &peer_sid) != 0)
|
|
|
|
+ return SECSID_NULL;
|
|
|
|
+ if (peer_sid == SECINITSID_UNLABELED)
|
|
|
|
+ return SECSID_NULL;
|
|
|
|
+
|
|
|
|
+ return peer_sid;
|
|
|
|
+}
|
|
|
|
+#endif /* CONFIG_NETLABEL */
|