All of lore.kernel.org
 help / color / mirror / Atom feed
From: Paul Moore <paul.moore@hp.com>
To: selinux@tycho.nsa.gov, linux-security-module@vger.kernel.org
Cc: vyekkirala@TrustedCS.com, chanson@TrustedCS.com
Subject: [RFC PATCH v8 18/18] SELinux: Add network ingress and egress control permission checks
Date: Fri, 14 Dec 2007 16:51:29 -0500	[thread overview]
Message-ID: <20071214215129.10069.75156.stgit@flek.lan> (raw)
In-Reply-To: <20071214213548.10069.59135.stgit@flek.lan>

This patch implements packet ingress/egress controls for SELinux which allow
SELinux security policy to control the flow of all IPv4 and IPv6 packets into
and out of the system.  Currently SELinux does not have proper control over
forwarded packets and this patch corrects this problem.

Special thanks to Venkat Yekkirala <vyekkirala@trustedcs.com> whose earlier
work on this topic eventually led to this patch.
---

 security/selinux/hooks.c |  335 +++++++++++++++++++++++++++++++---------------
 1 files changed, 228 insertions(+), 107 deletions(-)

diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 2f221b2..2a6d50f 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -12,8 +12,8 @@
  *  Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com>
  *  Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
  *                          <dgoeddel@trustedcs.com>
- *  Copyright (C) 2006 Hewlett-Packard Development Company, L.P.
- *                     Paul Moore, <paul.moore@hp.com>
+ *  Copyright (C) 2006, 2007 Hewlett-Packard Development Company, L.P.
+ *                     Paul Moore <paul.moore@hp.com>
  *  Copyright (C) 2007 Hitachi Software Engineering Co., Ltd.
  *                     Yuichi Nakamura <ynakam@hitachisoft.jp>
  *
@@ -3608,6 +3608,71 @@ static int selinux_socket_unix_may_send(struct socket *sock,
 	return 0;
 }
 
+static int selinux_inet_sys_rcv_skb(int ifindex, char *addrp, u16 family,
+				    u32 peer_sid,
+				    struct avc_audit_data *ad)
+{
+	int err;
+	u32 if_sid;
+	u32 node_sid;
+
+	err = sel_netif_sid(ifindex, &if_sid);
+	if (err)
+		return err;
+	err = avc_has_perm(if_sid, peer_sid, SECCLASS_PEER, PEER__INGRESS, ad);
+	if (err)
+		return err;
+
+	err = sel_netnode_sid(addrp, family, &node_sid);
+	if (err)
+		return err;
+	return avc_has_perm(node_sid, peer_sid,
+			    SECCLASS_PEER, PEER__INGRESS, ad);
+}
+
+static int selinux_inet_sys_snd_skb(struct sk_buff *skb, int family)
+{
+	int err = 0;
+
+	if (!selinux_policycap_netpeer)
+		return 0;
+
+	if (netlbl_enabled() || selinux_xfrm_enabled()) {
+		u32 if_sid;
+		u32 node_sid;
+		u32 peer_sid;
+		char *addrp;
+		struct avc_audit_data ad;
+
+		AVC_AUDIT_DATA_INIT(&ad, NET);
+		ad.u.net.netif = skb->iif;
+		ad.u.net.family = family;
+		err = selinux_parse_skb(skb, &ad, &addrp, 0, NULL);
+		if (err)
+			return err;
+
+		err = selinux_skb_peerlbl_sid(skb, family, &peer_sid);
+		if (err)
+			return err;
+
+		err = sel_netif_sid(skb->iif, &if_sid);
+		if (err)
+			return err;
+		err = avc_has_perm(if_sid, peer_sid,
+				   SECCLASS_PEER, PEER__EGRESS, &ad);
+		if (err)
+			return err;
+
+		err = sel_netnode_sid(addrp, family, &node_sid);
+		if (err)
+			return err;
+		err = avc_has_perm(node_sid, peer_sid,
+				   SECCLASS_PEER, PEER__EGRESS, &ad);
+	}
+
+	return err;
+}
+
 static int selinux_sock_rcv_skb_iptables_compat(struct sock *sk,
 						struct sk_buff *skb,
 						struct avc_audit_data *ad,
@@ -3748,6 +3813,10 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
 		err = selinux_skb_peerlbl_sid(skb, family, &peer_sid);
 		if (err)
 			return err;
+		err = selinux_inet_sys_rcv_skb(skb->iif, addrp, family,
+					       peer_sid, &ad);
+		if (err)
+			return err;
 		err = avc_has_perm(sk_sid, peer_sid, SECCLASS_PEER,
 				   PEER__RECV, &ad);
 	}
