aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Moore <paul.moore@hp.com>2009-03-27 17:10:34 -0400
committerJames Morris <jmorris@namei.org>2009-03-28 00:01:36 -0400
commit389fb800ac8be2832efedd19978a2b8ced37eb61 (patch)
treefa0bc16050dfb491aa05f76b54fa4c167de96376
parent284904aa79466a4736f4c775fdbe5c7407fa136c (diff)
netlabel: Label incoming TCP connections correctly in SELinux
The current NetLabel/SELinux behavior for incoming TCP connections works but only through a series of happy coincidences that rely on the limited nature of standard CIPSO (only able to convey MLS attributes) and the write equality imposed by the SELinux MLS constraints. The problem is that network sockets created as the result of an incoming TCP connection were not on-the-wire labeled based on the security attributes of the parent socket but rather based on the wire label of the remote peer. The issue had to do with how IP options were managed as part of the network stack and where the LSM hooks were in relation to the code which set the IP options on these newly created child sockets. While NetLabel/SELinux did correctly set the socket's on-the-wire label it was promptly cleared by the network stack and reset based on the IP options of the remote peer. This patch, in conjunction with a prior patch that adjusted the LSM hook locations, works to set the correct on-the-wire label format for new incoming connections through the security_inet_conn_request() hook. Besides the correct behavior there are many advantages to this change, the most significant is that all of the NetLabel socket labeling code in SELinux now lives in hooks which can return error codes to the core stack which allows us to finally get ride of the selinux_netlbl_inode_permission() logic which greatly simplfies the NetLabel/SELinux glue code. In the process of developing this patch I also ran into a small handful of AF_INET6 cleanliness issues that have been fixed which should make the code safer and easier to extend in the future. Signed-off-by: Paul Moore <paul.moore@hp.com> Acked-by: Casey Schaufler <casey@schaufler-ca.com> Signed-off-by: James Morris <jmorris@namei.org>
-rw-r--r--include/net/cipso_ipv4.h17
-rw-r--r--include/net/netlabel.h12
-rw-r--r--net/ipv4/cipso_ipv4.c130
-rw-r--r--net/netlabel/netlabel_kapi.c152
-rw-r--r--security/selinux/hooks.c54
-rw-r--r--security/selinux/include/netlabel.h27
-rw-r--r--security/selinux/netlabel.c186
-rw-r--r--security/smack/smack_lsm.c2
8 files changed, 360 insertions, 220 deletions
diff --git a/include/net/cipso_ipv4.h b/include/net/cipso_ipv4.h
index bedc7f62e35d..abd443604c9f 100644
--- a/include/net/cipso_ipv4.h
+++ b/include/net/cipso_ipv4.h
@@ -40,6 +40,7 @@
40#include <linux/net.h> 40#include <linux/net.h>
41#include <linux/skbuff.h> 41#include <linux/skbuff.h>
42#include <net/netlabel.h> 42#include <net/netlabel.h>
43#include <net/request_sock.h>
43#include <asm/atomic.h> 44#include <asm/atomic.h>
44 45
45/* known doi values */ 46/* known doi values */
@@ -215,6 +216,10 @@ int cipso_v4_sock_setattr(struct sock *sk,
215 const struct netlbl_lsm_secattr *secattr); 216 const struct netlbl_lsm_secattr *secattr);
216void cipso_v4_sock_delattr(struct sock *sk); 217void cipso_v4_sock_delattr(struct sock *sk);
217int cipso_v4_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr); 218int cipso_v4_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr);
219int cipso_v4_req_setattr(struct request_sock *req,
220 const struct cipso_v4_doi *doi_def,
221 const struct netlbl_lsm_secattr *secattr);
222void cipso_v4_req_delattr(struct request_sock *req);
218int cipso_v4_skbuff_setattr(struct sk_buff *skb, 223int cipso_v4_skbuff_setattr(struct sk_buff *skb,
219 const struct cipso_v4_doi *doi_def, 224 const struct cipso_v4_doi *doi_def,
220 const struct netlbl_lsm_secattr *secattr); 225 const struct netlbl_lsm_secattr *secattr);
@@ -247,6 +252,18 @@ static inline int cipso_v4_sock_getattr(struct sock *sk,
247 return -ENOSYS; 252 return -ENOSYS;
248} 253}
249 254
255static inline int cipso_v4_req_setattr(struct request_sock *req,
256 const struct cipso_v4_doi *doi_def,
257 const struct netlbl_lsm_secattr *secattr)
258{
259 return -ENOSYS;
260}
261
262static inline void cipso_v4_req_delattr(struct request_sock *req)
263{
264 return;
265}
266
250static inline int cipso_v4_skbuff_setattr(struct sk_buff *skb, 267static inline int cipso_v4_skbuff_setattr(struct sk_buff *skb,
251 const struct cipso_v4_doi *doi_def, 268 const struct cipso_v4_doi *doi_def,
252 const struct netlbl_lsm_secattr *secattr) 269 const struct netlbl_lsm_secattr *secattr)
diff --git a/include/net/netlabel.h b/include/net/netlabel.h
index 749011eedc0b..bdb10e5183d5 100644
--- a/include/net/netlabel.h
+++ b/include/net/netlabel.h
@@ -36,6 +36,7 @@
36#include <linux/in.h> 36#include <linux/in.h>
37#include <linux/in6.h> 37#include <linux/in6.h>
38#include <net/netlink.h> 38#include <net/netlink.h>
39#include <net/request_sock.h>
39#include <asm/atomic.h> 40#include <asm/atomic.h>
40 41
41struct cipso_v4_doi; 42struct cipso_v4_doi;
@@ -406,6 +407,7 @@ int netlbl_secattr_catmap_setrng(struct netlbl_lsm_secattr_catmap *catmap,
406 */ 407 */
407int netlbl_enabled(void); 408int netlbl_enabled(void);
408int netlbl_sock_setattr(struct sock *sk, 409int netlbl_sock_setattr(struct sock *sk,
410 u16 family,
409 const struct netlbl_lsm_secattr *secattr); 411 const struct netlbl_lsm_secattr *secattr);
410void netlbl_sock_delattr(struct sock *sk); 412void netlbl_sock_delattr(struct sock *sk);
411int netlbl_sock_getattr(struct sock *sk, 413int netlbl_sock_getattr(struct sock *sk,
@@ -413,6 +415,8 @@ int netlbl_sock_getattr(struct sock *sk,
413int netlbl_conn_setattr(struct sock *sk, 415int netlbl_conn_setattr(struct sock *sk,
414 struct sockaddr *addr, 416 struct sockaddr *addr,
415 const struct netlbl_lsm_secattr *secattr); 417 const struct netlbl_lsm_secattr *secattr);
418int netlbl_req_setattr(struct request_sock *req,
419 const struct netlbl_lsm_secattr *secattr);
416int netlbl_skbuff_setattr(struct sk_buff *skb, 420int netlbl_skbuff_setattr(struct sk_buff *skb,
417 u16 family, 421 u16 family,
418 const struct netlbl_lsm_secattr *secattr); 422 const struct netlbl_lsm_secattr *secattr);
@@ -519,7 +523,8 @@ static inline int netlbl_enabled(void)
519 return 0; 523 return 0;
520} 524}
521static inline int netlbl_sock_setattr(struct sock *sk, 525static inline int netlbl_sock_setattr(struct sock *sk,
522 const struct netlbl_lsm_secattr *secattr) 526 u16 family,
527 const struct netlbl_lsm_secattr *secattr)
523{ 528{
524 return -ENOSYS; 529 return -ENOSYS;
525} 530}
@@ -537,6 +542,11 @@ static inline int netlbl_conn_setattr(struct sock *sk,
537{ 542{
538 return -ENOSYS; 543 return -ENOSYS;
539} 544}
545static inline int netlbl_req_setattr(struct request_sock *req,
546 const struct netlbl_lsm_secattr *secattr)
547{
548 return -ENOSYS;
549}
540static inline int netlbl_skbuff_setattr(struct sk_buff *skb, 550static inline int netlbl_skbuff_setattr(struct sk_buff *skb,
541 u16 family, 551 u16 family,
542 const struct netlbl_lsm_secattr *secattr) 552 const struct netlbl_lsm_secattr *secattr)
diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c
index 7bc992976d29..039cc1ffe977 100644
--- a/net/ipv4/cipso_ipv4.c
+++ b/net/ipv4/cipso_ipv4.c
@@ -1942,23 +1942,85 @@ socket_setattr_failure:
1942} 1942}
1943 1943
1944/** 1944/**
1945 * cipso_v4_sock_delattr - Delete the CIPSO option from a socket 1945 * cipso_v4_req_setattr - Add a CIPSO option to a connection request socket
1946 * @sk: the socket 1946 * @req: the connection request socket
1947 * @doi_def: the CIPSO DOI to use
1948 * @secattr: the specific security attributes of the socket
1947 * 1949 *
1948 * Description: 1950 * Description:
1949 * Removes the CIPSO option from a socket, if present. 1951 * Set the CIPSO option on the given socket using the DOI definition and
1952 * security attributes passed to the function. Returns zero on success and
1953 * negative values on failure.
1950 * 1954 *
1951 */ 1955 */
1952void cipso_v4_sock_delattr(struct sock *sk) 1956int cipso_v4_req_setattr(struct request_sock *req,
1957 const struct cipso_v4_doi *doi_def,
1958 const struct netlbl_lsm_secattr *secattr)
1953{ 1959{
1954 u8 hdr_delta; 1960 int ret_val = -EPERM;
1955 struct ip_options *opt; 1961 unsigned char *buf = NULL;
1956 struct inet_sock *sk_inet; 1962 u32 buf_len;
1963 u32 opt_len;
1964 struct ip_options *opt = NULL;
1965 struct inet_request_sock *req_inet;
1957 1966
1958 sk_inet = inet_sk(sk); 1967 /* We allocate the maximum CIPSO option size here so we are probably
1959 opt = sk_inet->opt; 1968 * being a little wasteful, but it makes our life _much_ easier later
1960 if (opt == NULL || opt->cipso == 0) 1969 * on and after all we are only talking about 40 bytes. */
1961 return; 1970 buf_len = CIPSO_V4_OPT_LEN_MAX;
1971 buf = kmalloc(buf_len, GFP_ATOMIC);
1972 if (buf == NULL) {
1973 ret_val = -ENOMEM;
1974 goto req_setattr_failure;
1975 }
1976
1977 ret_val = cipso_v4_genopt(buf, buf_len, doi_def, secattr);
1978 if (ret_val < 0)
1979 goto req_setattr_failure;
1980 buf_len = ret_val;
1981
1982 /* We can't use ip_options_get() directly because it makes a call to
1983 * ip_options_get_alloc() which allocates memory with GFP_KERNEL and
1984 * we won't always have CAP_NET_RAW even though we _always_ want to
1985 * set the IPOPT_CIPSO option. */
1986 opt_len = (buf_len + 3) & ~3;
1987 opt = kzalloc(sizeof(*opt) + opt_len, GFP_ATOMIC);
1988 if (opt == NULL) {
1989 ret_val = -ENOMEM;
1990 goto req_setattr_failure;
1991 }
1992 memcpy(opt->__data, buf, buf_len);
1993 opt->optlen = opt_len;
1994 opt->cipso = sizeof(struct iphdr);
1995 kfree(buf);
1996 buf = NULL;
1997
1998 req_inet = inet_rsk(req);
1999 opt = xchg(&req_inet->opt, opt);
2000 kfree(opt);
2001
2002 return 0;
2003
2004req_setattr_failure:
2005 kfree(buf);
2006 kfree(opt);
2007 return ret_val;
2008}
2009
2010/**
2011 * cipso_v4_delopt - Delete the CIPSO option from a set of IP options
2012 * @opt_ptr: IP option pointer
2013 *
2014 * Description:
2015 * Deletes the CIPSO IP option from a set of IP options and makes the necessary
2016 * adjustments to the IP option structure. Returns zero on success, negative
2017 * values on failure.
2018 *
2019 */
2020int cipso_v4_delopt(struct ip_options **opt_ptr)
2021{
2022 int hdr_delta = 0;
2023 struct ip_options *opt = *opt_ptr;
1962 2024
1963 if (opt->srr || opt->rr || opt->ts || opt->router_alert) { 2025 if (opt->srr || opt->rr || opt->ts || opt->router_alert) {
1964 u8 cipso_len; 2026 u8 cipso_len;
@@ -2003,11 +2065,34 @@ void cipso_v4_sock_delattr(struct sock *sk)
2003 } else { 2065 } else {
2004 /* only the cipso option was present on the socket so we can 2066 /* only the cipso option was present on the socket so we can
2005 * remove the entire option struct */ 2067 * remove the entire option struct */
2006 sk_inet->opt = NULL; 2068 *opt_ptr = NULL;
2007 hdr_delta = opt->optlen; 2069 hdr_delta = opt->optlen;
2008 kfree(opt); 2070 kfree(opt);
2009 } 2071 }
2010 2072
2073 return hdr_delta;
2074}
2075
2076/**
2077 * cipso_v4_sock_delattr - Delete the CIPSO option from a socket
2078 * @sk: the socket
2079 *
2080 * Description:
2081 * Removes the CIPSO option from a socket, if present.
2082 *
2083 */
2084void cipso_v4_sock_delattr(struct sock *sk)
2085{
2086 int hdr_delta;
2087 struct ip_options *opt;
2088 struct inet_sock *sk_inet;
2089
2090 sk_inet = inet_sk(sk);
2091 opt = sk_inet->opt;
2092 if (opt == NULL || opt->cipso == 0)
2093 return;
2094
2095 hdr_delta = cipso_v4_delopt(&sk_inet->opt);
2011 if (sk_inet->is_icsk && hdr_delta > 0) { 2096 if (sk_inet->is_icsk && hdr_delta > 0) {
2012 struct inet_connection_sock *sk_conn = inet_csk(sk); 2097 struct inet_connection_sock *sk_conn = inet_csk(sk);
2013 sk_conn->icsk_ext_hdr_len -= hdr_delta; 2098 sk_conn->icsk_ext_hdr_len -= hdr_delta;
@@ -2016,6 +2101,27 @@ void cipso_v4_sock_delattr(struct sock *sk)
2016} 2101}
2017 2102
2018/** 2103/**
2104 * cipso_v4_req_delattr - Delete the CIPSO option from a request socket
2105 * @reg: the request socket
2106 *
2107 * Description:
2108 * Removes the CIPSO option from a request socket, if present.
2109 *
2110 */
2111void cipso_v4_req_delattr(struct request_sock *req)
2112{
2113 struct ip_options *opt;
2114 struct inet_request_sock *req_inet;
2115
2116 req_inet = inet_rsk(req);
2117 opt = req_inet->opt;
2118 if (opt == NULL || opt->cipso == 0)
2119 return;
2120
2121 cipso_v4_delopt(&req_inet->opt);
2122}
2123
2124/**
2019 * cipso_v4_getattr - Helper function for the cipso_v4_*_getattr functions 2125 * cipso_v4_getattr - Helper function for the cipso_v4_*_getattr functions
2020 * @cipso: the CIPSO v4 option 2126 * @cipso: the CIPSO v4 option
2021 * @secattr: the security attributes 2127 * @secattr: the security attributes
diff --git a/net/netlabel/netlabel_kapi.c b/net/netlabel/netlabel_kapi.c
index fd9229db075c..cae2f5f4cac0 100644
--- a/net/netlabel/netlabel_kapi.c
+++ b/net/netlabel/netlabel_kapi.c
@@ -619,8 +619,9 @@ int netlbl_enabled(void)
619} 619}
620 620
621/** 621/**
622 * netlbl_socket_setattr - Label a socket using the correct protocol 622 * netlbl_sock_setattr - Label a socket using the correct protocol
623 * @sk: the socket to label 623 * @sk: the socket to label
624 * @family: protocol family
624 * @secattr: the security attributes 625 * @secattr: the security attributes
625 * 626 *
626 * Description: 627 * Description:
@@ -633,29 +634,45 @@ int netlbl_enabled(void)
633 * 634 *
634 */ 635 */
635int netlbl_sock_setattr(struct sock *sk, 636int netlbl_sock_setattr(struct sock *sk,
637 u16 family,
636 const struct netlbl_lsm_secattr *secattr) 638 const struct netlbl_lsm_secattr *secattr)
637{ 639{
638 int ret_val = -ENOENT; 640 int ret_val;
639 struct netlbl_dom_map *dom_entry; 641 struct netlbl_dom_map *dom_entry;
640 642
641 rcu_read_lock(); 643 rcu_read_lock();
642 dom_entry = netlbl_domhsh_getentry(secattr->domain); 644 dom_entry = netlbl_domhsh_getentry(secattr->domain);
643 if (dom_entry == NULL) 645 if (dom_entry == NULL) {
646 ret_val = -ENOENT;
644 goto socket_setattr_return; 647 goto socket_setattr_return;
645 switch (dom_entry->type) { 648 }
646 case NETLBL_NLTYPE_ADDRSELECT: 649 switch (family) {
647 ret_val = -EDESTADDRREQ; 650 case AF_INET:
648 break; 651 switch (dom_entry->type) {
649 case NETLBL_NLTYPE_CIPSOV4: 652 case NETLBL_NLTYPE_ADDRSELECT:
650 ret_val = cipso_v4_sock_setattr(sk, 653 ret_val = -EDESTADDRREQ;
651 dom_entry->type_def.cipsov4, 654 break;
652 secattr); 655 case NETLBL_NLTYPE_CIPSOV4:
656 ret_val = cipso_v4_sock_setattr(sk,
657 dom_entry->type_def.cipsov4,
658 secattr);
659 break;
660 case NETLBL_NLTYPE_UNLABELED:
661 ret_val = 0;
662 break;
663 default:
664 ret_val = -ENOENT;
665 }
653 break; 666 break;
654 case NETLBL_NLTYPE_UNLABELED: 667#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
668 case AF_INET6:
669 /* since we don't support any IPv6 labeling protocols right
670 * now we can optimize everything away until we do */
655 ret_val = 0; 671 ret_val = 0;
656 break; 672 break;
673#endif /* IPv6 */
657 default: 674 default:
658 ret_val = -ENOENT; 675 ret_val = -EPROTONOSUPPORT;
659 } 676 }
660 677
661socket_setattr_return: 678socket_setattr_return:
@@ -689,9 +706,25 @@ void netlbl_sock_delattr(struct sock *sk)
689 * on failure. 706 * on failure.
690 * 707 *
691 */ 708 */
692int netlbl_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr) 709int netlbl_sock_getattr(struct sock *sk,
710 struct netlbl_lsm_secattr *secattr)
693{ 711{
694 return cipso_v4_sock_getattr(sk, secattr); 712 int ret_val;
713
714 switch (sk->sk_family) {
715 case AF_INET:
716 ret_val = cipso_v4_sock_getattr(sk, secattr);
717 break;
718#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
719 case AF_INET6:
720 ret_val = -ENOMSG;
721 break;
722#endif /* IPv6 */
723 default:
724 ret_val = -EPROTONOSUPPORT;
725 }
726
727 return ret_val;
695} 728}
696 729
697/** 730/**
@@ -748,7 +781,7 @@ int netlbl_conn_setattr(struct sock *sk,
748 break; 781 break;
749#endif /* IPv6 */ 782#endif /* IPv6 */
750 default: 783 default:
751 ret_val = 0; 784 ret_val = -EPROTONOSUPPORT;
752 } 785 }
753 786
754conn_setattr_return: 787conn_setattr_return:
@@ -757,6 +790,77 @@ conn_setattr_return:
757} 790}
758 791
759/** 792/**
793 * netlbl_req_setattr - Label a request socket using the correct protocol
794 * @req: the request socket to label
795 * @secattr: the security attributes
796 *
797 * Description:
798 * Attach the correct label to the given socket using the security attributes
799 * specified in @secattr. Returns zero on success, negative values on failure.
800 *
801 */
802int netlbl_req_setattr(struct request_sock *req,
803 const struct netlbl_lsm_secattr *secattr)
804{
805 int ret_val;
806 struct netlbl_dom_map *dom_entry;
807 struct netlbl_domaddr4_map *af4_entry;
808 u32 proto_type;
809 struct cipso_v4_doi *proto_cv4;
810
811 rcu_read_lock();
812 dom_entry = netlbl_domhsh_getentry(secattr->domain);
813 if (dom_entry == NULL) {
814 ret_val = -ENOENT;
815 goto req_setattr_return;
816 }
817 switch (req->rsk_ops->family) {
818 case AF_INET:
819 if (dom_entry->type == NETLBL_NLTYPE_ADDRSELECT) {
820 struct inet_request_sock *req_inet = inet_rsk(req);
821 af4_entry = netlbl_domhsh_getentry_af4(secattr->domain,
822 req_inet->rmt_addr);
823 if (af4_entry == NULL) {
824 ret_val = -ENOENT;
825 goto req_setattr_return;
826 }
827 proto_type = af4_entry->type;
828 proto_cv4 = af4_entry->type_def.cipsov4;
829 } else {
830 proto_type = dom_entry->type;
831 proto_cv4 = dom_entry->type_def.cipsov4;
832 }
833 switch (proto_type) {
834 case NETLBL_NLTYPE_CIPSOV4:
835 ret_val = cipso_v4_req_setattr(req, proto_cv4, secattr);
836 break;
837 case NETLBL_NLTYPE_UNLABELED:
838 /* just delete the protocols we support for right now
839 * but we could remove other protocols if needed */
840 cipso_v4_req_delattr(req);
841 ret_val = 0;
842 break;
843 default:
844 ret_val = -ENOENT;
845 }
846 break;
847#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
848 case AF_INET6:
849 /* since we don't support any IPv6 labeling protocols right
850 * now we can optimize everything away until we do */
851 ret_val = 0;
852 break;
853#endif /* IPv6 */
854 default:
855 ret_val = -EPROTONOSUPPORT;
856 }
857
858req_setattr_return:
859 rcu_read_unlock();
860 return ret_val;
861}
862
863/**
760 * netlbl_skbuff_setattr - Label a packet using the correct protocol 864 * netlbl_skbuff_setattr - Label a packet using the correct protocol
761 * @skb: the packet 865 * @skb: the packet
762 * @family: protocol family 866 * @family: protocol family
@@ -808,7 +912,7 @@ int netlbl_skbuff_setattr(struct sk_buff *skb,
808 break; 912 break;
809#endif /* IPv6 */ 913#endif /* IPv6 */
810 default: 914 default:
811 ret_val = 0; 915 ret_val = -EPROTONOSUPPORT;
812 } 916 }
813 917
814skbuff_setattr_return: 918skbuff_setattr_return:
@@ -833,9 +937,17 @@ int netlbl_skbuff_getattr(const struct sk_buff *skb,
833 u16 family, 937 u16 family,
834 struct netlbl_lsm_secattr *secattr) 938 struct netlbl_lsm_secattr *secattr)
835{ 939{
836 if (CIPSO_V4_OPTEXIST(skb) && 940 switch (family) {
837 cipso_v4_skbuff_getattr(skb, secattr) == 0) 941 case AF_INET:
838 return 0; 942 if (CIPSO_V4_OPTEXIST(skb) &&
943 cipso_v4_skbuff_getattr(skb, secattr) == 0)
944 return 0;
945 break;
946#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
947 case AF_INET6:
948 break;
949#endif /* IPv6 */
950 }
839 951
840 return netlbl_unlabel_getattr(skb, family, secattr); 952 return netlbl_unlabel_getattr(skb, family, secattr);
841} 953}
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 7c52ba243c64..ee2e781d11d7 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -311,7 +311,7 @@ static int sk_alloc_security(struct sock *sk, int family, gfp_t priority)
311 ssec->sid = SECINITSID_UNLABELED; 311 ssec->sid = SECINITSID_UNLABELED;
312 sk->sk_security = ssec; 312 sk->sk_security = ssec;
313 313
314 selinux_netlbl_sk_security_reset(ssec, family); 314 selinux_netlbl_sk_security_reset(ssec);
315 315
316 return 0; 316 return 0;
317} 317}
@@ -2945,7 +2945,6 @@ static void selinux_inode_getsecid(const struct inode *inode, u32 *secid)
2945static int selinux_revalidate_file_permission(struct file *file, int mask) 2945static int selinux_revalidate_file_permission(struct file *file, int mask)
2946{ 2946{
2947 const struct cred *cred = current_cred(); 2947 const struct cred *cred = current_cred();
2948 int rc;
2949 struct inode *inode = file->f_path.dentry->d_inode; 2948 struct inode *inode = file->f_path.dentry->d_inode;
2950 2949
2951 if (!mask) { 2950 if (!mask) {
@@ -2957,29 +2956,15 @@ static int selinux_revalidate_file_permission(struct file *file, int mask)
2957 if ((file->f_flags & O_APPEND) && (mask & MAY_WRITE)) 2956 if ((file->f_flags & O_APPEND) && (mask & MAY_WRITE))
2958 mask |= MAY_APPEND; 2957 mask |= MAY_APPEND;
2959 2958
2960 rc = file_has_perm(cred, file, 2959 return file_has_perm(cred, file,
2961 file_mask_to_av(inode->i_mode, mask)); 2960 file_mask_to_av(inode->i_mode, mask));
2962 if (rc)
2963 return rc;
2964
2965 return selinux_netlbl_inode_permission(inode, mask);
2966} 2961}
2967 2962
2968static int selinux_file_permission(struct file *file, int mask) 2963static int selinux_file_permission(struct file *file, int mask)
2969{ 2964{
2970 struct inode *inode = file->f_path.dentry->d_inode; 2965 if (!mask)
2971 struct file_security_struct *fsec = file->f_security;
2972 struct inode_security_struct *isec = inode->i_security;
2973 u32 sid = current_sid();
2974
2975 if (!mask) {
2976 /* No permission to check. Existence test. */ 2966 /* No permission to check. Existence test. */
2977 return 0; 2967 return 0;
2978 }
2979
2980 if (sid == fsec->sid && fsec->isid == isec->sid
2981 && fsec->pseqno == avc_policy_seqno())
2982 return selinux_netlbl_inode_permission(inode, mask);
2983 2968
2984 return selinux_revalidate_file_permission(file, mask); 2969 return selinux_revalidate_file_permission(file, mask);
2985} 2970}
@@ -3723,7 +3708,7 @@ static int selinux_socket_post_create(struct socket *sock, int family,
3723 sksec = sock->sk->sk_security; 3708 sksec = sock->sk->sk_security;
3724 sksec->sid = isec->sid; 3709 sksec->sid = isec->sid;
3725 sksec->sclass = isec->sclass; 3710 sksec->sclass = isec->sclass;
3726 err = selinux_netlbl_socket_post_create(sock); 3711 err = selinux_netlbl_socket_post_create(sock->sk, family);
3727 } 3712 }
3728 3713
3729 return err; 3714 return err;
@@ -3914,13 +3899,7 @@ static int selinux_socket_accept(struct socket *sock, struct socket *newsock)
3914static int selinux_socket_sendmsg(struct socket *sock, struct msghdr *msg, 3899static int selinux_socket_sendmsg(struct socket *sock, struct msghdr *msg,
3915 int size) 3900 int size)
3916{ 3901{
3917 int rc; 3902 return socket_has_perm(current, sock, SOCKET__WRITE);
3918
3919 rc = socket_has_perm(current, sock, SOCKET__WRITE);
3920 if (rc)
3921 return rc;
3922
3923 return selinux_netlbl_inode_permission(SOCK_INODE(sock), MAY_WRITE);
3924} 3903}
3925 3904
3926static int selinux_socket_recvmsg(struct socket *sock, struct msghdr *msg, 3905static int selinux_socket_recvmsg(struct socket *sock, struct msghdr *msg,
@@ -4304,7 +4283,7 @@ static void selinux_sk_clone_security(const struct sock *sk, struct sock *newsk)
4304 newssec->peer_sid = ssec->peer_sid; 4283 newssec->peer_sid = ssec->peer_sid;
4305 newssec->sclass = ssec->sclass; 4284 newssec->sclass = ssec->sclass;
4306 4285
4307 selinux_netlbl_sk_security_reset(newssec, newsk->sk_family); 4286 selinux_netlbl_sk_security_reset(newssec);
4308} 4287}
4309 4288
4310static void selinux_sk_getsecid(struct sock *sk, u32 *secid) 4289static void selinux_sk_getsecid(struct sock *sk, u32 *secid)
@@ -4348,16 +4327,15 @@ static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb,
4348 if (peersid == SECSID_NULL) { 4327 if (peersid == SECSID_NULL) {
4349 req->secid = sksec->sid; 4328 req->secid = sksec->sid;
4350 req->peer_secid = SECSID_NULL; 4329 req->peer_secid = SECSID_NULL;
4351 return 0; 4330 } else {
4331 err = security_sid_mls_copy(sksec->sid, peersid, &newsid);
4332 if (err)
4333 return err;
4334 req->secid = newsid;
4335 req->peer_secid = peersid;
4352 } 4336 }
4353 4337
4354 err = security_sid_mls_copy(sksec->sid, peersid, &newsid); 4338 return selinux_netlbl_inet_conn_request(req, family);
4355 if (err)
4356 return err;
4357
4358 req->secid = newsid;
4359 req->peer_secid = peersid;
4360 return 0;
4361} 4339}
4362 4340
4363static void selinux_inet_csk_clone(struct sock *newsk, 4341static void selinux_inet_csk_clone(struct sock *newsk,
@@ -4374,7 +4352,7 @@ static void selinux_inet_csk_clone(struct sock *newsk,
4374 4352
4375 /* We don't need to take any sort of lock here as we are the only 4353 /* We don't need to take any sort of lock here as we are the only
4376 * thread with access to newsksec */ 4354 * thread with access to newsksec */
4377 selinux_netlbl_sk_security_reset(newsksec, req->rsk_ops->family); 4355 selinux_netlbl_inet_csk_clone(newsk, req->rsk_ops->family);
4378} 4356}
4379 4357
4380static void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb) 4358static void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb)
@@ -4387,8 +4365,6 @@ static void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb)
4387 family = PF_INET; 4365 family = PF_INET;
4388 4366
4389 selinux_skb_peerlbl_sid(skb, family, &sksec->peer_sid); 4367 selinux_skb_peerlbl_sid(skb, family, &sksec->peer_sid);
4390
4391 selinux_netlbl_inet_conn_established(sk, family);
4392} 4368}
4393 4369
4394static void selinux_req_classify_flow(const struct request_sock *req, 4370static 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 b913c8d06038..b4b5b9b2f0be 100644
--- a/security/selinux/include/netlabel.h
+++ b/security/selinux/include/netlabel.h
@@ -32,6 +32,7 @@
32#include <linux/net.h> 32#include <linux/net.h>
33#include <linux/skbuff.h> 33#include <linux/skbuff.h>
34#include <net/sock.h> 34#include <net/sock.h>
35#include <net/request_sock.h>
35 36
36#include "avc.h" 37#include "avc.h"
37#include "objsec.h" 38#include "objsec.h"
@@ -42,8 +43,7 @@ void selinux_netlbl_cache_invalidate(void);
42void selinux_netlbl_err(struct sk_buff *skb, int error, int gateway); 43void selinux_netlbl_err(struct sk_buff *skb, int error, int gateway);
43 44
44void selinux_netlbl_sk_security_free(struct sk_security_struct *ssec); 45void selinux_netlbl_sk_security_free(struct sk_security_struct *ssec);
45void selinux_netlbl_sk_security_reset(struct sk_security_struct *ssec, 46void selinux_netlbl_sk_security_reset(struct sk_security_struct *ssec);
46 int family);
47 47
48int selinux_netlbl_skbuff_getsid(struct sk_buff *skb, 48int selinux_netlbl_skbuff_getsid(struct sk_buff *skb,
49 u16 family, 49 u16 family,
@@ -53,9 +53,9 @@ int selinux_netlbl_skbuff_setsid(struct sk_buff *skb,
53 u16 family, 53 u16 family,
54 u32 sid); 54 u32 sid);
55 55
56void selinux_netlbl_inet_conn_established(struct sock *sk, u16 family); 56int selinux_netlbl_inet_conn_request(struct request_sock *req, u16 family);
57int selinux_netlbl_socket_post_create(struct socket *sock); 57void selinux_netlbl_inet_csk_clone(struct sock *sk, u16 family);
58int selinux_netlbl_inode_permission(struct inode *inode, int mask); 58int selinux_netlbl_socket_post_create(struct sock *sk, u16 family);
59int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec, 59int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,
60 struct sk_buff *skb, 60 struct sk_buff *skb,
61 u16 family, 61 u16 family,
@@ -85,8 +85,7 @@ static inline void selinux_netlbl_sk_security_free(
85} 85}
86 86
87static inline void selinux_netlbl_sk_security_reset( 87static inline void selinux_netlbl_sk_security_reset(
88 struct sk_security_struct *ssec, 88 struct sk_security_struct *ssec)
89 int family)
90{ 89{
91 return; 90 return;
92} 91}
@@ -113,17 +112,17 @@ static inline int selinux_netlbl_conn_setsid(struct sock *sk,
113 return 0; 112 return 0;
114} 113}
115 114
116static inline void selinux_netlbl_inet_conn_established(struct sock *sk, 115static inline int selinux_netlbl_inet_conn_request(struct request_sock *req,
117 u16 family) 116 u16 family)
118{ 117{
119 return; 118 return 0;
120} 119}
121static inline int selinux_netlbl_socket_post_create(struct socket *sock) 120static inline void selinux_netlbl_inet_csk_clone(struct sock *sk, u16 family)
122{ 121{
123 return 0; 122 return;
124} 123}
125static inline int selinux_netlbl_inode_permission(struct inode *inode, 124static inline int selinux_netlbl_socket_post_create(struct sock *sk,
126 int mask) 125 u16 family)
127{ 126{
128 return 0; 127 return 0;
129} 128}
diff --git a/security/selinux/netlabel.c b/security/selinux/netlabel.c
index 350794ab9b42..2e984413c7b2 100644
--- a/security/selinux/netlabel.c
+++ b/security/selinux/netlabel.c
@@ -100,41 +100,6 @@ static struct netlbl_lsm_secattr *selinux_netlbl_sock_genattr(struct sock *sk)
100} 100}
101 101
102/** 102/**
103 * selinux_netlbl_sock_setsid - Label a socket using the NetLabel mechanism
104 * @sk: the socket to label
105 *
106 * Description:
107 * Attempt to label a socket using the NetLabel mechanism. Returns zero values
108 * on success, negative values on failure.
109 *
110 */
111static int selinux_netlbl_sock_setsid(struct sock *sk)
112{
113 int rc;
114 struct sk_security_struct *sksec = sk->sk_security;
115 struct netlbl_lsm_secattr *secattr;
116
117 if (sksec->nlbl_state != NLBL_REQUIRE)
118 return 0;
119
120 secattr = selinux_netlbl_sock_genattr(sk);
121 if (secattr == NULL)
122 return -ENOMEM;
123 rc = netlbl_sock_setattr(sk, secattr);
124 switch (rc) {
125 case 0:
126 sksec->nlbl_state = NLBL_LABELED;
127 break;
128 case -EDESTADDRREQ:
129 sksec->nlbl_state = NLBL_REQSKB;
130 rc = 0;
131 break;
132 }
133
134 return rc;
135}
136
137/**
138 * selinux_netlbl_cache_invalidate - Invalidate the NetLabel cache 103 * selinux_netlbl_cache_invalidate - Invalidate the NetLabel cache
139 * 104 *
140 * Description: 105 * Description:
@@ -188,13 +153,9 @@ void selinux_netlbl_sk_security_free(struct sk_security_struct *ssec)
188 * The caller is responsibile for all the NetLabel sk_security_struct locking. 153 * The caller is responsibile for all the NetLabel sk_security_struct locking.
189 * 154 *
190 */ 155 */
191void selinux_netlbl_sk_security_reset(struct sk_security_struct *ssec, 156void selinux_netlbl_sk_security_reset(struct sk_security_struct *ssec)
192 int family)
193{ 157{
194 if (family == PF_INET) 158 ssec->nlbl_state = NLBL_UNSET;
195 ssec->nlbl_state = NLBL_REQUIRE;
196 else
197 ssec->nlbl_state = NLBL_UNSET;
198} 159}
199 160
200/** 161/**
@@ -281,127 +242,86 @@ skbuff_setsid_return:
281} 242}
282 243
283/** 244/**
284 * selinux_netlbl_inet_conn_established - Netlabel the newly accepted connection 245 * selinux_netlbl_inet_conn_request - Label an incoming stream connection
285 * @sk: the new connection 246 * @req: incoming connection request socket
286 * 247 *
287 * Description: 248 * Description:
288 * A new connection has been established on @sk so make sure it is labeled 249 * A new incoming connection request is represented by @req, we need to label
289 * correctly with the NetLabel susbsystem. 250 * the new request_sock here and the stack will ensure the on-the-wire label
251 * will get preserved when a full sock is created once the connection handshake
252 * is complete. Returns zero on success, negative values on failure.
290 * 253 *
291 */ 254 */
292void selinux_netlbl_inet_conn_established(struct sock *sk, u16 family) 255int selinux_netlbl_inet_conn_request(struct request_sock *req, u16 family)
293{ 256{
294 int rc; 257 int rc;
295 struct sk_security_struct *sksec = sk->sk_security; 258 struct netlbl_lsm_secattr secattr;
296 struct netlbl_lsm_secattr *secattr;
297 struct inet_sock *sk_inet = inet_sk(sk);
298 struct sockaddr_in addr;
299
300 if (sksec->nlbl_state != NLBL_REQUIRE)
301 return;
302 259
303 secattr = selinux_netlbl_sock_genattr(sk); 260 if (family != PF_INET)
304 if (secattr == NULL) 261 return 0;
305 return;
306 262
307 rc = netlbl_sock_setattr(sk, secattr); 263 netlbl_secattr_init(&secattr);
308 switch (rc) { 264 rc = security_netlbl_sid_to_secattr(req->secid, &secattr);
309 case 0: 265 if (rc != 0)
310 sksec->nlbl_state = NLBL_LABELED; 266 goto inet_conn_request_return;
311 break; 267 rc = netlbl_req_setattr(req, &secattr);
312 case -EDESTADDRREQ: 268inet_conn_request_return:
313 /* no PF_INET6 support yet because we don't support any IPv6 269 netlbl_secattr_destroy(&secattr);
314 * labeling protocols */ 270 return rc;
315 if (family != PF_INET) {
316 sksec->nlbl_state = NLBL_UNSET;
317 return;
318 }
319
320 addr.sin_family = family;
321 addr.sin_addr.s_addr = sk_inet->daddr;
322 if (netlbl_conn_setattr(sk, (struct sockaddr *)&addr,
323 secattr) != 0) {
324 /* we failed to label the connected socket (could be
325 * for a variety of reasons, the actual "why" isn't
326 * important here) so we have to go to our backup plan,
327 * labeling the packets individually in the netfilter
328 * local output hook. this is okay but we need to
329 * adjust the MSS of the connection to take into
330 * account any labeling overhead, since we don't know
331 * the exact overhead at this point we'll use the worst
332 * case value which is 40 bytes for IPv4 */
333 struct inet_connection_sock *sk_conn = inet_csk(sk);
334 sk_conn->icsk_ext_hdr_len += 40 -
335 (sk_inet->opt ? sk_inet->opt->optlen : 0);
336 sk_conn->icsk_sync_mss(sk, sk_conn->icsk_pmtu_cookie);
337
338 sksec->nlbl_state = NLBL_REQSKB;
339 } else
340 sksec->nlbl_state = NLBL_CONNLABELED;
341 break;
342 default:
343 /* note that we are failing to label the socket which could be
344 * a bad thing since it means traffic could leave the system
345 * without the desired labeling, however, all is not lost as
346 * we have a check in selinux_netlbl_inode_permission() to
347 * pick up the pieces that we might drop here because we can't
348 * return an error code */
349 break;
350 }
351} 271}
352 272
353/** 273/**
354 * selinux_netlbl_socket_post_create - Label a socket using NetLabel 274 * selinux_netlbl_inet_csk_clone - Initialize the newly created sock
355 * @sock: the socket to label 275 * @sk: the new sock
356 * 276 *
357 * Description: 277 * Description:
358 * Attempt to label a socket using the NetLabel mechanism using the given 278 * A new connection has been established using @sk, we've already labeled the
359 * SID. Returns zero values on success, negative values on failure. 279 * socket via the request_sock struct in selinux_netlbl_inet_conn_request() but
280 * we need to set the NetLabel state here since we now have a sock structure.
360 * 281 *
361 */ 282 */
362int selinux_netlbl_socket_post_create(struct socket *sock) 283void selinux_netlbl_inet_csk_clone(struct sock *sk, u16 family)
363{ 284{
364 return selinux_netlbl_sock_setsid(sock->sk); 285 struct sk_security_struct *sksec = sk->sk_security;
286
287 if (family == PF_INET)
288 sksec->nlbl_state = NLBL_LABELED;
289 else
290 sksec->nlbl_state = NLBL_UNSET;
365} 291}
366 292
367/** 293/**
368 * selinux_netlbl_inode_permission - Verify the socket is NetLabel labeled 294 * selinux_netlbl_socket_post_create - Label a socket using NetLabel
369 * @inode: the file descriptor's inode 295 * @sock: the socket to label
370 * @mask: the permission mask 296 * @family: protocol family
371 * 297 *
372 * Description: 298 * Description:
373 * Looks at a file's inode and if it is marked as a socket protected by 299 * Attempt to label a socket using the NetLabel mechanism using the given
374 * NetLabel then verify that the socket has been labeled, if not try to label 300 * SID. Returns zero values on success, negative values on failure.
375 * the socket now with the inode's SID. Returns zero on success, negative
376 * values on failure.
377 * 301 *
378 */ 302 */
379int selinux_netlbl_inode_permission(struct inode *inode, int mask) 303int selinux_netlbl_socket_post_create(struct sock *sk, u16 family)
380{ 304{
381 int rc; 305 int rc;
382 struct sock *sk; 306 struct sk_security_struct *sksec = sk->sk_security;
383 struct socket *sock; 307 struct netlbl_lsm_secattr *secattr;
384 struct sk_security_struct *sksec;
385 308
386 if (!S_ISSOCK(inode->i_mode) || 309 if (family != PF_INET)
387 ((mask & (MAY_WRITE | MAY_APPEND)) == 0))
388 return 0;
389 sock = SOCKET_I(inode);
390 sk = sock->sk;
391 if (sk == NULL)
392 return 0;
393 sksec = sk->sk_security;
394 if (sksec == NULL || sksec->nlbl_state != NLBL_REQUIRE)
395 return 0; 310 return 0;
396 311
397 local_bh_disable(); 312 secattr = selinux_netlbl_sock_genattr(sk);
398 bh_lock_sock_nested(sk); 313 if (secattr == NULL)
399 if (likely(sksec->nlbl_state == NLBL_REQUIRE)) 314 return -ENOMEM;
400 rc = selinux_netlbl_sock_setsid(sk); 315 rc = netlbl_sock_setattr(sk, family, secattr);
401 else 316 switch (rc) {
317 case 0:
318 sksec->nlbl_state = NLBL_LABELED;
319 break;
320 case -EDESTADDRREQ:
321 sksec->nlbl_state = NLBL_REQSKB;
402 rc = 0; 322 rc = 0;
403 bh_unlock_sock(sk); 323 break;
404 local_bh_enable(); 324 }
405 325
406 return rc; 326 return rc;
407} 327}
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index fd20d15f5b9a..23ad420a49aa 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -1387,7 +1387,7 @@ static int smack_netlabel(struct sock *sk, int labeled)
1387 else { 1387 else {
1388 netlbl_secattr_init(&secattr); 1388 netlbl_secattr_init(&secattr);
1389 smack_to_secattr(ssp->smk_out, &secattr); 1389 smack_to_secattr(ssp->smk_out, &secattr);
1390 rc = netlbl_sock_setattr(sk, &secattr); 1390 rc = netlbl_sock_setattr(sk, sk->sk_family, &secattr);
1391 netlbl_secattr_destroy(&secattr); 1391 netlbl_secattr_destroy(&secattr);
1392 } 1392 }
1393 1393