aboutsummaryrefslogtreecommitdiffstats
path: root/net
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 /net
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>
Diffstat (limited to 'net')
-rw-r--r--net/ipv4/cipso_ipv4.c130
-rw-r--r--net/netlabel/netlabel_kapi.c152
2 files changed, 250 insertions, 32 deletions
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}