diff options
Diffstat (limited to 'security')
-rw-r--r-- | security/selinux/hooks.c | 50 | ||||
-rw-r--r-- | security/selinux/include/netlabel.h | 9 | ||||
-rw-r--r-- | security/selinux/include/objsec.h | 1 | ||||
-rw-r--r-- | security/selinux/netlabel.c | 68 |
4 files changed, 125 insertions, 3 deletions
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index a91146a6b37..7432bdd5d36 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -4407,13 +4407,15 @@ static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex, u32 peer_sid; struct avc_audit_data ad; u8 secmark_active; + u8 netlbl_active; u8 peerlbl_active; if (!selinux_policycap_netpeer) return NF_ACCEPT; secmark_active = selinux_secmark_enabled(); - peerlbl_active = netlbl_enabled() || selinux_xfrm_enabled(); + netlbl_active = netlbl_enabled(); + peerlbl_active = netlbl_active || selinux_xfrm_enabled(); if (!secmark_active && !peerlbl_active) return NF_ACCEPT; @@ -4440,6 +4442,14 @@ static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex, SECCLASS_PACKET, PACKET__FORWARD_IN, &ad)) return NF_DROP; + if (netlbl_active) + /* we do this in the FORWARD path and not the POST_ROUTING + * path because we want to make sure we apply the necessary + * labeling before IPsec is applied so we can leverage AH + * protection */ + if (selinux_netlbl_skbuff_setsid(skb, family, peer_sid) != 0) + return NF_DROP; + return NF_ACCEPT; } @@ -4463,6 +4473,37 @@ static unsigned int selinux_ipv6_forward(unsigned int hooknum, } #endif /* IPV6 */ +static unsigned int selinux_ip_output(struct sk_buff *skb, + u16 family) +{ + u32 sid; + + if (!netlbl_enabled()) + return NF_ACCEPT; + + /* we do this in the LOCAL_OUT path and not the POST_ROUTING path + * because we want to make sure we apply the necessary labeling + * before IPsec is applied so we can leverage AH protection */ + if (skb->sk) { + struct sk_security_struct *sksec = skb->sk->sk_security; + sid = sksec->sid; + } else + sid = SECINITSID_KERNEL; + if (selinux_netlbl_skbuff_setsid(skb, family, sid) != 0) + return NF_DROP; + + return NF_ACCEPT; +} + +static unsigned int selinux_ipv4_output(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_output(skb, PF_INET); +} + static int selinux_ip_postroute_iptables_compat(struct sock *sk, int ifindex, struct avc_audit_data *ad, @@ -5700,6 +5741,13 @@ static struct nf_hook_ops selinux_ipv4_ops[] = { .pf = PF_INET, .hooknum = NF_INET_FORWARD, .priority = NF_IP_PRI_SELINUX_FIRST, + }, + { + .hook = selinux_ipv4_output, + .owner = THIS_MODULE, + .pf = PF_INET, + .hooknum = NF_INET_LOCAL_OUT, + .priority = NF_IP_PRI_SELINUX_FIRST, } }; diff --git a/security/selinux/include/netlabel.h b/security/selinux/include/netlabel.h index d4e3ac8a7fb..b3e6ae071fc 100644 --- a/security/selinux/include/netlabel.h +++ b/security/selinux/include/netlabel.h @@ -48,6 +48,9 @@ int selinux_netlbl_skbuff_getsid(struct sk_buff *skb, u16 family, u32 *type, u32 *sid); +int selinux_netlbl_skbuff_setsid(struct sk_buff *skb, + u16 family, + u32 sid); void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock); int selinux_netlbl_socket_post_create(struct socket *sock); @@ -88,6 +91,12 @@ static inline int selinux_netlbl_skbuff_getsid(struct sk_buff *skb, *sid = SECSID_NULL; return 0; } +static inline int selinux_netlbl_skbuff_setsid(struct sk_buff *skb, + u16 family, + u32 sid) +{ + return 0; +} static inline void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock) diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h index 91070ab874c..f46dd1c3d01 100644 --- a/security/selinux/include/objsec.h +++ b/security/selinux/include/objsec.h @@ -117,6 +117,7 @@ struct sk_security_struct { NLBL_UNSET = 0, NLBL_REQUIRE, NLBL_LABELED, + NLBL_REQSKB, } nlbl_state; #endif }; diff --git a/security/selinux/netlabel.c b/security/selinux/netlabel.c index 4053f7fc95f..090404d6e51 100644 --- a/security/selinux/netlabel.c +++ b/security/selinux/netlabel.c @@ -9,7 +9,7 @@ */ /* - * (c) Copyright Hewlett-Packard Development Company, L.P., 2007 + * (c) Copyright Hewlett-Packard Development Company, L.P., 2007, 2008 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -31,6 +31,8 @@ #include <linux/rcupdate.h> #include <net/sock.h> #include <net/netlabel.h> +#include <net/inet_sock.h> +#include <net/inet_connection_sock.h> #include "objsec.h" #include "security.h" @@ -77,6 +79,8 @@ static int selinux_netlbl_sock_setsid(struct sock *sk) int rc; struct sk_security_struct *sksec = sk->sk_security; struct netlbl_lsm_secattr secattr; + struct inet_sock *sk_inet; + struct inet_connection_sock *sk_conn; if (sksec->nlbl_state != NLBL_REQUIRE) return 0; @@ -87,8 +91,29 @@ static int selinux_netlbl_sock_setsid(struct sock *sk) if (rc != 0) goto sock_setsid_return; rc = netlbl_sock_setattr(sk, &secattr); - if (rc == 0) + switch (rc) { + case 0: sksec->nlbl_state = NLBL_LABELED; + break; + case -EDESTADDRREQ: + /* we are going to possibly end up labeling the individual + * packets later which is problematic for stream sockets + * because of the additional IP header size, our solution is to + * allow for the maximum IP header length (40 bytes for IPv4, + * we don't have to worry about IPv6 yet) just in case */ + sk_inet = inet_sk(sk); + if (sk_inet->is_icsk) { + sk_conn = inet_csk(sk); + if (sk_inet->opt) + sk_conn->icsk_ext_hdr_len -= + sk_inet->opt->optlen; + sk_conn->icsk_ext_hdr_len += 40; + sk_conn->icsk_sync_mss(sk, sk_conn->icsk_pmtu_cookie); + } + sksec->nlbl_state = NLBL_REQSKB; + rc = 0; + break; + } sock_setsid_return: netlbl_secattr_destroy(&secattr); @@ -183,6 +208,45 @@ int selinux_netlbl_skbuff_getsid(struct sk_buff *skb, } /** + * selinux_netlbl_skbuff_setsid - Set the NetLabel on a packet given a sid + * @skb: the packet + * @family: protocol family + * @sid: the SID + * + * Description + * Call the NetLabel mechanism to set the label of a packet using @sid. + * Returns zero on auccess, negative values on failure. + * + */ +int selinux_netlbl_skbuff_setsid(struct sk_buff *skb, + u16 family, + u32 sid) +{ + int rc; + struct netlbl_lsm_secattr secattr; + struct sock *sk; + + /* if this is a locally generated packet check to see if it is already + * being labeled by it's parent socket, if it is just exit */ + sk = skb->sk; + if (sk != NULL) { + struct sk_security_struct *sksec = sk->sk_security; + if (sksec->nlbl_state != NLBL_REQSKB) + return 0; + } + + netlbl_secattr_init(&secattr); + rc = security_netlbl_sid_to_secattr(sid, &secattr); + if (rc != 0) + goto skbuff_setsid_return; + rc = netlbl_skbuff_setattr(skb, family, &secattr); + +skbuff_setsid_return: + netlbl_secattr_destroy(&secattr); + return rc; +} + +/** * selinux_netlbl_sock_graft - Netlabel the new socket * @sk: the new connection * @sock: the new socket |