@@ -3965,151 +4034,175 @@ out:
 
 #ifdef CONFIG_NETFILTER
 
-static int selinux_ip_postroute_last_compat(struct sock *sk,
-					    struct net_device *dev,
-					    struct avc_audit_data *ad,
-					    u16 family,
-					    char *addrp)
+static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex,
+				       u16 family)
 {
-	int err = 0;
-	u32 netif_perm, node_perm, node_sid, if_sid, send_perm = 0;
-	struct socket *sock;
-	struct inode *inode;
-	struct inode_security_struct *isec;
+	if (!selinux_policycap_netpeer)
+		return NF_ACCEPT;
 
-	sock = sk->sk_socket;
-	if (!sock)
-		goto out;
+	if (netlbl_enabled() || selinux_xfrm_enabled()) {
+		char *addrp;
+		u32 peer_sid;
+		struct avc_audit_data ad;
 
-	inode = SOCK_INODE(sock);
-	if (!inode)
-		goto out;
+		AVC_AUDIT_DATA_INIT(&ad, NET);
+		ad.u.net.netif = ifindex;
+		ad.u.net.family = family;
+		if (selinux_parse_skb(skb, &ad, &addrp, 1, NULL) != 0)
+			return NF_DROP;
+
+		if (selinux_skb_peerlbl_sid(skb, family, &peer_sid) != 0)
+			return NF_DROP;
+		if (selinux_inet_sys_rcv_skb(ifindex, addrp, family,
+					     peer_sid, &ad) != 0)
+			return NF_DROP;
+	}
 
-	isec = inode->i_security;
-	
-	err = sel_netif_sid(dev->ifindex, &if_sid);
-	if (err)
-		goto out;
+	return NF_ACCEPT;
+}
+
+static unsigned int selinux_ipv4_forward(unsigned int hooknum,
+					 struct sk_buff *skb,
+					 const struct net_device *in,
+					 const struct net_device *out,
+					 int (*okfn)(struct sk_buff *))
+{
+	return selinux_ip_forward(skb, in->ifindex, PF_INET);
+}
+
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+static unsigned int selinux_ipv6_forward(unsigned int hooknum,
+					 struct sk_buff *skb,
+					 const struct net_device *in,
+					 const struct net_device *out,
+					 int (*okfn)(struct sk_buff *))
+{
+	return selinux_ip_forward(skb, in->ifindex, PF_INET6);
+}
+#endif	/* IPV6 */
 
