diff options
| -rw-r--r-- | security/selinux/hooks.c | 1 | ||||
| -rw-r--r-- | security/selinux/include/netlabel.h | 7 | ||||
| -rw-r--r-- | security/selinux/include/objsec.h | 7 | ||||
| -rw-r--r-- | security/selinux/netlabel.c | 115 |
4 files changed, 91 insertions, 39 deletions
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 632ac3e80a61..3aa811eba25b 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
| @@ -291,6 +291,7 @@ static void sk_free_security(struct sock *sk) | |||
| 291 | struct sk_security_struct *ssec = sk->sk_security; | 291 | struct sk_security_struct *ssec = sk->sk_security; |
| 292 | 292 | ||
| 293 | sk->sk_security = NULL; | 293 | sk->sk_security = NULL; |
| 294 | selinux_netlbl_sk_security_free(ssec); | ||
| 294 | kfree(ssec); | 295 | kfree(ssec); |
| 295 | } | 296 | } |
| 296 | 297 | ||
diff --git a/security/selinux/include/netlabel.h b/security/selinux/include/netlabel.h index 982bac0ac328..b913c8d06038 100644 --- a/security/selinux/include/netlabel.h +++ b/security/selinux/include/netlabel.h | |||
| @@ -41,6 +41,7 @@ void selinux_netlbl_cache_invalidate(void); | |||
| 41 | 41 | ||
| 42 | void selinux_netlbl_err(struct sk_buff *skb, int error, int gateway); | 42 | void selinux_netlbl_err(struct sk_buff *skb, int error, int gateway); |
| 43 | 43 | ||
| 44 | void selinux_netlbl_sk_security_free(struct sk_security_struct *ssec); | ||
| 44 | void selinux_netlbl_sk_security_reset(struct sk_security_struct *ssec, | 45 | void selinux_netlbl_sk_security_reset(struct sk_security_struct *ssec, |
| 45 | int family); | 46 | int family); |
| 46 | 47 | ||
| @@ -77,6 +78,12 @@ static inline void selinux_netlbl_err(struct sk_buff *skb, | |||
| 77 | return; | 78 | return; |
| 78 | } | 79 | } |
| 79 | 80 | ||
| 81 | static inline void selinux_netlbl_sk_security_free( | ||
| 82 | struct sk_security_struct *ssec) | ||
| 83 | { | ||
| 84 | return; | ||
| 85 | } | ||
| 86 | |||
| 80 | static inline void selinux_netlbl_sk_security_reset( | 87 | static inline void selinux_netlbl_sk_security_reset( |
| 81 | struct sk_security_struct *ssec, | 88 | struct sk_security_struct *ssec, |
| 82 | int family) | 89 | int family) |
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h index ad34787c6c02..f8be8d7fa26d 100644 --- a/security/selinux/include/objsec.h +++ b/security/selinux/include/objsec.h | |||
| @@ -109,9 +109,6 @@ struct netport_security_struct { | |||
| 109 | }; | 109 | }; |
| 110 | 110 | ||
| 111 | struct sk_security_struct { | 111 | struct sk_security_struct { |
| 112 | u32 sid; /* SID of this object */ | ||
| 113 | u32 peer_sid; /* SID of peer */ | ||
| 114 | u16 sclass; /* sock security class */ | ||
| 115 | #ifdef CONFIG_NETLABEL | 112 | #ifdef CONFIG_NETLABEL |
| 116 | enum { /* NetLabel state */ | 113 | enum { /* NetLabel state */ |
| 117 | NLBL_UNSET = 0, | 114 | NLBL_UNSET = 0, |
| @@ -120,7 +117,11 @@ struct sk_security_struct { | |||
| 120 | NLBL_REQSKB, | 117 | NLBL_REQSKB, |
| 121 | NLBL_CONNLABELED, | 118 | NLBL_CONNLABELED, |
| 122 | } nlbl_state; | 119 | } nlbl_state; |
| 120 | struct netlbl_lsm_secattr *nlbl_secattr; /* NetLabel sec attributes */ | ||
| 123 | #endif | 121 | #endif |
| 122 | u32 sid; /* SID of this object */ | ||
| 123 | u32 peer_sid; /* SID of peer */ | ||
| 124 | u16 sclass; /* sock security class */ | ||
| 124 | }; | 125 | }; |
| 125 | 126 | ||
| 126 | struct key_security_struct { | 127 | struct key_security_struct { |
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 | } |
