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 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 |