diff options
| author | James Morris <james.l.morris@oracle.com> | 2016-07-06 20:15:34 -0400 |
|---|---|---|
| committer | James Morris <james.l.morris@oracle.com> | 2016-07-06 20:15:34 -0400 |
| commit | d011a4d861ce583466a8ae72a0c8e7f51c8cba4e (patch) | |
| tree | 1ff8dfe7d486f5648e69ee85e54cde1987d8296a /security/selinux | |
| parent | 544e1cea03e6674e3c12a3b8e8cc507c3dbeaf0c (diff) | |
| parent | 3f09354ac84c6904787189d85fb306bf60f714b8 (diff) | |
Merge branch 'stable-4.8' of git://git.infradead.org/users/pcmoore/selinux into next
Diffstat (limited to 'security/selinux')
| -rw-r--r-- | security/selinux/hooks.c | 21 | ||||
| -rw-r--r-- | security/selinux/include/netlabel.h | 4 | ||||
| -rw-r--r-- | security/selinux/netlabel.c | 36 | ||||
| -rw-r--r-- | security/selinux/selinuxfs.c | 2 | ||||
| -rw-r--r-- | security/selinux/ss/ebitmap.c | 2 | ||||
| -rw-r--r-- | security/selinux/ss/services.c | 70 |
6 files changed, 72 insertions, 63 deletions
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index a86d537eb79b..da934342a39f 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
| @@ -4604,13 +4604,13 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) | |||
| 4604 | err = selinux_inet_sys_rcv_skb(sock_net(sk), skb->skb_iif, | 4604 | err = selinux_inet_sys_rcv_skb(sock_net(sk), skb->skb_iif, |
| 4605 | addrp, family, peer_sid, &ad); | 4605 | addrp, family, peer_sid, &ad); |
| 4606 | if (err) { | 4606 | if (err) { |
| 4607 | selinux_netlbl_err(skb, err, 0); | 4607 | selinux_netlbl_err(skb, family, err, 0); |
| 4608 | return err; | 4608 | return err; |
| 4609 | } | 4609 | } |
| 4610 | err = avc_has_perm(sk_sid, peer_sid, SECCLASS_PEER, | 4610 | err = avc_has_perm(sk_sid, peer_sid, SECCLASS_PEER, |
| 4611 | PEER__RECV, &ad); | 4611 | PEER__RECV, &ad); |
| 4612 | if (err) { | 4612 | if (err) { |
| 4613 | selinux_netlbl_err(skb, err, 0); | 4613 | selinux_netlbl_err(skb, family, err, 0); |
| 4614 | return err; | 4614 | return err; |
| 4615 | } | 4615 | } |
| 4616 | } | 4616 | } |
| @@ -4978,7 +4978,7 @@ static unsigned int selinux_ip_forward(struct sk_buff *skb, | |||
| 4978 | err = selinux_inet_sys_rcv_skb(dev_net(indev), indev->ifindex, | 4978 | err = selinux_inet_sys_rcv_skb(dev_net(indev), indev->ifindex, |
| 4979 | addrp, family, peer_sid, &ad); | 4979 | addrp, family, peer_sid, &ad); |
| 4980 | if (err) { | 4980 | if (err) { |
| 4981 | selinux_netlbl_err(skb, err, 1); | 4981 | selinux_netlbl_err(skb, family, err, 1); |
| 4982 | return NF_DROP; | 4982 | return NF_DROP; |
| 4983 | } | 4983 | } |
| 4984 | } | 4984 | } |
| @@ -5064,6 +5064,15 @@ static unsigned int selinux_ipv4_output(void *priv, | |||
| 5064 | return selinux_ip_output(skb, PF_INET); | 5064 | return selinux_ip_output(skb, PF_INET); |
| 5065 | } | 5065 | } |
| 5066 | 5066 | ||
| 5067 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | ||
| 5068 | static unsigned int selinux_ipv6_output(void *priv, | ||
| 5069 | struct sk_buff *skb, | ||
| 5070 | const struct nf_hook_state *state) | ||
| 5071 | { | ||
| 5072 | return selinux_ip_output(skb, PF_INET6); | ||
| 5073 | } | ||
| 5074 | #endif /* IPV6 */ | ||
| 5075 | |||
| 5067 | static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb, | 5076 | static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb, |
| 5068 | int ifindex, | 5077 | int ifindex, |
| 5069 | u16 family) | 5078 | u16 family) |
| @@ -6298,6 +6307,12 @@ static struct nf_hook_ops selinux_nf_ops[] = { | |||
| 6298 | .hooknum = NF_INET_FORWARD, | 6307 | .hooknum = NF_INET_FORWARD, |
| 6299 | .priority = NF_IP6_PRI_SELINUX_FIRST, | 6308 | .priority = NF_IP6_PRI_SELINUX_FIRST, |
| 6300 | }, | 6309 | }, |
| 6310 | { | ||
| 6311 | .hook = selinux_ipv6_output, | ||
| 6312 | .pf = NFPROTO_IPV6, | ||
| 6313 | .hooknum = NF_INET_LOCAL_OUT, | ||
| 6314 | .priority = NF_IP6_PRI_SELINUX_FIRST, | ||
| 6315 | }, | ||
| 6301 | #endif /* IPV6 */ | 6316 | #endif /* IPV6 */ |
| 6302 | }; | 6317 | }; |
| 6303 | 6318 | ||
diff --git a/security/selinux/include/netlabel.h b/security/selinux/include/netlabel.h index 8c59b8f150e8..75686d53df07 100644 --- a/security/selinux/include/netlabel.h +++ b/security/selinux/include/netlabel.h | |||
| @@ -40,7 +40,8 @@ | |||
| 40 | #ifdef CONFIG_NETLABEL | 40 | #ifdef CONFIG_NETLABEL |
| 41 | void selinux_netlbl_cache_invalidate(void); | 41 | void selinux_netlbl_cache_invalidate(void); |
| 42 | 42 | ||
| 43 | void selinux_netlbl_err(struct sk_buff *skb, int error, int gateway); | 43 | void selinux_netlbl_err(struct sk_buff *skb, u16 family, int error, |
| 44 | int gateway); | ||
| 44 | 45 | ||
| 45 | void selinux_netlbl_sk_security_free(struct sk_security_struct *sksec); | 46 | void selinux_netlbl_sk_security_free(struct sk_security_struct *sksec); |
| 46 | void selinux_netlbl_sk_security_reset(struct sk_security_struct *sksec); | 47 | void selinux_netlbl_sk_security_reset(struct sk_security_struct *sksec); |
| @@ -72,6 +73,7 @@ static inline void selinux_netlbl_cache_invalidate(void) | |||
| 72 | } | 73 | } |
| 73 | 74 | ||
| 74 | static inline void selinux_netlbl_err(struct sk_buff *skb, | 75 | static inline void selinux_netlbl_err(struct sk_buff *skb, |
| 76 | u16 family, | ||
| 75 | int error, | 77 | int error, |
| 76 | int gateway) | 78 | int gateway) |
| 77 | { | 79 | { |
diff --git a/security/selinux/netlabel.c b/security/selinux/netlabel.c index 1f989a539fd4..aaba6677ee2e 100644 --- a/security/selinux/netlabel.c +++ b/security/selinux/netlabel.c | |||
| @@ -54,6 +54,7 @@ | |||
| 54 | * | 54 | * |
| 55 | */ | 55 | */ |
| 56 | static int selinux_netlbl_sidlookup_cached(struct sk_buff *skb, | 56 | static int selinux_netlbl_sidlookup_cached(struct sk_buff *skb, |
| 57 | u16 family, | ||
| 57 | struct netlbl_lsm_secattr *secattr, | 58 | struct netlbl_lsm_secattr *secattr, |
| 58 | u32 *sid) | 59 | u32 *sid) |
| 59 | { | 60 | { |
| @@ -63,7 +64,7 @@ static int selinux_netlbl_sidlookup_cached(struct sk_buff *skb, | |||
| 63 | if (rc == 0 && | 64 | if (rc == 0 && |
| 64 | (secattr->flags & NETLBL_SECATTR_CACHEABLE) && | 65 | (secattr->flags & NETLBL_SECATTR_CACHEABLE) && |
| 65 | (secattr->flags & NETLBL_SECATTR_CACHE)) | 66 | (secattr->flags & NETLBL_SECATTR_CACHE)) |
| 66 | netlbl_cache_add(skb, secattr); | 67 | netlbl_cache_add(skb, family, secattr); |
| 67 | 68 | ||
| 68 | return rc; | 69 | return rc; |
| 69 | } | 70 | } |
| @@ -151,9 +152,9 @@ void selinux_netlbl_cache_invalidate(void) | |||
| 151 | * present on the packet, NetLabel is smart enough to only act when it should. | 152 | * present on the packet, NetLabel is smart enough to only act when it should. |
| 152 | * | 153 | * |
| 153 | */ | 154 | */ |
| 154 | void selinux_netlbl_err(struct sk_buff *skb, int error, int gateway) | 155 | void selinux_netlbl_err(struct sk_buff *skb, u16 family, int error, int gateway) |
| 155 | { | 156 | { |
| 156 | netlbl_skbuff_err(skb, error, gateway); | 157 | netlbl_skbuff_err(skb, family, error, gateway); |
| 157 | } | 158 | } |
| 158 | 159 | ||
| 159 | /** | 160 | /** |
| @@ -214,7 +215,8 @@ int selinux_netlbl_skbuff_getsid(struct sk_buff *skb, | |||
| 214 | netlbl_secattr_init(&secattr); | 215 | netlbl_secattr_init(&secattr); |
| 215 | rc = netlbl_skbuff_getattr(skb, family, &secattr); | 216 | rc = netlbl_skbuff_getattr(skb, family, &secattr); |
| 216 | if (rc == 0 && secattr.flags != NETLBL_SECATTR_NONE) | 217 | if (rc == 0 && secattr.flags != NETLBL_SECATTR_NONE) |
| 217 | rc = selinux_netlbl_sidlookup_cached(skb, &secattr, sid); | 218 | rc = selinux_netlbl_sidlookup_cached(skb, family, |
| 219 | &secattr, sid); | ||
| 218 | else | 220 | else |
| 219 | *sid = SECSID_NULL; | 221 | *sid = SECSID_NULL; |
| 220 | *type = secattr.type; | 222 | *type = secattr.type; |
| @@ -284,7 +286,7 @@ int selinux_netlbl_inet_conn_request(struct request_sock *req, u16 family) | |||
| 284 | int rc; | 286 | int rc; |
| 285 | struct netlbl_lsm_secattr secattr; | 287 | struct netlbl_lsm_secattr secattr; |
| 286 | 288 | ||
| 287 | if (family != PF_INET) | 289 | if (family != PF_INET && family != PF_INET6) |
| 288 | return 0; | 290 | return 0; |
| 289 | 291 | ||
| 290 | netlbl_secattr_init(&secattr); | 292 | netlbl_secattr_init(&secattr); |
| @@ -333,7 +335,7 @@ int selinux_netlbl_socket_post_create(struct sock *sk, u16 family) | |||
| 333 | struct sk_security_struct *sksec = sk->sk_security; | 335 | struct sk_security_struct *sksec = sk->sk_security; |
| 334 | struct netlbl_lsm_secattr *secattr; | 336 | struct netlbl_lsm_secattr *secattr; |
| 335 | 337 | ||
| 336 | if (family != PF_INET) | 338 | if (family != PF_INET && family != PF_INET6) |
| 337 | return 0; | 339 | return 0; |
| 338 | 340 | ||
| 339 | secattr = selinux_netlbl_sock_genattr(sk); | 341 | secattr = selinux_netlbl_sock_genattr(sk); |
| @@ -382,7 +384,8 @@ int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec, | |||
| 382 | netlbl_secattr_init(&secattr); | 384 | netlbl_secattr_init(&secattr); |
| 383 | rc = netlbl_skbuff_getattr(skb, family, &secattr); | 385 | rc = netlbl_skbuff_getattr(skb, family, &secattr); |
| 384 | if (rc == 0 && secattr.flags != NETLBL_SECATTR_NONE) | 386 | if (rc == 0 && secattr.flags != NETLBL_SECATTR_NONE) |
| 385 | rc = selinux_netlbl_sidlookup_cached(skb, &secattr, &nlbl_sid); | 387 | rc = selinux_netlbl_sidlookup_cached(skb, family, |
| 388 | &secattr, &nlbl_sid); | ||
| 386 | else | 389 | else |
| 387 | nlbl_sid = SECINITSID_UNLABELED; | 390 | nlbl_sid = SECINITSID_UNLABELED; |
| 388 | netlbl_secattr_destroy(&secattr); | 391 | netlbl_secattr_destroy(&secattr); |
| @@ -405,11 +408,26 @@ int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec, | |||
| 405 | return 0; | 408 | return 0; |
| 406 | 409 | ||
| 407 | if (nlbl_sid != SECINITSID_UNLABELED) | 410 | if (nlbl_sid != SECINITSID_UNLABELED) |
| 408 | netlbl_skbuff_err(skb, rc, 0); | 411 | netlbl_skbuff_err(skb, family, rc, 0); |
| 409 | return rc; | 412 | return rc; |
| 410 | } | 413 | } |
| 411 | 414 | ||
| 412 | /** | 415 | /** |
| 416 | * selinux_netlbl_option - Is this a NetLabel option | ||
| 417 | * @level: the socket level or protocol | ||
| 418 | * @optname: the socket option name | ||
| 419 | * | ||
| 420 | * Description: | ||
| 421 | * Returns true if @level and @optname refer to a NetLabel option. | ||
| 422 | * Helper for selinux_netlbl_socket_setsockopt(). | ||
| 423 | */ | ||
| 424 | static inline int selinux_netlbl_option(int level, int optname) | ||
| 425 | { | ||
| 426 | return (level == IPPROTO_IP && optname == IP_OPTIONS) || | ||
| 427 | (level == IPPROTO_IPV6 && optname == IPV6_HOPOPTS); | ||
| 428 | } | ||
| 429 | |||
| 430 | /** | ||
| 413 | * selinux_netlbl_socket_setsockopt - Do not allow users to remove a NetLabel | 431 | * selinux_netlbl_socket_setsockopt - Do not allow users to remove a NetLabel |
| 414 | * @sock: the socket | 432 | * @sock: the socket |
| 415 | * @level: the socket level or protocol | 433 | * @level: the socket level or protocol |
| @@ -431,7 +449,7 @@ int selinux_netlbl_socket_setsockopt(struct socket *sock, | |||
| 431 | struct sk_security_struct *sksec = sk->sk_security; | 449 | struct sk_security_struct *sksec = sk->sk_security; |
| 432 | struct netlbl_lsm_secattr secattr; | 450 | struct netlbl_lsm_secattr secattr; |
| 433 | 451 | ||
| 434 | if (level == IPPROTO_IP && optname == IP_OPTIONS && | 452 | if (selinux_netlbl_option(level, optname) && |
| 435 | (sksec->nlbl_state == NLBL_LABELED || | 453 | (sksec->nlbl_state == NLBL_LABELED || |
| 436 | sksec->nlbl_state == NLBL_CONNLABELED)) { | 454 | sksec->nlbl_state == NLBL_CONNLABELED)) { |
| 437 | netlbl_secattr_init(&secattr); | 455 | netlbl_secattr_init(&secattr); |
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index 1b1fd27de632..0765c5b053b5 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c | |||
| @@ -1347,7 +1347,7 @@ static ssize_t sel_write_avc_cache_threshold(struct file *file, | |||
| 1347 | { | 1347 | { |
| 1348 | char *page; | 1348 | char *page; |
| 1349 | ssize_t ret; | 1349 | ssize_t ret; |
| 1350 | int new_value; | 1350 | unsigned int new_value; |
| 1351 | 1351 | ||
| 1352 | ret = task_has_security(current, SECURITY__SETSECPARAM); | 1352 | ret = task_has_security(current, SECURITY__SETSECPARAM); |
| 1353 | if (ret) | 1353 | if (ret) |
diff --git a/security/selinux/ss/ebitmap.c b/security/selinux/ss/ebitmap.c index 57644b1dc42e..894b6cdc11c5 100644 --- a/security/selinux/ss/ebitmap.c +++ b/security/selinux/ss/ebitmap.c | |||
| @@ -165,7 +165,7 @@ int ebitmap_netlbl_import(struct ebitmap *ebmap, | |||
| 165 | e_iter = kzalloc(sizeof(*e_iter), GFP_ATOMIC); | 165 | e_iter = kzalloc(sizeof(*e_iter), GFP_ATOMIC); |
| 166 | if (e_iter == NULL) | 166 | if (e_iter == NULL) |
| 167 | goto netlbl_import_failure; | 167 | goto netlbl_import_failure; |
| 168 | e_iter->startbit = offset & ~(EBITMAP_SIZE - 1); | 168 | e_iter->startbit = offset - (offset % EBITMAP_SIZE); |
| 169 | if (e_prev == NULL) | 169 | if (e_prev == NULL) |
| 170 | ebmap->node = e_iter; | 170 | ebmap->node = e_iter; |
| 171 | else | 171 | else |
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index 89df64672b89..082b20c78363 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c | |||
| @@ -543,7 +543,7 @@ static void type_attribute_bounds_av(struct context *scontext, | |||
| 543 | struct av_decision *avd) | 543 | struct av_decision *avd) |
| 544 | { | 544 | { |
| 545 | struct context lo_scontext; | 545 | struct context lo_scontext; |
| 546 | struct context lo_tcontext; | 546 | struct context lo_tcontext, *tcontextp = tcontext; |
| 547 | struct av_decision lo_avd; | 547 | struct av_decision lo_avd; |
| 548 | struct type_datum *source; | 548 | struct type_datum *source; |
| 549 | struct type_datum *target; | 549 | struct type_datum *target; |
| @@ -553,67 +553,41 @@ static void type_attribute_bounds_av(struct context *scontext, | |||
| 553 | scontext->type - 1); | 553 | scontext->type - 1); |
| 554 | BUG_ON(!source); | 554 | BUG_ON(!source); |
| 555 | 555 | ||
| 556 | if (!source->bounds) | ||
| 557 | return; | ||
| 558 | |||
| 556 | target = flex_array_get_ptr(policydb.type_val_to_struct_array, | 559 | target = flex_array_get_ptr(policydb.type_val_to_struct_array, |
| 557 | tcontext->type - 1); | 560 | tcontext->type - 1); |
| 558 | BUG_ON(!target); | 561 | BUG_ON(!target); |
| 559 | 562 | ||
| 560 | if (source->bounds) { | 563 | memset(&lo_avd, 0, sizeof(lo_avd)); |
| 561 | memset(&lo_avd, 0, sizeof(lo_avd)); | ||
| 562 | |||
| 563 | memcpy(&lo_scontext, scontext, sizeof(lo_scontext)); | ||
| 564 | lo_scontext.type = source->bounds; | ||
| 565 | 564 | ||
| 566 | context_struct_compute_av(&lo_scontext, | 565 | memcpy(&lo_scontext, scontext, sizeof(lo_scontext)); |
| 567 | tcontext, | 566 | lo_scontext.type = source->bounds; |
| 568 | tclass, | ||
| 569 | &lo_avd, | ||
| 570 | NULL); | ||
| 571 | if ((lo_avd.allowed & avd->allowed) == avd->allowed) | ||
| 572 | return; /* no masked permission */ | ||
| 573 | masked = ~lo_avd.allowed & avd->allowed; | ||
| 574 | } | ||
| 575 | 567 | ||
| 576 | if (target->bounds) { | 568 | if (target->bounds) { |
| 577 | memset(&lo_avd, 0, sizeof(lo_avd)); | ||
| 578 | |||
| 579 | memcpy(&lo_tcontext, tcontext, sizeof(lo_tcontext)); | 569 | memcpy(&lo_tcontext, tcontext, sizeof(lo_tcontext)); |
| 580 | lo_tcontext.type = target->bounds; | 570 | lo_tcontext.type = target->bounds; |
| 581 | 571 | tcontextp = &lo_tcontext; | |
| 582 | context_struct_compute_av(scontext, | ||
| 583 | &lo_tcontext, | ||
| 584 | tclass, | ||
| 585 | &lo_avd, | ||
| 586 | NULL); | ||
| 587 | if ((lo_avd.allowed & avd->allowed) == avd->allowed) | ||
| 588 | return; /* no masked permission */ | ||
| 589 | masked = ~lo_avd.allowed & avd->allowed; | ||
| 590 | } | 572 | } |
| 591 | 573 | ||
| 592 | if (source->bounds && target->bounds) { | 574 | context_struct_compute_av(&lo_scontext, |
| 593 | memset(&lo_avd, 0, sizeof(lo_avd)); | 575 | tcontextp, |
| 594 | /* | 576 | tclass, |
| 595 | * lo_scontext and lo_tcontext are already | 577 | &lo_avd, |
| 596 | * set up. | 578 | NULL); |
| 597 | */ | ||
| 598 | 579 | ||
| 599 | context_struct_compute_av(&lo_scontext, | 580 | masked = ~lo_avd.allowed & avd->allowed; |
| 600 | &lo_tcontext, | ||
| 601 | tclass, | ||
| 602 | &lo_avd, | ||
| 603 | NULL); | ||
| 604 | if ((lo_avd.allowed & avd->allowed) == avd->allowed) | ||
| 605 | return; /* no masked permission */ | ||
| 606 | masked = ~lo_avd.allowed & avd->allowed; | ||
| 607 | } | ||
| 608 | 581 | ||
| 609 | if (masked) { | 582 | if (likely(!masked)) |
| 610 | /* mask violated permissions */ | 583 | return; /* no masked permission */ |
| 611 | avd->allowed &= ~masked; | ||
| 612 | 584 | ||
| 613 | /* audit masked permissions */ | 585 | /* mask violated permissions */ |
| 614 | security_dump_masked_av(scontext, tcontext, | 586 | avd->allowed &= ~masked; |
| 615 | tclass, masked, "bounds"); | 587 | |
| 616 | } | 588 | /* audit masked permissions */ |
| 589 | security_dump_masked_av(scontext, tcontext, | ||
| 590 | tclass, masked, "bounds"); | ||
| 617 | } | 591 | } |
| 618 | 592 | ||
| 619 | /* | 593 | /* |