-	switch (isec->sclass) {
+static int selinux_ip_postroute_compat(struct sock *sk,
+				       int ifindex,
+				       struct avc_audit_data *ad,
+				       u16 family, char *addrp)
+{
+	int err;
+	struct sk_security_struct *sksec = sk->sk_security;
+	u16 sk_class;
+	u32 netif_perm, node_perm, send_perm;
+	u32 port_sid, node_sid, if_sid, sk_sid;
+
+	sk_sid = sksec->sid;
+	sk_class = sksec->sclass;
+
+	switch (sk_class) {
 	case SECCLASS_UDP_SOCKET:
 		netif_perm = NETIF__UDP_SEND;
 		node_perm = NODE__UDP_SEND;
 		send_perm = UDP_SOCKET__SEND_MSG;
 		break;
-	
 	case SECCLASS_TCP_SOCKET:
 		netif_perm = NETIF__TCP_SEND;
 		node_perm = NODE__TCP_SEND;
 		send_perm = TCP_SOCKET__SEND_MSG;
 		break;
-
 	case SECCLASS_DCCP_SOCKET:
 		netif_perm = NETIF__DCCP_SEND;
 		node_perm = NODE__DCCP_SEND;
 		send_perm = DCCP_SOCKET__SEND_MSG;
 		break;
-
 	default:
 		netif_perm = NETIF__RAWIP_SEND;
 		node_perm = NODE__RAWIP_SEND;
+		send_perm = 0;
 		break;
 	}
 
-	err = avc_has_perm(isec->sid, if_sid, SECCLASS_NETIF, netif_perm, ad);
+	err = sel_netif_sid(ifindex, &if_sid);
 	if (err)
-		goto out;
+		return err;
+	err = avc_has_perm(sk_sid, if_sid, SECCLASS_NETIF, netif_perm, ad);
+	if (err)
+		return err;
 		
 	err = sel_netnode_sid(addrp, family, &node_sid);
 	if (err)
-		goto out;
-	
-	err = avc_has_perm(isec->sid, node_sid, SECCLASS_NODE, node_perm, ad);
+		return err;
+	err = avc_has_perm(sk_sid, node_sid, SECCLASS_NODE, node_perm, ad);
 	if (err)
-		goto out;
-
-	if (send_perm) {
-		u32 port_sid;
-		
-		err = security_port_sid(sk->sk_family,
-		                        sk->sk_type,
-		                        sk->sk_protocol,
-		                        ntohs(ad->u.net.dport),
-		                        &port_sid);
-		if (err)
-			goto out;
+		return err;
 
-		err = avc_has_perm(isec->sid, port_sid, isec->sclass,
-				   send_perm, ad);
-	}
-out:
-	return err;
+	if (!send_perm)
+		return 0;
+	err = security_port_sid(sk->sk_family, sk->sk_type,
+				sk->sk_protocol, ntohs(ad->u.net.dport),
+				&port_sid);
+	if (err)
+		return err;
+	return avc_has_perm(sk_sid, port_sid, sk_class, send_perm, ad);
 }
 
-static unsigned int selinux_ip_postroute_last(unsigned int hooknum,
-                                              struct sk_buff *skb,
-                                              const struct net_device *in,
-                                              const struct net_device *out,
-                                              int (*okfn)(struct sk_buff *),
-                                              u16 family)
+static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
+					 u16 family)
 {
-	char *addrp;
-	int err = 0;
+	int err;
 	struct sock *sk;
-	struct avc_audit_data ad;
-	struct net_device *dev = (struct net_device *)out;
 	struct sk_security_struct *sksec;
+	struct avc_audit_data ad;
+	char *addrp;
 	u8 proto;
 
 	sk = skb->sk;
 	if (!sk)
-		goto out;
-
+		return NF_ACCEPT;
 	sksec = sk->sk_security;
 
 	AVC_AUDIT_DATA_INIT(&ad, NET);
-	ad.u.net.netif = dev->ifindex;
+	ad.u.net.netif = ifindex;
 	ad.u.net.family = family;
-
 	err = selinux_parse_skb(skb, &ad, &addrp, 0, &proto);
 	if (err)
-		goto out;
+		return NF_DROP;
 
 	if (selinux_compat_net)
-		err = selinux_ip_postroute_last_compat(sk, dev, &ad,
-						       family, addrp);
+		err = selinux_ip_postroute_compat(sk, ifindex, &ad,
+						  family, addrp);
 	else
 		err = avc_has_perm(sksec->sid, skb->secmark, SECCLASS_PACKET,
 				   PACKET__SEND, &ad);
-
 	if (err)
-		goto out;
+		return NF_DROP;
 
-	err = selinux_xfrm_postroute_last(sksec->sid, skb, &ad, proto);
-out:
-	return err ? NF_DROP : NF_ACCEPT;
+	if (!selinux_policycap_netpeer) {
+		/* If the network peer controls are enabled we handle all the
+		 * outbound peer label access checks in the
+		 * selinux_inet_sys_snd_skb() hook. */
+		err = selinux_xfrm_postroute_last(sksec->sid, skb, &ad, proto);
+		if (err)
+			return NF_DROP;
+	}
+
+	return NF_ACCEPT;
 }
 
-static unsigned int selinux_ipv4_postroute_last(unsigned int hooknum,
-						struct sk_buff *skb,
-						const struct net_device *in,
-						const struct net_device *out,
-						int (*okfn)(struct sk_buff *))
+static unsigned int selinux_ipv4_postroute(unsigned int hooknum,
+					   struct sk_buff *skb,
+					   const struct net_device *in,
+					   const struct net_device *out,
+					   int (*okfn)(struct sk_buff *))
 {
-	return selinux_ip_postroute_last(hooknum, skb, in, out, okfn, PF_INET);
+	return selinux_ip_postroute(skb, out->ifindex, PF_INET);
 }
 
 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
-
-static unsigned int selinux_ipv6_postroute_last(unsigned int hooknum,
-						struct sk_buff *skb,
-						const struct net_device *in,
-						const struct net_device *out,
-						int (*okfn)(struct sk_buff *))
+static unsigned int selinux_ipv6_postroute(unsigned int hooknum,
+					   struct sk_buff *skb,
+					   const struct net_device *in,
+					   const struct net_device *out,
+					   int (*okfn)(struct sk_buff *))
 {
-	return selinux_ip_postroute_last(hooknum, skb, in, out, okfn, PF_INET6);
+	return selinux_ip_postroute(skb, out->ifindex, PF_INET6);
 }
