diff options
Diffstat (limited to 'security/selinux/netlabel.c')
-rw-r--r-- | security/selinux/netlabel.c | 115 |
1 files changed, 79 insertions, 36 deletions
diff --git a/security/selinux/netlabel.c b/security/selinux/netlabel.c index b22b7dafa0e3..f58701a7b728 100644 --- a/security/selinux/netlabel.c +++ b/security/selinux/netlabel.c | |||
@@ -68,6 +68,38 @@ static int selinux_netlbl_sidlookup_cached(struct sk_buff *skb, | |||
68 | } | 68 | } |
69 | 69 | ||
70 | /** | 70 | /** |
71 | * selinux_netlbl_sock_genattr - Generate the NetLabel socket secattr | ||
72 | * @sk: the socket | ||
73 | * | ||
74 | * Description: | ||
75 | * Generate the NetLabel security attributes for a socket, making full use of | ||
76 | * the socket's attribute cache. Returns a pointer to the security attributes | ||
77 | * on success, NULL on failure. | ||
78 | * | ||
79 | */ | ||
80 | static struct netlbl_lsm_secattr *selinux_netlbl_sock_genattr(struct sock *sk) | ||
81 | { | ||
82 | int rc; | ||
83 | struct sk_security_struct *sksec = sk->sk_security; | ||
84 | struct netlbl_lsm_secattr *secattr; | ||
85 | |||
86 | if (sksec->nlbl_secattr != NULL) | ||
87 | return sksec->nlbl_secattr; | ||
88 | |||
89 | secattr = netlbl_secattr_alloc(GFP_ATOMIC); | ||
90 | if (secattr == NULL) | ||
91 | return NULL; | ||
92 | rc = security_netlbl_sid_to_secattr(sksec->sid, secattr); | ||
93 | if (rc != 0) { | ||
94 | netlbl_secattr_free(secattr); | ||
95 | return NULL; | ||
96 | } | ||
97 | sksec->nlbl_secattr = secattr; | ||
98 | |||
99 | return secattr; | ||
100 | } | ||
101 | |||
102 | /** | ||
71 | * selinux_netlbl_sock_setsid - Label a socket using the NetLabel mechanism | 103 | * selinux_netlbl_sock_setsid - Label a socket using the NetLabel mechanism |
72 | * @sk: the socket to label | 104 | * @sk: the socket to label |
73 | * | 105 | * |
@@ -80,17 +112,15 @@ static int selinux_netlbl_sock_setsid(struct sock *sk) | |||
80 | { | 112 | { |
81 | int rc; | 113 | int rc; |
82 | struct sk_security_struct *sksec = sk->sk_security; | 114 | struct sk_security_struct *sksec = sk->sk_security; |
83 | struct netlbl_lsm_secattr secattr; | 115 | struct netlbl_lsm_secattr *secattr; |
84 | 116 | ||
85 | if (sksec->nlbl_state != NLBL_REQUIRE) | 117 | if (sksec->nlbl_state != NLBL_REQUIRE) |
86 | return 0; | 118 | return 0; |
87 | 119 | ||
88 | netlbl_secattr_init(&secattr); | 120 | secattr = selinux_netlbl_sock_genattr(sk); |
89 | 121 | if (secattr == NULL) | |
90 | rc = security_netlbl_sid_to_secattr(sksec->sid, &secattr); | 122 | return -ENOMEM; |
91 | if (rc != 0) | 123 | rc = netlbl_sock_setattr(sk, secattr); |
92 | goto sock_setsid_return; | ||
93 | rc = netlbl_sock_setattr(sk, &secattr); | ||
94 | switch (rc) { | 124 | switch (rc) { |
95 | case 0: | 125 | case 0: |
96 | sksec->nlbl_state = NLBL_LABELED; | 126 | sksec->nlbl_state = NLBL_LABELED; |
@@ -101,8 +131,6 @@ static int selinux_netlbl_sock_setsid(struct sock *sk) | |||
101 | break; | 131 | break; |
102 | } | 132 | } |
103 | 133 | ||
104 | sock_setsid_return: | ||
105 | netlbl_secattr_destroy(&secattr); | ||
106 | return rc; | 134 | return rc; |
107 | } | 135 | } |
108 | 136 | ||
@@ -137,6 +165,20 @@ void selinux_netlbl_err(struct sk_buff *skb, int error, int gateway) | |||
137 | } | 165 | } |
138 | 166 | ||
139 | /** | 167 | /** |
168 | * selinux_netlbl_sk_security_free - Free the NetLabel fields | ||
169 | * @sssec: the sk_security_struct | ||
170 | * | ||
171 | * Description: | ||
172 | * Free all of the memory in the NetLabel fields of a sk_security_struct. | ||
173 | * | ||
174 | */ | ||
175 | void selinux_netlbl_sk_security_free(struct sk_security_struct *ssec) | ||
176 | { | ||
177 | if (ssec->nlbl_secattr != NULL) | ||
178 | netlbl_secattr_free(ssec->nlbl_secattr); | ||
179 | } | ||
180 | |||
181 | /** | ||
140 | * selinux_netlbl_sk_security_reset - Reset the NetLabel fields | 182 | * selinux_netlbl_sk_security_reset - Reset the NetLabel fields |
141 | * @ssec: the sk_security_struct | 183 | * @ssec: the sk_security_struct |
142 | * @family: the socket family | 184 | * @family: the socket family |
@@ -209,7 +251,8 @@ int selinux_netlbl_skbuff_setsid(struct sk_buff *skb, | |||
209 | u32 sid) | 251 | u32 sid) |
210 | { | 252 | { |
211 | int rc; | 253 | int rc; |
212 | struct netlbl_lsm_secattr secattr; | 254 | struct netlbl_lsm_secattr secattr_storage; |
255 | struct netlbl_lsm_secattr *secattr = NULL; | ||
213 | struct sock *sk; | 256 | struct sock *sk; |
214 | 257 | ||
215 | /* if this is a locally generated packet check to see if it is already | 258 | /* if this is a locally generated packet check to see if it is already |
@@ -219,16 +262,21 @@ int selinux_netlbl_skbuff_setsid(struct sk_buff *skb, | |||
219 | struct sk_security_struct *sksec = sk->sk_security; | 262 | struct sk_security_struct *sksec = sk->sk_security; |
220 | if (sksec->nlbl_state != NLBL_REQSKB) | 263 | if (sksec->nlbl_state != NLBL_REQSKB) |
221 | return 0; | 264 | return 0; |
265 | secattr = sksec->nlbl_secattr; | ||
266 | } | ||
267 | if (secattr == NULL) { | ||
268 | secattr = &secattr_storage; | ||
269 | netlbl_secattr_init(secattr); | ||
270 | rc = security_netlbl_sid_to_secattr(sid, secattr); | ||
271 | if (rc != 0) | ||
272 | goto skbuff_setsid_return; | ||
222 | } | 273 | } |
223 | 274 | ||
224 | netlbl_secattr_init(&secattr); | 275 | rc = netlbl_skbuff_setattr(skb, family, secattr); |
225 | rc = security_netlbl_sid_to_secattr(sid, &secattr); | ||
226 | if (rc != 0) | ||
227 | goto skbuff_setsid_return; | ||
228 | rc = netlbl_skbuff_setattr(skb, family, &secattr); | ||
229 | 276 | ||
230 | skbuff_setsid_return: | 277 | skbuff_setsid_return: |
231 | netlbl_secattr_destroy(&secattr); | 278 | if (secattr == &secattr_storage) |
279 | netlbl_secattr_destroy(secattr); | ||
232 | return rc; | 280 | return rc; |
233 | } | 281 | } |
234 | 282 | ||
@@ -245,18 +293,18 @@ void selinux_netlbl_inet_conn_established(struct sock *sk, u16 family) | |||
245 | { | 293 | { |
246 | int rc; | 294 | int rc; |
247 | struct sk_security_struct *sksec = sk->sk_security; | 295 | struct sk_security_struct *sksec = sk->sk_security; |
248 | struct netlbl_lsm_secattr secattr; | 296 | struct netlbl_lsm_secattr *secattr; |
249 | struct inet_sock *sk_inet = inet_sk(sk); | 297 | struct inet_sock *sk_inet = inet_sk(sk); |
250 | struct sockaddr_in addr; | 298 | struct sockaddr_in addr; |
251 | 299 | ||
252 | if (sksec->nlbl_state != NLBL_REQUIRE) | 300 | if (sksec->nlbl_state != NLBL_REQUIRE) |
253 | return; | 301 | return; |
254 | 302 | ||
255 | netlbl_secattr_init(&secattr); | 303 | secattr = selinux_netlbl_sock_genattr(sk); |
256 | if (security_netlbl_sid_to_secattr(sksec->sid, &secattr) != 0) | 304 | if (secattr == NULL) |
257 | goto inet_conn_established_return; | 305 | return; |
258 | 306 | ||
259 | rc = netlbl_sock_setattr(sk, &secattr); | 307 | rc = netlbl_sock_setattr(sk, secattr); |
260 | switch (rc) { | 308 | switch (rc) { |
261 | case 0: | 309 | case 0: |
262 | sksec->nlbl_state = NLBL_LABELED; | 310 | sksec->nlbl_state = NLBL_LABELED; |
@@ -266,13 +314,13 @@ void selinux_netlbl_inet_conn_established(struct sock *sk, u16 family) | |||
266 | * labeling protocols */ | 314 | * labeling protocols */ |
267 | if (family != PF_INET) { | 315 | if (family != PF_INET) { |
268 | sksec->nlbl_state = NLBL_UNSET; | 316 | sksec->nlbl_state = NLBL_UNSET; |
269 | goto inet_conn_established_return; | 317 | return; |
270 | } | 318 | } |
271 | 319 | ||
272 | addr.sin_family = family; | 320 | addr.sin_family = family; |
273 | addr.sin_addr.s_addr = sk_inet->daddr; | 321 | addr.sin_addr.s_addr = sk_inet->daddr; |
274 | if (netlbl_conn_setattr(sk, (struct sockaddr *)&addr, | 322 | if (netlbl_conn_setattr(sk, (struct sockaddr *)&addr, |
275 | &secattr) != 0) { | 323 | secattr) != 0) { |
276 | /* we failed to label the connected socket (could be | 324 | /* we failed to label the connected socket (could be |
277 | * for a variety of reasons, the actual "why" isn't | 325 | * for a variety of reasons, the actual "why" isn't |
278 | * important here) so we have to go to our backup plan, | 326 | * important here) so we have to go to our backup plan, |
@@ -300,10 +348,6 @@ void selinux_netlbl_inet_conn_established(struct sock *sk, u16 family) | |||
300 | * return an error code */ | 348 | * return an error code */ |
301 | break; | 349 | break; |
302 | } | 350 | } |
303 | |||
304 | inet_conn_established_return: | ||
305 | netlbl_secattr_destroy(&secattr); | ||
306 | return; | ||
307 | } | 351 | } |
308 | 352 | ||
309 | /** | 353 | /** |
@@ -468,13 +512,12 @@ int selinux_netlbl_socket_connect(struct sock *sk, struct sockaddr *addr) | |||
468 | { | 512 | { |
469 | int rc; | 513 | int rc; |
470 | struct sk_security_struct *sksec = sk->sk_security; | 514 | struct sk_security_struct *sksec = sk->sk_security; |
471 | struct netlbl_lsm_secattr secattr; | 515 | struct netlbl_lsm_secattr *secattr; |
472 | 516 | ||
473 | if (sksec->nlbl_state != NLBL_REQSKB && | 517 | if (sksec->nlbl_state != NLBL_REQSKB && |
474 | sksec->nlbl_state != NLBL_CONNLABELED) | 518 | sksec->nlbl_state != NLBL_CONNLABELED) |
475 | return 0; | 519 | return 0; |
476 | 520 | ||
477 | netlbl_secattr_init(&secattr); | ||
478 | local_bh_disable(); | 521 | local_bh_disable(); |
479 | bh_lock_sock_nested(sk); | 522 | bh_lock_sock_nested(sk); |
480 | 523 | ||
@@ -487,17 +530,17 @@ int selinux_netlbl_socket_connect(struct sock *sk, struct sockaddr *addr) | |||
487 | rc = 0; | 530 | rc = 0; |
488 | goto socket_connect_return; | 531 | goto socket_connect_return; |
489 | } | 532 | } |
490 | rc = security_netlbl_sid_to_secattr(sksec->sid, &secattr); | 533 | secattr = selinux_netlbl_sock_genattr(sk); |
491 | if (rc != 0) | 534 | if (secattr == NULL) { |
535 | rc = -ENOMEM; | ||
492 | goto socket_connect_return; | 536 | goto socket_connect_return; |
493 | rc = netlbl_conn_setattr(sk, addr, &secattr); | 537 | } |
494 | if (rc != 0) | 538 | rc = netlbl_conn_setattr(sk, addr, secattr); |
495 | goto socket_connect_return; | 539 | if (rc == 0) |
496 | sksec->nlbl_state = NLBL_CONNLABELED; | 540 | sksec->nlbl_state = NLBL_CONNLABELED; |
497 | 541 | ||
498 | socket_connect_return: | 542 | socket_connect_return: |
499 | bh_unlock_sock(sk); | 543 | bh_unlock_sock(sk); |
500 | local_bh_enable(); | 544 | local_bh_enable(); |
501 | netlbl_secattr_destroy(&secattr); | ||
502 | return rc; | 545 | return rc; |
503 | } | 546 | } |