diff options
| -rw-r--r-- | include/net/cipso_ipv4.h | 5 | ||||
| -rw-r--r-- | include/net/netlabel.h | 13 | ||||
| -rw-r--r-- | net/ipv4/cipso_ipv4.c | 74 | ||||
| -rw-r--r-- | net/netlabel/netlabel_kapi.c | 78 | ||||
| -rw-r--r-- | security/selinux/hooks.c | 11 | ||||
| -rw-r--r-- | security/selinux/include/netlabel.h | 19 | ||||
| -rw-r--r-- | security/selinux/include/objsec.h | 1 | ||||
| -rw-r--r-- | security/selinux/netlabel.c | 147 |
8 files changed, 311 insertions, 37 deletions
diff --git a/include/net/cipso_ipv4.h b/include/net/cipso_ipv4.h index 2ce093ba553d..811febf97caf 100644 --- a/include/net/cipso_ipv4.h +++ b/include/net/cipso_ipv4.h | |||
| @@ -207,6 +207,7 @@ void cipso_v4_error(struct sk_buff *skb, int error, u32 gateway); | |||
| 207 | int cipso_v4_sock_setattr(struct sock *sk, | 207 | int cipso_v4_sock_setattr(struct sock *sk, |
| 208 | const struct cipso_v4_doi *doi_def, | 208 | const struct cipso_v4_doi *doi_def, |
| 209 | const struct netlbl_lsm_secattr *secattr); | 209 | const struct netlbl_lsm_secattr *secattr); |
| 210 | void cipso_v4_sock_delattr(struct sock *sk); | ||
| 210 | int cipso_v4_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr); | 211 | int cipso_v4_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr); |
| 211 | int cipso_v4_skbuff_setattr(struct sk_buff *skb, | 212 | int cipso_v4_skbuff_setattr(struct sk_buff *skb, |
| 212 | const struct cipso_v4_doi *doi_def, | 213 | const struct cipso_v4_doi *doi_def, |
| @@ -230,6 +231,10 @@ static inline int cipso_v4_sock_setattr(struct sock *sk, | |||
| 230 | return -ENOSYS; | 231 | return -ENOSYS; |
| 231 | } | 232 | } |
| 232 | 233 | ||
| 234 | static inline void cipso_v4_sock_delattr(struct sock *sk) | ||
| 235 | { | ||
| 236 | } | ||
| 237 | |||
| 233 | static inline int cipso_v4_sock_getattr(struct sock *sk, | 238 | static inline int cipso_v4_sock_getattr(struct sock *sk, |
| 234 | struct netlbl_lsm_secattr *secattr) | 239 | struct netlbl_lsm_secattr *secattr) |
| 235 | { | 240 | { |
diff --git a/include/net/netlabel.h b/include/net/netlabel.h index 3f67e6d49e40..074cad40ac66 100644 --- a/include/net/netlabel.h +++ b/include/net/netlabel.h | |||
| @@ -380,8 +380,12 @@ int netlbl_secattr_catmap_setrng(struct netlbl_lsm_secattr_catmap *catmap, | |||
| 380 | int netlbl_enabled(void); | 380 | int netlbl_enabled(void); |
| 381 | int netlbl_sock_setattr(struct sock *sk, | 381 | int netlbl_sock_setattr(struct sock *sk, |
| 382 | const struct netlbl_lsm_secattr *secattr); | 382 | const struct netlbl_lsm_secattr *secattr); |
| 383 | void netlbl_sock_delattr(struct sock *sk); | ||
| 383 | int netlbl_sock_getattr(struct sock *sk, | 384 | int netlbl_sock_getattr(struct sock *sk, |
| 384 | struct netlbl_lsm_secattr *secattr); | 385 | struct netlbl_lsm_secattr *secattr); |
| 386 | int netlbl_conn_setattr(struct sock *sk, | ||
| 387 | struct sockaddr *addr, | ||
| 388 | const struct netlbl_lsm_secattr *secattr); | ||
| 385 | int netlbl_skbuff_setattr(struct sk_buff *skb, | 389 | int netlbl_skbuff_setattr(struct sk_buff *skb, |
| 386 | u16 family, | 390 | u16 family, |
| 387 | const struct netlbl_lsm_secattr *secattr); | 391 | const struct netlbl_lsm_secattr *secattr); |
| @@ -449,11 +453,20 @@ static inline int netlbl_sock_setattr(struct sock *sk, | |||
| 449 | { | 453 | { |
| 450 | return -ENOSYS; | 454 | return -ENOSYS; |
| 451 | } | 455 | } |
| 456 | static inline void netlbl_sock_delattr(struct sock *sk) | ||
| 457 | { | ||
| 458 | } | ||
| 452 | static inline int netlbl_sock_getattr(struct sock *sk, | 459 | static inline int netlbl_sock_getattr(struct sock *sk, |
| 453 | struct netlbl_lsm_secattr *secattr) | 460 | struct netlbl_lsm_secattr *secattr) |
| 454 | { | 461 | { |
| 455 | return -ENOSYS; | 462 | return -ENOSYS; |
| 456 | } | 463 | } |
| 464 | static inline int netlbl_conn_setattr(struct sock *sk, | ||
| 465 | struct sockaddr *addr, | ||
| 466 | const struct netlbl_lsm_secattr *secattr) | ||
| 467 | { | ||
| 468 | return -ENOSYS; | ||
| 469 | } | ||
| 457 | static inline int netlbl_skbuff_setattr(struct sk_buff *skb, | 470 | static inline int netlbl_skbuff_setattr(struct sk_buff *skb, |
| 458 | u16 family, | 471 | u16 family, |
| 459 | const struct netlbl_lsm_secattr *secattr) | 472 | const struct netlbl_lsm_secattr *secattr) |
diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c index e13d6dbb66ab..23768b9d6b64 100644 --- a/net/ipv4/cipso_ipv4.c +++ b/net/ipv4/cipso_ipv4.c | |||
| @@ -1810,6 +1810,80 @@ socket_setattr_failure: | |||
| 1810 | } | 1810 | } |
| 1811 | 1811 | ||
| 1812 | /** | 1812 | /** |
| 1813 | * cipso_v4_sock_delattr - Delete the CIPSO option from a socket | ||
| 1814 | * @sk: the socket | ||
| 1815 | * | ||
| 1816 | * Description: | ||
| 1817 | * Removes the CIPSO option from a socket, if present. | ||
| 1818 | * | ||
| 1819 | */ | ||
| 1820 | void cipso_v4_sock_delattr(struct sock *sk) | ||
| 1821 | { | ||
| 1822 | u8 hdr_delta; | ||
| 1823 | struct ip_options *opt; | ||
| 1824 | struct inet_sock *sk_inet; | ||
| 1825 | |||
| 1826 | sk_inet = inet_sk(sk); | ||
| 1827 | opt = sk_inet->opt; | ||
| 1828 | if (opt == NULL || opt->cipso == 0) | ||
| 1829 | return; | ||
| 1830 | |||
| 1831 | if (opt->srr || opt->rr || opt->ts || opt->router_alert) { | ||
| 1832 | u8 cipso_len; | ||
| 1833 | u8 cipso_off; | ||
| 1834 | unsigned char *cipso_ptr; | ||
| 1835 | int iter; | ||
| 1836 | int optlen_new; | ||
| 1837 | |||
| 1838 | cipso_off = opt->cipso - sizeof(struct iphdr); | ||
| 1839 | cipso_ptr = &opt->__data[cipso_off]; | ||
| 1840 | cipso_len = cipso_ptr[1]; | ||
| 1841 | |||
| 1842 | if (opt->srr > opt->cipso) | ||
| 1843 | opt->srr -= cipso_len; | ||
| 1844 | if (opt->rr > opt->cipso) | ||
| 1845 | opt->rr -= cipso_len; | ||
| 1846 | if (opt->ts > opt->cipso) | ||
| 1847 | opt->ts -= cipso_len; | ||
| 1848 | if (opt->router_alert > opt->cipso) | ||
| 1849 | opt->router_alert -= cipso_len; | ||
| 1850 | opt->cipso = 0; | ||
| 1851 | |||
| 1852 | memmove(cipso_ptr, cipso_ptr + cipso_len, | ||
| 1853 | opt->optlen - cipso_off - cipso_len); | ||
| 1854 | |||
| 1855 | /* determining the new total option length is tricky because of | ||
| 1856 | * the padding necessary, the only thing i can think to do at | ||
| 1857 | * this point is walk the options one-by-one, skipping the | ||
| 1858 | * padding at the end to determine the actual option size and | ||
| 1859 | * from there we can determine the new total option length */ | ||
| 1860 | iter = 0; | ||
| 1861 | optlen_new = 0; | ||
| 1862 | while (iter < opt->optlen) | ||
| 1863 | if (opt->__data[iter] != IPOPT_NOP) { | ||
| 1864 | iter += opt->__data[iter + 1]; | ||
| 1865 | optlen_new = iter; | ||
| 1866 | } else | ||
| 1867 | iter++; | ||
| 1868 | hdr_delta = opt->optlen; | ||
| 1869 | opt->optlen = (optlen_new + 3) & ~3; | ||
| 1870 | hdr_delta -= opt->optlen; | ||
| 1871 | } else { | ||
| 1872 | /* only the cipso option was present on the socket so we can | ||
| 1873 | * remove the entire option struct */ | ||
| 1874 | sk_inet->opt = NULL; | ||
| 1875 | hdr_delta = opt->optlen; | ||
| 1876 | kfree(opt); | ||
| 1877 | } | ||
| 1878 | |||
| 1879 | if (sk_inet->is_icsk && hdr_delta > 0) { | ||
| 1880 | struct inet_connection_sock *sk_conn = inet_csk(sk); | ||
| 1881 | sk_conn->icsk_ext_hdr_len -= hdr_delta; | ||
| 1882 | sk_conn->icsk_sync_mss(sk, sk_conn->icsk_pmtu_cookie); | ||
| 1883 | } | ||
| 1884 | } | ||
| 1885 | |||
| 1886 | /** | ||
| 1813 | * cipso_v4_getattr - Helper function for the cipso_v4_*_getattr functions | 1887 | * cipso_v4_getattr - Helper function for the cipso_v4_*_getattr functions |
| 1814 | * @cipso: the CIPSO v4 option | 1888 | * @cipso: the CIPSO v4 option |
| 1815 | * @secattr: the security attributes | 1889 | * @secattr: the security attributes |
diff --git a/net/netlabel/netlabel_kapi.c b/net/netlabel/netlabel_kapi.c index cc8047d1f505..78fc557689b2 100644 --- a/net/netlabel/netlabel_kapi.c +++ b/net/netlabel/netlabel_kapi.c | |||
| @@ -10,7 +10,7 @@ | |||
| 10 | */ | 10 | */ |
| 11 | 11 | ||
| 12 | /* | 12 | /* |
| 13 | * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 | 13 | * (c) Copyright Hewlett-Packard Development Company, L.P., 2006, 2008 |
| 14 | * | 14 | * |
| 15 | * This program is free software; you can redistribute it and/or modify | 15 | * This program is free software; you can redistribute it and/or modify |
| 16 | * it under the terms of the GNU General Public License as published by | 16 | * it under the terms of the GNU General Public License as published by |
| @@ -456,6 +456,20 @@ socket_setattr_return: | |||
| 456 | } | 456 | } |
| 457 | 457 | ||
| 458 | /** | 458 | /** |
| 459 | * netlbl_sock_delattr - Delete all the NetLabel labels on a socket | ||
| 460 | * @sk: the socket | ||
| 461 | * | ||
| 462 | * Description: | ||
| 463 | * Remove all the NetLabel labeling from @sk. The caller is responsible for | ||
| 464 | * ensuring that @sk is locked. | ||
| 465 | * | ||
| 466 | */ | ||
| 467 | void netlbl_sock_delattr(struct sock *sk) | ||
| 468 | { | ||
| 469 | cipso_v4_sock_delattr(sk); | ||
| 470 | } | ||
| 471 | |||
| 472 | /** | ||
| 459 | * netlbl_sock_getattr - Determine the security attributes of a sock | 473 | * netlbl_sock_getattr - Determine the security attributes of a sock |
| 460 | * @sk: the sock | 474 | * @sk: the sock |
| 461 | * @secattr: the security attributes | 475 | * @secattr: the security attributes |
| @@ -473,6 +487,68 @@ int netlbl_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr) | |||
| 473 | } | 487 | } |
| 474 | 488 | ||
| 475 | /** | 489 | /** |
| 490 | * netlbl_conn_setattr - Label a connected socket using the correct protocol | ||
| 491 | * @sk: the socket to label | ||
| 492 | * @addr: the destination address | ||
| 493 | * @secattr: the security attributes | ||
| 494 | * | ||
| 495 | * Description: | ||
| 496 | * Attach the correct label to the given connected socket using the security | ||
| 497 | * attributes specified in @secattr. The caller is responsible for ensuring | ||
| 498 | * that @sk is locked. Returns zero on success, negative values on failure. | ||
| 499 | * | ||
| 500 | */ | ||
| 501 | int netlbl_conn_setattr(struct sock *sk, | ||
| 502 | struct sockaddr *addr, | ||
| 503 | const struct netlbl_lsm_secattr *secattr) | ||
| 504 | { | ||
| 505 | int ret_val; | ||
| 506 | struct sockaddr_in *addr4; | ||
| 507 | struct netlbl_domaddr4_map *af4_entry; | ||
| 508 | |||
| 509 | rcu_read_lock(); | ||
| 510 | switch (addr->sa_family) { | ||
| 511 | case AF_INET: | ||
| 512 | addr4 = (struct sockaddr_in *)addr; | ||
| 513 | af4_entry = netlbl_domhsh_getentry_af4(secattr->domain, | ||
| 514 | addr4->sin_addr.s_addr); | ||
| 515 | if (af4_entry == NULL) { | ||
| 516 | ret_val = -ENOENT; | ||
| 517 | goto conn_setattr_return; | ||
| 518 | } | ||
| 519 | switch (af4_entry->type) { | ||
| 520 | case NETLBL_NLTYPE_CIPSOV4: | ||
| 521 | ret_val = cipso_v4_sock_setattr(sk, | ||
| 522 | af4_entry->type_def.cipsov4, | ||
| 523 | secattr); | ||
| 524 | break; | ||
| 525 | case NETLBL_NLTYPE_UNLABELED: | ||
| 526 | /* just delete the protocols we support for right now | ||
| 527 | * but we could remove other protocols if needed */ | ||
| 528 | cipso_v4_sock_delattr(sk); | ||
| 529 | ret_val = 0; | ||
| 530 | break; | ||
| 531 | default: | ||
| 532 | ret_val = -ENOENT; | ||
| 533 | } | ||
| 534 | break; | ||
| 535 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | ||
| 536 | case AF_INET6: | ||
| 537 | /* since we don't support any IPv6 labeling protocols right | ||
| 538 | * now we can optimize everything away until we do */ | ||
| 539 | ret_val = 0; | ||
| 540 | break; | ||
| 541 | #endif /* IPv6 */ | ||
| 542 | default: | ||
| 543 | ret_val = 0; | ||
| 544 | } | ||
| 545 | |||
| 546 | conn_setattr_return: | ||
| 547 | rcu_read_unlock(); | ||
| 548 | return ret_val; | ||
| 549 | } | ||
| 550 | |||
| 551 | /** | ||
| 476 | * netlbl_skbuff_setattr - Label a packet using the correct protocol | 552 | * netlbl_skbuff_setattr - Label a packet using the correct protocol |
| 477 | * @skb: the packet | 553 | * @skb: the packet |
| 478 | * @family: protocol family | 554 | * @family: protocol family |
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 7432bdd5d367..632ac3e80a61 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
| @@ -3794,6 +3794,7 @@ out: | |||
| 3794 | 3794 | ||
| 3795 | static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, int addrlen) | 3795 | static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, int addrlen) |
| 3796 | { | 3796 | { |
| 3797 | struct sock *sk = sock->sk; | ||
| 3797 | struct inode_security_struct *isec; | 3798 | struct inode_security_struct *isec; |
| 3798 | int err; | 3799 | int err; |
| 3799 | 3800 | ||
| @@ -3807,7 +3808,6 @@ static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, | |||
| 3807 | isec = SOCK_INODE(sock)->i_security; | 3808 | isec = SOCK_INODE(sock)->i_security; |
| 3808 | if (isec->sclass == SECCLASS_TCP_SOCKET || | 3809 | if (isec->sclass == SECCLASS_TCP_SOCKET || |
| 3809 | isec->sclass == SECCLASS_DCCP_SOCKET) { | 3810 | isec->sclass == SECCLASS_DCCP_SOCKET) { |
| 3810 | struct sock *sk = sock->sk; | ||
| 3811 | struct avc_audit_data ad; | 3811 | struct avc_audit_data ad; |
| 3812 | struct sockaddr_in *addr4 = NULL; | 3812 | struct sockaddr_in *addr4 = NULL; |
| 3813 | struct sockaddr_in6 *addr6 = NULL; | 3813 | struct sockaddr_in6 *addr6 = NULL; |
| @@ -3841,6 +3841,8 @@ static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, | |||
| 3841 | goto out; | 3841 | goto out; |
| 3842 | } | 3842 | } |
| 3843 | 3843 | ||
| 3844 | err = selinux_netlbl_socket_connect(sk, address); | ||
| 3845 | |||
| 3844 | out: | 3846 | out: |
| 3845 | return err; | 3847 | return err; |
| 3846 | } | 3848 | } |
| @@ -4290,8 +4292,6 @@ static void selinux_sock_graft(struct sock *sk, struct socket *parent) | |||
| 4290 | sk->sk_family == PF_UNIX) | 4292 | sk->sk_family == PF_UNIX) |
| 4291 | isec->sid = sksec->sid; | 4293 | isec->sid = sksec->sid; |
| 4292 | sksec->sclass = isec->sclass; | 4294 | sksec->sclass = isec->sclass; |
| 4293 | |||
| 4294 | selinux_netlbl_sock_graft(sk, parent); | ||
| 4295 | } | 4295 | } |
| 4296 | 4296 | ||
| 4297 | static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb, | 4297 | static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb, |
| @@ -4342,8 +4342,7 @@ static void selinux_inet_csk_clone(struct sock *newsk, | |||
| 4342 | selinux_netlbl_sk_security_reset(newsksec, req->rsk_ops->family); | 4342 | selinux_netlbl_sk_security_reset(newsksec, req->rsk_ops->family); |
| 4343 | } | 4343 | } |
| 4344 | 4344 | ||
| 4345 | static void selinux_inet_conn_established(struct sock *sk, | 4345 | static void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb) |
| 4346 | struct sk_buff *skb) | ||
| 4347 | { | 4346 | { |
| 4348 | u16 family = sk->sk_family; | 4347 | u16 family = sk->sk_family; |
| 4349 | struct sk_security_struct *sksec = sk->sk_security; | 4348 | struct sk_security_struct *sksec = sk->sk_security; |
| @@ -4353,6 +4352,8 @@ static void selinux_inet_conn_established(struct sock *sk, | |||
| 4353 | family = PF_INET; | 4352 | family = PF_INET; |
| 4354 | 4353 | ||
| 4355 | selinux_skb_peerlbl_sid(skb, family, &sksec->peer_sid); | 4354 | selinux_skb_peerlbl_sid(skb, family, &sksec->peer_sid); |
| 4355 | |||
| 4356 | selinux_netlbl_inet_conn_established(sk, family); | ||
| 4356 | } | 4357 | } |
| 4357 | 4358 | ||
| 4358 | static void selinux_req_classify_flow(const struct request_sock *req, | 4359 | static void selinux_req_classify_flow(const struct request_sock *req, |
diff --git a/security/selinux/include/netlabel.h b/security/selinux/include/netlabel.h index b3e6ae071fc3..982bac0ac328 100644 --- a/security/selinux/include/netlabel.h +++ b/security/selinux/include/netlabel.h | |||
| @@ -52,7 +52,7 @@ int selinux_netlbl_skbuff_setsid(struct sk_buff *skb, | |||
| 52 | u16 family, | 52 | u16 family, |
| 53 | u32 sid); | 53 | u32 sid); |
| 54 | 54 | ||
| 55 | void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock); | 55 | void selinux_netlbl_inet_conn_established(struct sock *sk, u16 family); |
| 56 | int selinux_netlbl_socket_post_create(struct socket *sock); | 56 | int selinux_netlbl_socket_post_create(struct socket *sock); |
| 57 | int selinux_netlbl_inode_permission(struct inode *inode, int mask); | 57 | int selinux_netlbl_inode_permission(struct inode *inode, int mask); |
| 58 | int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec, | 58 | int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec, |
| @@ -62,6 +62,8 @@ int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec, | |||
| 62 | int selinux_netlbl_socket_setsockopt(struct socket *sock, | 62 | int selinux_netlbl_socket_setsockopt(struct socket *sock, |
| 63 | int level, | 63 | int level, |
| 64 | int optname); | 64 | int optname); |
| 65 | int selinux_netlbl_socket_connect(struct sock *sk, struct sockaddr *addr); | ||
| 66 | |||
| 65 | #else | 67 | #else |
| 66 | static inline void selinux_netlbl_cache_invalidate(void) | 68 | static inline void selinux_netlbl_cache_invalidate(void) |
| 67 | { | 69 | { |
| @@ -98,8 +100,14 @@ static inline int selinux_netlbl_skbuff_setsid(struct sk_buff *skb, | |||
| 98 | return 0; | 100 | return 0; |
| 99 | } | 101 | } |
| 100 | 102 | ||
| 101 | static inline void selinux_netlbl_sock_graft(struct sock *sk, | 103 | static inline int selinux_netlbl_conn_setsid(struct sock *sk, |
| 102 | struct socket *sock) | 104 | struct sockaddr *addr) |
| 105 | { | ||
| 106 | return 0; | ||
| 107 | } | ||
| 108 | |||
| 109 | static inline void selinux_netlbl_inet_conn_established(struct sock *sk, | ||
| 110 | u16 family) | ||
| 103 | { | 111 | { |
| 104 | return; | 112 | return; |
| 105 | } | 113 | } |
| @@ -125,6 +133,11 @@ static inline int selinux_netlbl_socket_setsockopt(struct socket *sock, | |||
| 125 | { | 133 | { |
| 126 | return 0; | 134 | return 0; |
| 127 | } | 135 | } |
| 136 | static inline int selinux_netlbl_socket_connect(struct sock *sk, | ||
| 137 | struct sockaddr *addr) | ||
| 138 | { | ||
| 139 | return 0; | ||
| 140 | } | ||
| 128 | #endif /* CONFIG_NETLABEL */ | 141 | #endif /* CONFIG_NETLABEL */ |
| 129 | 142 | ||
| 130 | #endif | 143 | #endif |
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h index f46dd1c3d01c..ad34787c6c02 100644 --- a/security/selinux/include/objsec.h +++ b/security/selinux/include/objsec.h | |||
| @@ -118,6 +118,7 @@ struct sk_security_struct { | |||
| 118 | NLBL_REQUIRE, | 118 | NLBL_REQUIRE, |
| 119 | NLBL_LABELED, | 119 | NLBL_LABELED, |
| 120 | NLBL_REQSKB, | 120 | NLBL_REQSKB, |
| 121 | NLBL_CONNLABELED, | ||
| 121 | } nlbl_state; | 122 | } nlbl_state; |
| 122 | #endif | 123 | #endif |
| 123 | }; | 124 | }; |
diff --git a/security/selinux/netlabel.c b/security/selinux/netlabel.c index 090404d6e512..b22b7dafa0e3 100644 --- a/security/selinux/netlabel.c +++ b/security/selinux/netlabel.c | |||
| @@ -29,10 +29,12 @@ | |||
| 29 | 29 | ||
| 30 | #include <linux/spinlock.h> | 30 | #include <linux/spinlock.h> |
| 31 | #include <linux/rcupdate.h> | 31 | #include <linux/rcupdate.h> |
| 32 | #include <linux/ip.h> | ||
| 33 | #include <linux/ipv6.h> | ||
| 32 | #include <net/sock.h> | 34 | #include <net/sock.h> |
| 33 | #include <net/netlabel.h> | 35 | #include <net/netlabel.h> |
| 34 | #include <net/inet_sock.h> | 36 | #include <net/ip.h> |
| 35 | #include <net/inet_connection_sock.h> | 37 | #include <net/ipv6.h> |
| 36 | 38 | ||
| 37 | #include "objsec.h" | 39 | #include "objsec.h" |
| 38 | #include "security.h" | 40 | #include "security.h" |
| @@ -79,8 +81,6 @@ static int selinux_netlbl_sock_setsid(struct sock *sk) | |||
| 79 | int rc; | 81 | int rc; |
| 80 | struct sk_security_struct *sksec = sk->sk_security; | 82 | struct sk_security_struct *sksec = sk->sk_security; |
| 81 | struct netlbl_lsm_secattr secattr; | 83 | struct netlbl_lsm_secattr secattr; |
| 82 | struct inet_sock *sk_inet; | ||
| 83 | struct inet_connection_sock *sk_conn; | ||
| 84 | 84 | ||
| 85 | if (sksec->nlbl_state != NLBL_REQUIRE) | 85 | if (sksec->nlbl_state != NLBL_REQUIRE) |
| 86 | return 0; | 86 | return 0; |
| @@ -96,20 +96,6 @@ static int selinux_netlbl_sock_setsid(struct sock *sk) | |||
| 96 | sksec->nlbl_state = NLBL_LABELED; | 96 | sksec->nlbl_state = NLBL_LABELED; |
| 97 | break; | 97 | break; |
| 98 | case -EDESTADDRREQ: | 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; | 99 | sksec->nlbl_state = NLBL_REQSKB; |
| 114 | rc = 0; | 100 | rc = 0; |
| 115 | break; | 101 | break; |
| @@ -247,21 +233,77 @@ skbuff_setsid_return: | |||
| 247 | } | 233 | } |
| 248 | 234 | ||
| 249 | /** | 235 | /** |
| 250 | * selinux_netlbl_sock_graft - Netlabel the new socket | 236 | * selinux_netlbl_inet_conn_established - Netlabel the newly accepted connection |
| 251 | * @sk: the new connection | 237 | * @sk: the new connection |
| 252 | * @sock: the new socket | ||
| 253 | * | 238 | * |
| 254 | * Description: | 239 | * Description: |
| 255 | * The connection represented by @sk is being grafted onto @sock so set the | 240 | * A new connection has been established on @sk so make sure it is labeled |
| 256 | * socket's NetLabel to match the SID of @sk. | 241 | * correctly with the NetLabel susbsystem. |
| 257 | * | 242 | * |
| 258 | */ | 243 | */ |
| 259 | void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock) | 244 | void selinux_netlbl_inet_conn_established(struct sock *sk, u16 family) |
| 260 | { | 245 | { |
| 261 | /* Try to set the NetLabel on the socket to save time later, if we fail | 246 | int rc; |
| 262 | * here we will pick up the pieces in later calls to | 247 | struct sk_security_struct *sksec = sk->sk_security; |
| 263 | * selinux_netlbl_inode_permission(). */ | 248 | struct netlbl_lsm_secattr secattr; |
| 264 | selinux_netlbl_sock_setsid(sk); | 249 | struct inet_sock *sk_inet = inet_sk(sk); |
| 250 | struct sockaddr_in addr; | ||
| 251 | |||
| 252 | if (sksec->nlbl_state != NLBL_REQUIRE) | ||
| 253 | return; | ||
| 254 | |||
| 255 | netlbl_secattr_init(&secattr); | ||
| 256 | if (security_netlbl_sid_to_secattr(sksec->sid, &secattr) != 0) | ||
| 257 | goto inet_conn_established_return; | ||
| 258 | |||
| 259 | rc = netlbl_sock_setattr(sk, &secattr); | ||
| 260 | switch (rc) { | ||
| 261 | case 0: | ||
| 262 | sksec->nlbl_state = NLBL_LABELED; | ||
| 263 | break; | ||
| 264 | case -EDESTADDRREQ: | ||
| 265 | /* no PF_INET6 support yet because we don't support any IPv6 | ||
| 266 | * labeling protocols */ | ||
| 267 | if (family != PF_INET) { | ||
| 268 | sksec->nlbl_state = NLBL_UNSET; | ||
| 269 | goto inet_conn_established_return; | ||
| 270 | } | ||
| 271 | |||
| 272 | addr.sin_family = family; | ||
| 273 | addr.sin_addr.s_addr = sk_inet->daddr; | ||
| 274 | if (netlbl_conn_setattr(sk, (struct sockaddr *)&addr, | ||
| 275 | &secattr) != 0) { | ||
| 276 | /* we failed to label the connected socket (could be | ||
| 277 | * for a variety of reasons, the actual "why" isn't | ||
| 278 | * important here) so we have to go to our backup plan, | ||
| 279 | * labeling the packets individually in the netfilter | ||
| 280 | * local output hook. this is okay but we need to | ||
| 281 | * adjust the MSS of the connection to take into | ||
| 282 | * account any labeling overhead, since we don't know | ||
| 283 | * the exact overhead at this point we'll use the worst | ||
| 284 | * case value which is 40 bytes for IPv4 */ | ||
| 285 | struct inet_connection_sock *sk_conn = inet_csk(sk); | ||
| 286 | sk_conn->icsk_ext_hdr_len += 40 - | ||
| 287 | (sk_inet->opt ? sk_inet->opt->optlen : 0); | ||
| 288 | sk_conn->icsk_sync_mss(sk, sk_conn->icsk_pmtu_cookie); | ||
| 289 | |||
| 290 | sksec->nlbl_state = NLBL_REQSKB; | ||
| 291 | } else | ||
| 292 | sksec->nlbl_state = NLBL_CONNLABELED; | ||
| 293 | break; | ||
| 294 | default: | ||
| 295 | /* note that we are failing to label the socket which could be | ||
| 296 | * a bad thing since it means traffic could leave the system | ||
| 297 | * without the desired labeling, however, all is not lost as | ||
| 298 | * we have a check in selinux_netlbl_inode_permission() to | ||
| 299 | * pick up the pieces that we might drop here because we can't | ||
| 300 | * return an error code */ | ||
| 301 | break; | ||
| 302 | } | ||
| 303 | |||
| 304 | inet_conn_established_return: | ||
| 305 | netlbl_secattr_destroy(&secattr); | ||
| 306 | return; | ||
| 265 | } | 307 | } |
| 266 | 308 | ||
| 267 | /** | 309 | /** |
| @@ -398,7 +440,8 @@ int selinux_netlbl_socket_setsockopt(struct socket *sock, | |||
| 398 | struct netlbl_lsm_secattr secattr; | 440 | struct netlbl_lsm_secattr secattr; |
| 399 | 441 | ||
| 400 | if (level == IPPROTO_IP && optname == IP_OPTIONS && | 442 | if (level == IPPROTO_IP && optname == IP_OPTIONS && |
| 401 | sksec->nlbl_state == NLBL_LABELED) { | 443 | (sksec->nlbl_state == NLBL_LABELED || |
| 444 | sksec->nlbl_state == NLBL_CONNLABELED)) { | ||
| 402 | netlbl_secattr_init(&secattr); | 445 | netlbl_secattr_init(&secattr); |
| 403 | lock_sock(sk); | 446 | lock_sock(sk); |
| 404 | rc = netlbl_sock_getattr(sk, &secattr); | 447 | rc = netlbl_sock_getattr(sk, &secattr); |
| @@ -410,3 +453,51 @@ int selinux_netlbl_socket_setsockopt(struct socket *sock, | |||
| 410 | 453 | ||
| 411 | return rc; | 454 | return rc; |
| 412 | } | 455 | } |
| 456 | |||
| 457 | /** | ||
| 458 | * selinux_netlbl_socket_connect - Label a client-side socket on connect | ||
| 459 | * @sk: the socket to label | ||
| 460 | * @addr: the destination address | ||
| 461 | * | ||
| 462 | * Description: | ||
| 463 | * Attempt to label a connected socket with NetLabel using the given address. | ||
| 464 | * Returns zero values on success, negative values on failure. | ||
| 465 | * | ||
| 466 | */ | ||
| 467 | int selinux_netlbl_socket_connect(struct sock *sk, struct sockaddr *addr) | ||
| 468 | { | ||
| 469 | int rc; | ||
| 470 | struct sk_security_struct *sksec = sk->sk_security; | ||
| 471 | struct netlbl_lsm_secattr secattr; | ||
| 472 | |||
| 473 | if (sksec->nlbl_state != NLBL_REQSKB && | ||
| 474 | sksec->nlbl_state != NLBL_CONNLABELED) | ||
| 475 | return 0; | ||
| 476 | |||
| 477 | netlbl_secattr_init(&secattr); | ||
| 478 | local_bh_disable(); | ||
| 479 | bh_lock_sock_nested(sk); | ||
| 480 | |||
| 481 | /* connected sockets are allowed to disconnect when the address family | ||
| 482 | * is set to AF_UNSPEC, if that is what is happening we want to reset | ||
| 483 | * the socket */ | ||
| 484 | if (addr->sa_family == AF_UNSPEC) { | ||
| 485 | netlbl_sock_delattr(sk); | ||
| 486 | sksec->nlbl_state = NLBL_REQSKB; | ||
| 487 | rc = 0; | ||
| 488 | goto socket_connect_return; | ||
| 489 | } | ||
| 490 | rc = security_netlbl_sid_to_secattr(sksec->sid, &secattr); | ||
| 491 | if (rc != 0) | ||
| 492 | goto socket_connect_return; | ||
| 493 | rc = netlbl_conn_setattr(sk, addr, &secattr); | ||
| 494 | if (rc != 0) | ||
| 495 | goto socket_connect_return; | ||
| 496 | sksec->nlbl_state = NLBL_CONNLABELED; | ||
| 497 | |||
| 498 | socket_connect_return: | ||
| 499 | bh_unlock_sock(sk); | ||
| 500 | local_bh_enable(); | ||
| 501 | netlbl_secattr_destroy(&secattr); | ||
| 502 | return rc; | ||
| 503 | } | ||