-
 #endif	/* IPV6 */
 
 #endif	/* CONFIG_NETFILTER */
@@ -4991,6 +5084,7 @@ static struct security_operations selinux_ops = {
 	.inet_csk_clone =		selinux_inet_csk_clone,
 	.inet_conn_established =	selinux_inet_conn_established,
 	.req_classify_flow =		selinux_req_classify_flow,
+	.inet_sys_snd_skb =		selinux_inet_sys_snd_skb,
 
 #ifdef CONFIG_SECURITY_NETWORK_XFRM
 	.xfrm_policy_alloc_security =	selinux_xfrm_policy_alloc,
@@ -5094,22 +5188,40 @@ security_initcall(selinux_init);
 
 #if defined(CONFIG_NETFILTER)
 
-static struct nf_hook_ops selinux_ipv4_op = {
-	.hook =		selinux_ipv4_postroute_last,
-	.owner =	THIS_MODULE,
-	.pf =		PF_INET,
-	.hooknum =	NF_IP_POST_ROUTING,
-	.priority =	NF_IP_PRI_SELINUX_LAST,
+static struct nf_hook_ops selinux_ipv4_ops[] = {
+	{
+		.hook =		selinux_ipv4_postroute,
+		.owner =	THIS_MODULE,
+		.pf =		PF_INET,
+		.hooknum =	NF_IP_POST_ROUTING,
+		.priority =	NF_IP_PRI_SELINUX_LAST,
+	},
+	{
+		.hook =		selinux_ipv4_forward,
+		.owner =	THIS_MODULE,
+		.pf =		PF_INET,
+		.hooknum =	NF_IP_FORWARD,
+		.priority =	NF_IP_PRI_SELINUX_FIRST,
+	}
 };
 
 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
 
-static struct nf_hook_ops selinux_ipv6_op = {
-	.hook =		selinux_ipv6_postroute_last,
-	.owner =	THIS_MODULE,
-	.pf =		PF_INET6,
-	.hooknum =	NF_IP6_POST_ROUTING,
-	.priority =	NF_IP6_PRI_SELINUX_LAST,
+static struct nf_hook_ops selinux_ipv6_ops[] = {
+	{
+		.hook =		selinux_ipv6_postroute,
+		.owner =	THIS_MODULE,
+		.pf =		PF_INET6,
+		.hooknum =	NF_IP6_POST_ROUTING,
+		.priority =	NF_IP6_PRI_SELINUX_LAST,
+	},
+	{
+		.hook =		selinux_ipv6_forward,
+		.owner =	THIS_MODULE,
+		.pf =		PF_INET6,
+		.hooknum =	NF_IP6_FORWARD,
+		.priority =	NF_IP6_PRI_SELINUX_FIRST,
+	}
 };
 
 #endif	/* IPV6 */
@@ -5117,22 +5229,27 @@ static struct nf_hook_ops selinux_ipv6_op = {
 static int __init selinux_nf_ip_init(void)
 {
 	int err = 0;
+	u32 iter;
 
 	if (!selinux_enabled)
 		goto out;
 
 	printk(KERN_DEBUG "SELinux:  Registering netfilter hooks\n");
 
-	err = nf_register_hook(&selinux_ipv4_op);
-	if (err)
-		panic("SELinux: nf_register_hook for IPv4: error %d\n", err);
+	for (iter = 0; iter < ARRAY_SIZE(selinux_ipv4_ops); iter++) {
+		err = nf_register_hook(&selinux_ipv4_ops[iter]);
+		if (err)
+			panic("SELinux: nf_register_hook for IPv4: error %d\n",
+			      err);
+	}
 
 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
-
-	err = nf_register_hook(&selinux_ipv6_op);
-	if (err)
-		panic("SELinux: nf_register_hook for IPv6: error %d\n", err);
-
+	for (iter = 0; iter < ARRAY_SIZE(selinux_ipv6_ops); iter++) {
+		err = nf_register_hook(&selinux_ipv6_ops[iter]);
+		if (err)
+			panic("SELinux: nf_register_hook for IPv6: error %d\n",
+			      err);
+	}
 #endif	/* IPV6 */
 
 out:
@@ -5144,11 +5261,15 @@ __initcall(selinux_nf_ip_init);
 #ifdef CONFIG_SECURITY_SELINUX_DISABLE
 static void selinux_nf_ip_exit(void)
 {
+	u32 iter;
+
 	printk(KERN_DEBUG "SELinux:  Unregistering netfilter hooks\n");
 
-	nf_unregister_hook(&selinux_ipv4_op);
+	for (iter = 0; iter < ARRAY_SIZE(selinux_ipv4_ops); iter++)
+		nf_unregister_hook(&selinux_ipv4_ops[iter]);
 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
-	nf_unregister_hook(&selinux_ipv6_op);
+	for (iter = 0; iter < ARRAY_SIZE(selinux_ipv6_ops); iter++)
+		nf_unregister_hook(&selinux_ipv6_ops[iter]);
 #endif	/* IPV6 */
 }
 #endif


--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.

  parent reply	other threads:[~2007-12-14 21:57 UTC|newest]

Thread overview: 38+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2007-12-14 21:49 [RFC PATCH v8 00/18] Update to the labeled networking patches for 2.6.25 Paul Moore
2007-12-14 21:49 ` [RFC PATCH v8 01/18] NetLabel: Remove unneeded RCU read locks Paul Moore
2007-12-14 21:50 ` [RFC PATCH v8 02/18] NetLabel: Cleanup the LSM domain hash functions Paul Moore
2007-12-14 21:50 ` [RFC PATCH v8 03/18] NetLabel: Consolidate the LSM domain mapping/hashing locks Paul Moore
2007-12-14 21:50 ` [RFC PATCH v8 04/18] NetLabel: Add secid token support to the NetLabel secattr struct Paul Moore
2007-12-14 21:50 ` [RFC PATCH v8 05/18] LSM: Add secctx_to_secid() LSM hook Paul Moore
2007-12-17 19:49   ` Stephen Smalley
2007-12-17 20:42     ` Casey Schaufler
2007-12-18  8:25   ` James Morris
2007-12-18 13:44     ` Paul Moore
2007-12-14 21:50 ` [RFC PATCH v8 06/18] LSM: Add inet_sys_snd_skb() " Paul Moore
2007-12-17 19:45   ` Stephen Smalley
2007-12-17 20:48     ` Paul Moore
2007-12-14 21:50 ` [RFC PATCH v8 07/18] NetLabel: Add IP address family information to the netlbl_skbuff_getattr() function Paul Moore
2007-12-14 21:50 ` [RFC PATCH v8 08/18] SELinux: Convert the netif code to use ifindex values Paul Moore
2007-12-14 21:50 ` [RFC PATCH v8 09/18] SELinux: Only store the network interface's ifindex Paul Moore
2007-12-17 19:56   ` Stephen Smalley
2007-12-17 20:51     ` Paul Moore
2007-12-14 21:50 ` [RFC PATCH v8 10/18] SELinux: Add a network node caching mechanism similar to the sel_netif_*() functions Paul Moore
2007-12-17 20:35   ` Stephen Smalley
2007-12-17 20:56     ` Paul Moore
2007-12-18  8:16       ` James Morris
2007-12-18 13:26       ` Stephen Smalley
2007-12-18 13:37         ` Paul Moore
2007-12-14 21:50 ` [RFC PATCH v8 11/18] SELinux: Add a capabilities bitmap to SELinux policy version 22 Paul Moore
2007-12-14 21:50 ` [RFC PATCH v8 12/18] SELinux: Add new peer permissions to the Flask definitions Paul Moore
2007-12-14 21:51 ` [RFC PATCH v8 13/18] SELinux: Better integration between peer labeling subsystems Paul Moore
2007-12-14 21:51 ` [RFC PATCH v8 14/18] SELinux: Enable dynamic enable/disable of the network access checks Paul Moore
2007-12-14 21:51 ` [RFC PATCH v8 15/18] SELinux: Allow NetLabel to directly cache SIDs Paul Moore
2007-12-14 21:51 ` [RFC PATCH v8 16/18] NetLabel: Introduce static network labels for unlabeled connections Paul Moore
2007-12-14 21:51 ` [RFC PATCH v8 17/18] NetLabel: Add auditing to the static labeling mechanism Paul Moore
2007-12-14 21:51 ` Paul Moore [this message]
2007-12-16 16:47   ` [RFC PATCH v8 18/18] SELinux: Add network ingress and egress control permission checks Paul Moore
2007-12-17 20:05     ` Stephen Smalley
2007-12-17 21:06       ` Paul Moore
2007-12-18 13:59       ` Paul Moore
2007-12-18 15:14         ` Stephen Smalley
2007-12-18 17:03           ` Paul Moore

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20071214215129.10069.75156.stgit@flek.lan \
    --to=paul.moore@hp.com \
    --cc=chanson@TrustedCS.com \
    --cc=linux-security-module@vger.kernel.org \
    --cc=selinux@tycho.nsa.gov \
    --cc=vyekkirala@TrustedCS.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.