diff options
author | Paul Moore <paul.moore@hp.com> | 2008-10-10 10:16:32 -0400 |
---|---|---|
committer | Paul Moore <paul.moore@hp.com> | 2008-10-10 10:16:32 -0400 |
commit | 948bf85c1bc9a84754786a9d5dd99b7ecc46451e (patch) | |
tree | a4706be1f4a5a37408774ef3c4cab8cf2e7775b5 /security/selinux | |
parent | 63c41688743760631188cf0f4ae986a6793ccb0a (diff) |
netlabel: Add functionality to set the security attributes of a packet
This patch builds upon the new NetLabel address selector functionality by
providing the NetLabel KAPI and CIPSO engine support needed to enable the
new packet-based labeling. The only new addition to the NetLabel KAPI at
this point is shown below:
* int netlbl_skbuff_setattr(skb, family, secattr)
... and is designed to be called from a Netfilter hook after the packet's
IP header has been populated such as in the FORWARD or LOCAL_OUT hooks.
This patch also provides the necessary SELinux hooks to support this new
functionality. Smack support is not currently included due to uncertainty
regarding the permissions needed to expand the Smack network access controls.
Signed-off-by: Paul Moore <paul.moore@hp.com>
Reviewed-by: James Morris <jmorris@namei.org>
Diffstat (limited to 'security/selinux')
-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 a91146a6b37d..7432bdd5d367 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, | |||
4407 | u32 peer_sid; | 4407 | u32 peer_sid; |
4408 | struct avc_audit_data ad; | 4408 | struct avc_audit_data ad; |
4409 | u8 secmark_active; | 4409 | u8 secmark_active; |
4410 | u8 netlbl_active; | ||
4410 | u8 peerlbl_active; | 4411 | u8 peerlbl_active; |
4411 | 4412 | ||
4412 | if (!selinux_policycap_netpeer) | 4413 | if (!selinux_policycap_netpeer) |
4413 | return NF_ACCEPT; | 4414 | return NF_ACCEPT; |
4414 | 4415 | ||
4415 | secmark_active = selinux_secmark_enabled(); | 4416 | secmark_active = selinux_secmark_enabled(); |
4416 | peerlbl_active = netlbl_enabled() || selinux_xfrm_enabled(); | 4417 | netlbl_active = netlbl_enabled(); |
4418 | peerlbl_active = netlbl_active || selinux_xfrm_enabled(); | ||
4417 | if (!secmark_active && !peerlbl_active) | 4419 | if (!secmark_active && !peerlbl_active) |
4418 | return NF_ACCEPT; | 4420 | return NF_ACCEPT; |
4419 | 4421 | ||
@@ -4440,6 +4442,14 @@ static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex, | |||
4440 | SECCLASS_PACKET, PACKET__FORWARD_IN, &ad)) | 4442 | SECCLASS_PACKET, PACKET__FORWARD_IN, &ad)) |
4441 | return NF_DROP; | 4443 | return NF_DROP; |
4442 | 4444 | ||
4445 | if (netlbl_active) | ||
4446 | /* we do this in the FORWARD path and not the POST_ROUTING | ||
4447 | * path because we want to make sure we apply the necessary | ||
4448 | * labeling before IPsec is applied so we can leverage AH | ||
4449 | * protection */ | ||
4450 | if (selinux_netlbl_skbuff_setsid(skb, family, peer_sid) != 0) | ||
4451 | return NF_DROP; | ||
4452 | |||
4443 | return NF_ACCEPT; | 4453 | return NF_ACCEPT; |
4444 | } | 4454 | } |
4445 | 4455 | ||
@@ -4463,6 +4473,37 @@ static unsigned int selinux_ipv6_forward(unsigned int hooknum, | |||
4463 | } | 4473 | } |
4464 | #endif /* IPV6 */ | 4474 | #endif /* IPV6 */ |
4465 | 4475 | ||
4476 | static unsigned int selinux_ip_output(struct sk_buff *skb, | ||
4477 | u16 family) | ||
4478 | { | ||
4479 | u32 sid; | ||
4480 | |||
4481 | if (!netlbl_enabled()) | ||
4482 | return NF_ACCEPT; | ||
4483 | |||
4484 | /* we do this in the LOCAL_OUT path and not the POST_ROUTING path | ||
4485 | * because we want to make sure we apply the necessary labeling | ||
4486 | * before IPsec is applied so we can leverage AH protection */ | ||
4487 | if (skb->sk) { | ||
4488 | struct sk_security_struct *sksec = skb->sk->sk_security; | ||
4489 | sid = sksec->sid; | ||
4490 | } else | ||
4491 | sid = SECINITSID_KERNEL; | ||
4492 | if (selinux_netlbl_skbuff_setsid(skb, family, sid) != 0) | ||
4493 | return NF_DROP; | ||
4494 | |||
4495 | return NF_ACCEPT; | ||
4496 | } | ||
4497 | |||
4498 | static unsigned int selinux_ipv4_output(unsigned int hooknum, | ||
4499 | struct sk_buff *skb, | ||
4500 | const struct net_device *in, | ||
4501 | const struct net_device *out, | ||
4502 | int (*okfn)(struct sk_buff *)) | ||
4503 | { | ||
4504 | return selinux_ip_output(skb, PF_INET); | ||
4505 | } | ||
4506 | |||
4466 | static int selinux_ip_postroute_iptables_compat(struct sock *sk, | 4507 | static int selinux_ip_postroute_iptables_compat(struct sock *sk, |
4467 | int ifindex, | 4508 | int ifindex, |
4468 | struct avc_audit_data *ad, | 4509 | struct avc_audit_data *ad, |
@@ -5700,6 +5741,13 @@ static struct nf_hook_ops selinux_ipv4_ops[] = { | |||
5700 | .pf = PF_INET, | 5741 | .pf = PF_INET, |
5701 | .hooknum = NF_INET_FORWARD, | 5742 | .hooknum = NF_INET_FORWARD, |
5702 | .priority = NF_IP_PRI_SELINUX_FIRST, | 5743 | .priority = NF_IP_PRI_SELINUX_FIRST, |
5744 | }, | ||
5745 | { | ||
5746 | .hook = selinux_ipv4_output, | ||
5747 | .owner = THIS_MODULE, | ||
5748 | .pf = PF_INET, | ||
5749 | .hooknum = NF_INET_LOCAL_OUT, | ||
5750 | .priority = NF_IP_PRI_SELINUX_FIRST, | ||
5703 | } | 5751 | } |
5704 | }; | 5752 | }; |
5705 | 5753 | ||
diff --git a/security/selinux/include/netlabel.h b/security/selinux/include/netlabel.h index d4e3ac8a7fbf..b3e6ae071fc3 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, | |||
48 | u16 family, | 48 | u16 family, |
49 | u32 *type, | 49 | u32 *type, |
50 | u32 *sid); | 50 | u32 *sid); |
51 | int selinux_netlbl_skbuff_setsid(struct sk_buff *skb, | ||
52 | u16 family, | ||
53 | u32 sid); | ||
51 | 54 | ||
52 | void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock); | 55 | void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock); |
53 | int selinux_netlbl_socket_post_create(struct socket *sock); | 56 | int selinux_netlbl_socket_post_create(struct socket *sock); |
@@ -88,6 +91,12 @@ static inline int selinux_netlbl_skbuff_getsid(struct sk_buff *skb, | |||
88 | *sid = SECSID_NULL; | 91 | *sid = SECSID_NULL; |
89 | return 0; | 92 | return 0; |
90 | } | 93 | } |
94 | static inline int selinux_netlbl_skbuff_setsid(struct sk_buff *skb, | ||
95 | u16 family, | ||
96 | u32 sid) | ||
97 | { | ||
98 | return 0; | ||
99 | } | ||
91 | 100 | ||
92 | static inline void selinux_netlbl_sock_graft(struct sock *sk, | 101 | static inline void selinux_netlbl_sock_graft(struct sock *sk, |
93 | struct socket *sock) | 102 | struct socket *sock) |
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h index 91070ab874ce..f46dd1c3d01c 100644 --- a/security/selinux/include/objsec.h +++ b/security/selinux/include/objsec.h | |||
@@ -117,6 +117,7 @@ struct sk_security_struct { | |||
117 | NLBL_UNSET = 0, | 117 | NLBL_UNSET = 0, |
118 | NLBL_REQUIRE, | 118 | NLBL_REQUIRE, |
119 | NLBL_LABELED, | 119 | NLBL_LABELED, |
120 | NLBL_REQSKB, | ||
120 | } nlbl_state; | 121 | } nlbl_state; |
121 | #endif | 122 | #endif |
122 | }; | 123 | }; |
diff --git a/security/selinux/netlabel.c b/security/selinux/netlabel.c index 4053f7fc95fb..090404d6e512 100644 --- a/security/selinux/netlabel.c +++ b/security/selinux/netlabel.c | |||
@@ -9,7 +9,7 @@ | |||
9 | */ | 9 | */ |
10 | 10 | ||
11 | /* | 11 | /* |
12 | * (c) Copyright Hewlett-Packard Development Company, L.P., 2007 | 12 | * (c) Copyright Hewlett-Packard Development Company, L.P., 2007, 2008 |
13 | * | 13 | * |
14 | * This program is free software; you can redistribute it and/or modify | 14 | * This program is free software; you can redistribute it and/or modify |
15 | * it under the terms of the GNU General Public License as published by | 15 | * it under the terms of the GNU General Public License as published by |
@@ -31,6 +31,8 @@ | |||
31 | #include <linux/rcupdate.h> | 31 | #include <linux/rcupdate.h> |
32 | #include <net/sock.h> | 32 | #include <net/sock.h> |
33 | #include <net/netlabel.h> | 33 | #include <net/netlabel.h> |
34 | #include <net/inet_sock.h> | ||
35 | #include <net/inet_connection_sock.h> | ||
34 | 36 | ||
35 | #include "objsec.h" | 37 | #include "objsec.h" |
36 | #include "security.h" | 38 | #include "security.h" |
@@ -77,6 +79,8 @@ static int selinux_netlbl_sock_setsid(struct sock *sk) | |||
77 | int rc; | 79 | int rc; |
78 | struct sk_security_struct *sksec = sk->sk_security; | 80 | struct sk_security_struct *sksec = sk->sk_security; |
79 | struct netlbl_lsm_secattr secattr; | 81 | struct netlbl_lsm_secattr secattr; |
82 | struct inet_sock *sk_inet; | ||
83 | struct inet_connection_sock *sk_conn; | ||
80 | 84 | ||
81 | if (sksec->nlbl_state != NLBL_REQUIRE) | 85 | if (sksec->nlbl_state != NLBL_REQUIRE) |
82 | return 0; | 86 | return 0; |
@@ -87,8 +91,29 @@ static int selinux_netlbl_sock_setsid(struct sock *sk) | |||
87 | if (rc != 0) | 91 | if (rc != 0) |
88 | goto sock_setsid_return; | 92 | goto sock_setsid_return; |
89 | rc = netlbl_sock_setattr(sk, &secattr); | 93 | rc = netlbl_sock_setattr(sk, &secattr); |
90 | if (rc == 0) | 94 | switch (rc) { |
95 | case 0: | ||
91 | sksec->nlbl_state = NLBL_LABELED; | 96 | sksec->nlbl_state = NLBL_LABELED; |
97 | break; | ||
98 | case -EDESTADDRREQ: | ||
99 | /* we are going to possibly end up labeling the individual | ||
100 | * packets later which is problematic for stream sockets | ||
101 | * because of the additional IP header size, our solution is to | ||
102 | * allow for the maximum IP header length (40 bytes for IPv4, | ||
103 | * we don't have to worry about IPv6 yet) just in case */ | ||
104 | sk_inet = inet_sk(sk); | ||
105 | if (sk_inet->is_icsk) { | ||
106 | sk_conn = inet_csk(sk); | ||
107 | if (sk_inet->opt) | ||
108 | sk_conn->icsk_ext_hdr_len -= | ||
109 | sk_inet->opt->optlen; | ||
110 | sk_conn->icsk_ext_hdr_len += 40; | ||
111 | sk_conn->icsk_sync_mss(sk, sk_conn->icsk_pmtu_cookie); | ||
112 | } | ||
113 | sksec->nlbl_state = NLBL_REQSKB; | ||
114 | rc = 0; | ||
115 | break; | ||
116 | } | ||
92 | 117 | ||
93 | sock_setsid_return: | 118 | sock_setsid_return: |
94 | netlbl_secattr_destroy(&secattr); | 119 | netlbl_secattr_destroy(&secattr); |
@@ -183,6 +208,45 @@ int selinux_netlbl_skbuff_getsid(struct sk_buff *skb, | |||
183 | } | 208 | } |
184 | 209 | ||
185 | /** | 210 | /** |
211 | * selinux_netlbl_skbuff_setsid - Set the NetLabel on a packet given a sid | ||
212 | * @skb: the packet | ||
213 | * @family: protocol family | ||
214 | * @sid: the SID | ||
215 | * | ||
216 | * Description | ||
217 | * Call the NetLabel mechanism to set the label of a packet using @sid. | ||
218 | * Returns zero on auccess, negative values on failure. | ||
219 | * | ||
220 | */ | ||
221 | int selinux_netlbl_skbuff_setsid(struct sk_buff *skb, | ||
222 | u16 family, | ||
223 | u32 sid) | ||
224 | { | ||
225 | int rc; | ||
226 | struct netlbl_lsm_secattr secattr; | ||
227 | struct sock *sk; | ||
228 | |||
229 | /* if this is a locally generated packet check to see if it is already | ||
230 | * being labeled by it's parent socket, if it is just exit */ | ||
231 | sk = skb->sk; | ||
232 | if (sk != NULL) { | ||
233 | struct sk_security_struct *sksec = sk->sk_security; | ||
234 | if (sksec->nlbl_state != NLBL_REQSKB) | ||
235 | return 0; | ||
236 | } | ||
237 | |||
238 | netlbl_secattr_init(&secattr); | ||
239 | rc = security_netlbl_sid_to_secattr(sid, &secattr); | ||
240 | if (rc != 0) | ||
241 | goto skbuff_setsid_return; | ||
242 | rc = netlbl_skbuff_setattr(skb, family, &secattr); | ||
243 | |||
244 | skbuff_setsid_return: | ||
245 | netlbl_secattr_destroy(&secattr); | ||
246 | return rc; | ||
247 | } | ||
248 | |||
249 | /** | ||
186 | * selinux_netlbl_sock_graft - Netlabel the new socket | 250 | * selinux_netlbl_sock_graft - Netlabel the new socket |
187 | * @sk: the new connection | 251 | * @sk: the new connection |
188 | * @sock: the new socket | 252 | * @sock: the new socket |