Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Paul Moore and committed by
James Morris
389fb800 284904aa

+364 -224
+17
include/net/cipso_ipv4.h
··· 40 40 #include <linux/net.h> 41 41 #include <linux/skbuff.h> 42 42 #include <net/netlabel.h> 43 + #include <net/request_sock.h> 43 44 #include <asm/atomic.h> 44 45 45 46 /* known doi values */ ··· 216 215 const struct netlbl_lsm_secattr *secattr); 217 216 void cipso_v4_sock_delattr(struct sock *sk); 218 217 int cipso_v4_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr); 218 + int cipso_v4_req_setattr(struct request_sock *req, 219 + const struct cipso_v4_doi *doi_def, 220 + const struct netlbl_lsm_secattr *secattr); 221 + void cipso_v4_req_delattr(struct request_sock *req); 219 222 int cipso_v4_skbuff_setattr(struct sk_buff *skb, 220 223 const struct cipso_v4_doi *doi_def, 221 224 const struct netlbl_lsm_secattr *secattr); ··· 250 245 struct netlbl_lsm_secattr *secattr) 251 246 { 252 247 return -ENOSYS; 248 + } 249 + 250 + static inline int cipso_v4_req_setattr(struct request_sock *req, 251 + const struct cipso_v4_doi *doi_def, 252 + const struct netlbl_lsm_secattr *secattr) 253 + { 254 + return -ENOSYS; 255 + } 256 + 257 + static inline void cipso_v4_req_delattr(struct request_sock *req) 258 + { 259 + return; 253 260 } 254 261 255 262 static inline int cipso_v4_skbuff_setattr(struct sk_buff *skb,
+11 -1
include/net/netlabel.h
··· 36 36 #include <linux/in.h> 37 37 #include <linux/in6.h> 38 38 #include <net/netlink.h> 39 + #include <net/request_sock.h> 39 40 #include <asm/atomic.h> 40 41 41 42 struct cipso_v4_doi; ··· 407 406 */ 408 407 int netlbl_enabled(void); 409 408 int netlbl_sock_setattr(struct sock *sk, 409 + u16 family, 410 410 const struct netlbl_lsm_secattr *secattr); 411 411 void netlbl_sock_delattr(struct sock *sk); 412 412 int netlbl_sock_getattr(struct sock *sk, ··· 415 413 int netlbl_conn_setattr(struct sock *sk, 416 414 struct sockaddr *addr, 417 415 const struct netlbl_lsm_secattr *secattr); 416 + int netlbl_req_setattr(struct request_sock *req, 417 + const struct netlbl_lsm_secattr *secattr); 418 418 int netlbl_skbuff_setattr(struct sk_buff *skb, 419 419 u16 family, 420 420 const struct netlbl_lsm_secattr *secattr); ··· 523 519 return 0; 524 520 } 525 521 static inline int netlbl_sock_setattr(struct sock *sk, 526 - const struct netlbl_lsm_secattr *secattr) 522 + u16 family, 523 + const struct netlbl_lsm_secattr *secattr) 527 524 { 528 525 return -ENOSYS; 529 526 } ··· 539 534 static inline int netlbl_conn_setattr(struct sock *sk, 540 535 struct sockaddr *addr, 541 536 const struct netlbl_lsm_secattr *secattr) 537 + { 538 + return -ENOSYS; 539 + } 540 + static inline int netlbl_req_setattr(struct request_sock *req, 541 + const struct netlbl_lsm_secattr *secattr) 542 542 { 543 543 return -ENOSYS; 544 544 }
+118 -12
net/ipv4/cipso_ipv4.c
··· 1942 1942 } 1943 1943 1944 1944 /** 1945 - * cipso_v4_sock_delattr - Delete the CIPSO option from a socket 1946 - * @sk: the socket 1945 + * cipso_v4_req_setattr - Add a CIPSO option to a connection request 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 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 */ 1952 - void cipso_v4_sock_delattr(struct sock *sk) 1956 + int 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; 1955 - struct ip_options *opt; 1956 - struct inet_sock *sk_inet; 1960 + int ret_val = -EPERM; 1961 + unsigned char *buf = NULL; 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); 1959 - opt = sk_inet->opt; 1960 - if (opt == NULL || opt->cipso == 0) 1961 - return; 1967 + /* We allocate the maximum CIPSO option size here so we are probably 1968 + * being a little wasteful, but it makes our life _much_ easier later 1969 + * on and after all we are only talking about 40 bytes. */ 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 + 2004 + req_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 + */ 2020 + int cipso_v4_delopt(struct ip_options **opt_ptr) 2021 + { 2022 + int hdr_delta = 0; 2023 + struct ip_options *opt = *opt_ptr; 1962 2024 1963 2025 if (opt->srr || opt->rr || opt->ts || opt->router_alert) { 1964 2026 u8 cipso_len; ··· 2065 2003 } else { 2066 2004 /* only the cipso option was present on the socket so we can 2067 2005 * remove the entire option struct */ 2068 - sk_inet->opt = NULL; 2006 + *opt_ptr = NULL; 2069 2007 hdr_delta = opt->optlen; 2070 2008 kfree(opt); 2071 2009 } 2072 2010 2011 + return hdr_delta; 2012 + } 2013 + 2014 + /** 2015 + * cipso_v4_sock_delattr - Delete the CIPSO option from a socket 2016 + * @sk: the socket 2017 + * 2018 + * Description: 2019 + * Removes the CIPSO option from a socket, if present. 2020 + * 2021 + */ 2022 + void cipso_v4_sock_delattr(struct sock *sk) 2023 + { 2024 + int hdr_delta; 2025 + struct ip_options *opt; 2026 + struct inet_sock *sk_inet; 2027 + 2028 + sk_inet = inet_sk(sk); 2029 + opt = sk_inet->opt; 2030 + if (opt == NULL || opt->cipso == 0) 2031 + return; 2032 + 2033 + hdr_delta = cipso_v4_delopt(&sk_inet->opt); 2073 2034 if (sk_inet->is_icsk && hdr_delta > 0) { 2074 2035 struct inet_connection_sock *sk_conn = inet_csk(sk); 2075 2036 sk_conn->icsk_ext_hdr_len -= hdr_delta; 2076 2037 sk_conn->icsk_sync_mss(sk, sk_conn->icsk_pmtu_cookie); 2077 2038 } 2039 + } 2040 + 2041 + /** 2042 + * cipso_v4_req_delattr - Delete the CIPSO option from a request socket 2043 + * @reg: the request socket 2044 + * 2045 + * Description: 2046 + * Removes the CIPSO option from a request socket, if present. 2047 + * 2048 + */ 2049 + void cipso_v4_req_delattr(struct request_sock *req) 2050 + { 2051 + struct ip_options *opt; 2052 + struct inet_request_sock *req_inet; 2053 + 2054 + req_inet = inet_rsk(req); 2055 + opt = req_inet->opt; 2056 + if (opt == NULL || opt->cipso == 0) 2057 + return; 2058 + 2059 + cipso_v4_delopt(&req_inet->opt); 2078 2060 } 2079 2061 2080 2062 /**
+132 -20
net/netlabel/netlabel_kapi.c
··· 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 623 * @sk: the socket to label 624 + * @family: protocol family 624 625 * @secattr: the security attributes 625 626 * 626 627 * Description: ··· 634 633 * 635 634 */ 636 635 int netlbl_sock_setattr(struct sock *sk, 636 + u16 family, 637 637 const struct netlbl_lsm_secattr *secattr) 638 638 { 639 - int ret_val = -ENOENT; 639 + int ret_val; 640 640 struct netlbl_dom_map *dom_entry; 641 641 642 642 rcu_read_lock(); 643 643 dom_entry = netlbl_domhsh_getentry(secattr->domain); 644 - if (dom_entry == NULL) 644 + if (dom_entry == NULL) { 645 + ret_val = -ENOENT; 645 646 goto socket_setattr_return; 646 - switch (dom_entry->type) { 647 - case NETLBL_NLTYPE_ADDRSELECT: 648 - ret_val = -EDESTADDRREQ; 647 + } 648 + switch (family) { 649 + case AF_INET: 650 + switch (dom_entry->type) { 651 + case NETLBL_NLTYPE_ADDRSELECT: 652 + ret_val = -EDESTADDRREQ; 653 + break; 654 + case NETLBL_NLTYPE_CIPSOV4: 655 + ret_val = cipso_v4_sock_setattr(sk, 656 + dom_entry->type_def.cipsov4, 657 + secattr); 658 + break; 659 + case NETLBL_NLTYPE_UNLABELED: 660 + ret_val = 0; 661 + break; 662 + default: 663 + ret_val = -ENOENT; 664 + } 649 665 break; 650 - case NETLBL_NLTYPE_CIPSOV4: 651 - ret_val = cipso_v4_sock_setattr(sk, 652 - dom_entry->type_def.cipsov4, 653 - secattr); 654 - break; 655 - case NETLBL_NLTYPE_UNLABELED: 666 + #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 667 + case AF_INET6: 668 + /* since we don't support any IPv6 labeling protocols right 669 + * now we can optimize everything away until we do */ 656 670 ret_val = 0; 657 671 break; 672 + #endif /* IPv6 */ 658 673 default: 659 - ret_val = -ENOENT; 674 + ret_val = -EPROTONOSUPPORT; 660 675 } 661 676 662 677 socket_setattr_return: ··· 706 689 * on failure. 707 690 * 708 691 */ 709 - int netlbl_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr) 692 + int netlbl_sock_getattr(struct sock *sk, 693 + struct netlbl_lsm_secattr *secattr) 710 694 { 711 - return cipso_v4_sock_getattr(sk, secattr); 695 + int ret_val; 696 + 697 + switch (sk->sk_family) { 698 + case AF_INET: 699 + ret_val = cipso_v4_sock_getattr(sk, secattr); 700 + break; 701 + #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 702 + case AF_INET6: 703 + ret_val = -ENOMSG; 704 + break; 705 + #endif /* IPv6 */ 706 + default: 707 + ret_val = -EPROTONOSUPPORT; 708 + } 709 + 710 + return ret_val; 712 711 } 713 712 714 713 /** ··· 781 748 break; 782 749 #endif /* IPv6 */ 783 750 default: 784 - ret_val = 0; 751 + ret_val = -EPROTONOSUPPORT; 785 752 } 786 753 787 754 conn_setattr_return: 755 + rcu_read_unlock(); 756 + return ret_val; 757 + } 758 + 759 + /** 760 + * netlbl_req_setattr - Label a request socket using the correct protocol 761 + * @req: the request socket to label 762 + * @secattr: the security attributes 763 + * 764 + * Description: 765 + * Attach the correct label to the given socket using the security attributes 766 + * specified in @secattr. Returns zero on success, negative values on failure. 767 + * 768 + */ 769 + int netlbl_req_setattr(struct request_sock *req, 770 + const struct netlbl_lsm_secattr *secattr) 771 + { 772 + int ret_val; 773 + struct netlbl_dom_map *dom_entry; 774 + struct netlbl_domaddr4_map *af4_entry; 775 + u32 proto_type; 776 + struct cipso_v4_doi *proto_cv4; 777 + 778 + rcu_read_lock(); 779 + dom_entry = netlbl_domhsh_getentry(secattr->domain); 780 + if (dom_entry == NULL) { 781 + ret_val = -ENOENT; 782 + goto req_setattr_return; 783 + } 784 + switch (req->rsk_ops->family) { 785 + case AF_INET: 786 + if (dom_entry->type == NETLBL_NLTYPE_ADDRSELECT) { 787 + struct inet_request_sock *req_inet = inet_rsk(req); 788 + af4_entry = netlbl_domhsh_getentry_af4(secattr->domain, 789 + req_inet->rmt_addr); 790 + if (af4_entry == NULL) { 791 + ret_val = -ENOENT; 792 + goto req_setattr_return; 793 + } 794 + proto_type = af4_entry->type; 795 + proto_cv4 = af4_entry->type_def.cipsov4; 796 + } else { 797 + proto_type = dom_entry->type; 798 + proto_cv4 = dom_entry->type_def.cipsov4; 799 + } 800 + switch (proto_type) { 801 + case NETLBL_NLTYPE_CIPSOV4: 802 + ret_val = cipso_v4_req_setattr(req, proto_cv4, secattr); 803 + break; 804 + case NETLBL_NLTYPE_UNLABELED: 805 + /* just delete the protocols we support for right now 806 + * but we could remove other protocols if needed */ 807 + cipso_v4_req_delattr(req); 808 + ret_val = 0; 809 + break; 810 + default: 811 + ret_val = -ENOENT; 812 + } 813 + break; 814 + #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 815 + case AF_INET6: 816 + /* since we don't support any IPv6 labeling protocols right 817 + * now we can optimize everything away until we do */ 818 + ret_val = 0; 819 + break; 820 + #endif /* IPv6 */ 821 + default: 822 + ret_val = -EPROTONOSUPPORT; 823 + } 824 + 825 + req_setattr_return: 788 826 rcu_read_unlock(); 789 827 return ret_val; 790 828 } ··· 912 808 break; 913 809 #endif /* IPv6 */ 914 810 default: 915 - ret_val = 0; 811 + ret_val = -EPROTONOSUPPORT; 916 812 } 917 813 918 814 skbuff_setattr_return: ··· 937 833 u16 family, 938 834 struct netlbl_lsm_secattr *secattr) 939 835 { 940 - if (CIPSO_V4_OPTEXIST(skb) && 941 - cipso_v4_skbuff_getattr(skb, secattr) == 0) 942 - return 0; 836 + switch (family) { 837 + case AF_INET: 838 + if (CIPSO_V4_OPTEXIST(skb) && 839 + cipso_v4_skbuff_getattr(skb, secattr) == 0) 840 + return 0; 841 + break; 842 + #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 843 + case AF_INET6: 844 + break; 845 + #endif /* IPv6 */ 846 + } 943 847 944 848 return netlbl_unlabel_getattr(skb, family, secattr); 945 849 }
+15 -39
security/selinux/hooks.c
··· 311 311 ssec->sid = SECINITSID_UNLABELED; 312 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 316 return 0; 317 317 } ··· 2945 2945 static int selinux_revalidate_file_permission(struct file *file, int mask) 2946 2946 { 2947 2947 const struct cred *cred = current_cred(); 2948 - int rc; 2949 2948 struct inode *inode = file->f_path.dentry->d_inode; 2950 2949 2951 2950 if (!mask) { ··· 2956 2957 if ((file->f_flags & O_APPEND) && (mask & MAY_WRITE)) 2957 2958 mask |= MAY_APPEND; 2958 2959 2959 - rc = file_has_perm(cred, file, 2960 - file_mask_to_av(inode->i_mode, mask)); 2961 - if (rc) 2962 - return rc; 2963 - 2964 - return selinux_netlbl_inode_permission(inode, mask); 2960 + return file_has_perm(cred, file, 2961 + file_mask_to_av(inode->i_mode, mask)); 2965 2962 } 2966 2963 2967 2964 static int selinux_file_permission(struct file *file, int mask) 2968 2965 { 2969 - struct inode *inode = file->f_path.dentry->d_inode; 2970 - struct file_security_struct *fsec = file->f_security; 2971 - struct inode_security_struct *isec = inode->i_security; 2972 - u32 sid = current_sid(); 2973 - 2974 - if (!mask) { 2966 + if (!mask) 2975 2967 /* No permission to check. Existence test. */ 2976 2968 return 0; 2977 - } 2978 - 2979 - if (sid == fsec->sid && fsec->isid == isec->sid 2980 - && fsec->pseqno == avc_policy_seqno()) 2981 - return selinux_netlbl_inode_permission(inode, mask); 2982 2969 2983 2970 return selinux_revalidate_file_permission(file, mask); 2984 2971 } ··· 3708 3723 sksec = sock->sk->sk_security; 3709 3724 sksec->sid = isec->sid; 3710 3725 sksec->sclass = isec->sclass; 3711 - err = selinux_netlbl_socket_post_create(sock); 3726 + err = selinux_netlbl_socket_post_create(sock->sk, family); 3712 3727 } 3713 3728 3714 3729 return err; ··· 3899 3914 static int selinux_socket_sendmsg(struct socket *sock, struct msghdr *msg, 3900 3915 int size) 3901 3916 { 3902 - int rc; 3903 - 3904 - rc = socket_has_perm(current, sock, SOCKET__WRITE); 3905 - if (rc) 3906 - return rc; 3907 - 3908 - return selinux_netlbl_inode_permission(SOCK_INODE(sock), MAY_WRITE); 3917 + return socket_has_perm(current, sock, SOCKET__WRITE); 3909 3918 } 3910 3919 3911 3920 static int selinux_socket_recvmsg(struct socket *sock, struct msghdr *msg, ··· 4283 4304 newssec->peer_sid = ssec->peer_sid; 4284 4305 newssec->sclass = ssec->sclass; 4285 4306 4286 - selinux_netlbl_sk_security_reset(newssec, newsk->sk_family); 4307 + selinux_netlbl_sk_security_reset(newssec); 4287 4308 } 4288 4309 4289 4310 static void selinux_sk_getsecid(struct sock *sk, u32 *secid) ··· 4327 4348 if (peersid == SECSID_NULL) { 4328 4349 req->secid = sksec->sid; 4329 4350 req->peer_secid = SECSID_NULL; 4330 - return 0; 4351 + } else { 4352 + err = security_sid_mls_copy(sksec->sid, peersid, &newsid); 4353 + if (err) 4354 + return err; 4355 + req->secid = newsid; 4356 + req->peer_secid = peersid; 4331 4357 } 4332 4358 4333 - err = security_sid_mls_copy(sksec->sid, peersid, &newsid); 4334 - if (err) 4335 - return err; 4336 - 4337 - req->secid = newsid; 4338 - req->peer_secid = peersid; 4339 - return 0; 4359 + return selinux_netlbl_inet_conn_request(req, family); 4340 4360 } 4341 4361 4342 4362 static void selinux_inet_csk_clone(struct sock *newsk, ··· 4352 4374 4353 4375 /* We don't need to take any sort of lock here as we are the only 4354 4376 * thread with access to newsksec */ 4355 - selinux_netlbl_sk_security_reset(newsksec, req->rsk_ops->family); 4377 + selinux_netlbl_inet_csk_clone(newsk, req->rsk_ops->family); 4356 4378 } 4357 4379 4358 4380 static void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb) ··· 4365 4387 family = PF_INET; 4366 4388 4367 4389 selinux_skb_peerlbl_sid(skb, family, &sksec->peer_sid); 4368 - 4369 - selinux_netlbl_inet_conn_established(sk, family); 4370 4390 } 4371 4391 4372 4392 static void selinux_req_classify_flow(const struct request_sock *req,
+14 -15
security/selinux/include/netlabel.h
··· 32 32 #include <linux/net.h> 33 33 #include <linux/skbuff.h> 34 34 #include <net/sock.h> 35 + #include <net/request_sock.h> 35 36 36 37 #include "avc.h" 37 38 #include "objsec.h" ··· 43 42 void selinux_netlbl_err(struct sk_buff *skb, int error, int gateway); 44 43 45 44 void selinux_netlbl_sk_security_free(struct sk_security_struct *ssec); 46 - void selinux_netlbl_sk_security_reset(struct sk_security_struct *ssec, 47 - int family); 45 + void selinux_netlbl_sk_security_reset(struct sk_security_struct *ssec); 48 46 49 47 int selinux_netlbl_skbuff_getsid(struct sk_buff *skb, 50 48 u16 family, ··· 53 53 u16 family, 54 54 u32 sid); 55 55 56 - void selinux_netlbl_inet_conn_established(struct sock *sk, u16 family); 57 - int selinux_netlbl_socket_post_create(struct socket *sock); 58 - int selinux_netlbl_inode_permission(struct inode *inode, int mask); 56 + int selinux_netlbl_inet_conn_request(struct request_sock *req, u16 family); 57 + void selinux_netlbl_inet_csk_clone(struct sock *sk, u16 family); 58 + int selinux_netlbl_socket_post_create(struct sock *sk, u16 family); 59 59 int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec, 60 60 struct sk_buff *skb, 61 61 u16 family, ··· 85 85 } 86 86 87 87 static inline void selinux_netlbl_sk_security_reset( 88 - struct sk_security_struct *ssec, 89 - int family) 88 + struct sk_security_struct *ssec) 90 89 { 91 90 return; 92 91 } ··· 112 113 return 0; 113 114 } 114 115 115 - static inline void selinux_netlbl_inet_conn_established(struct sock *sk, 116 - u16 family) 117 - { 118 - return; 119 - } 120 - static inline int selinux_netlbl_socket_post_create(struct socket *sock) 116 + static inline int selinux_netlbl_inet_conn_request(struct request_sock *req, 117 + u16 family) 121 118 { 122 119 return 0; 123 120 } 124 - static inline int selinux_netlbl_inode_permission(struct inode *inode, 125 - int mask) 121 + static inline void selinux_netlbl_inet_csk_clone(struct sock *sk, u16 family) 122 + { 123 + return; 124 + } 125 + static inline int selinux_netlbl_socket_post_create(struct sock *sk, 126 + u16 family) 126 127 { 127 128 return 0; 128 129 }
+56 -136
security/selinux/netlabel.c
··· 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 - */ 111 - static 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 103 * selinux_netlbl_cache_invalidate - Invalidate the NetLabel cache 139 104 * 140 105 * Description: ··· 153 188 * The caller is responsibile for all the NetLabel sk_security_struct locking. 154 189 * 155 190 */ 156 - void selinux_netlbl_sk_security_reset(struct sk_security_struct *ssec, 157 - int family) 191 + void selinux_netlbl_sk_security_reset(struct sk_security_struct *ssec) 158 192 { 159 - if (family == PF_INET) 160 - ssec->nlbl_state = NLBL_REQUIRE; 161 - else 162 - ssec->nlbl_state = NLBL_UNSET; 193 + ssec->nlbl_state = NLBL_UNSET; 163 194 } 164 195 165 196 /** ··· 242 281 } 243 282 244 283 /** 245 - * selinux_netlbl_inet_conn_established - Netlabel the newly accepted connection 246 - * @sk: the new connection 284 + * selinux_netlbl_inet_conn_request - Label an incoming stream connection 285 + * @req: incoming connection request socket 247 286 * 248 287 * Description: 249 - * A new connection has been established on @sk so make sure it is labeled 250 - * correctly with the NetLabel susbsystem. 288 + * A new incoming connection request is represented by @req, we need to label 289 + * the new request_sock here and the stack will ensure the on-the-wire label 290 + * will get preserved when a full sock is created once the connection handshake 291 + * is complete. Returns zero on success, negative values on failure. 251 292 * 252 293 */ 253 - void selinux_netlbl_inet_conn_established(struct sock *sk, u16 family) 294 + int selinux_netlbl_inet_conn_request(struct request_sock *req, u16 family) 254 295 { 255 296 int rc; 297 + struct netlbl_lsm_secattr secattr; 298 + 299 + if (family != PF_INET) 300 + return 0; 301 + 302 + netlbl_secattr_init(&secattr); 303 + rc = security_netlbl_sid_to_secattr(req->secid, &secattr); 304 + if (rc != 0) 305 + goto inet_conn_request_return; 306 + rc = netlbl_req_setattr(req, &secattr); 307 + inet_conn_request_return: 308 + netlbl_secattr_destroy(&secattr); 309 + return rc; 310 + } 311 + 312 + /** 313 + * selinux_netlbl_inet_csk_clone - Initialize the newly created sock 314 + * @sk: the new sock 315 + * 316 + * Description: 317 + * A new connection has been established using @sk, we've already labeled the 318 + * socket via the request_sock struct in selinux_netlbl_inet_conn_request() but 319 + * we need to set the NetLabel state here since we now have a sock structure. 320 + * 321 + */ 322 + void selinux_netlbl_inet_csk_clone(struct sock *sk, u16 family) 323 + { 256 324 struct sk_security_struct *sksec = sk->sk_security; 257 - struct netlbl_lsm_secattr *secattr; 258 - struct inet_sock *sk_inet = inet_sk(sk); 259 - struct sockaddr_in addr; 260 325 261 - if (sksec->nlbl_state != NLBL_REQUIRE) 262 - return; 263 - 264 - secattr = selinux_netlbl_sock_genattr(sk); 265 - if (secattr == NULL) 266 - return; 267 - 268 - rc = netlbl_sock_setattr(sk, secattr); 269 - switch (rc) { 270 - case 0: 326 + if (family == PF_INET) 271 327 sksec->nlbl_state = NLBL_LABELED; 272 - break; 273 - case -EDESTADDRREQ: 274 - /* no PF_INET6 support yet because we don't support any IPv6 275 - * labeling protocols */ 276 - if (family != PF_INET) { 277 - sksec->nlbl_state = NLBL_UNSET; 278 - return; 279 - } 280 - 281 - addr.sin_family = family; 282 - addr.sin_addr.s_addr = sk_inet->daddr; 283 - if (netlbl_conn_setattr(sk, (struct sockaddr *)&addr, 284 - secattr) != 0) { 285 - /* we failed to label the connected socket (could be 286 - * for a variety of reasons, the actual "why" isn't 287 - * important here) so we have to go to our backup plan, 288 - * labeling the packets individually in the netfilter 289 - * local output hook. this is okay but we need to 290 - * adjust the MSS of the connection to take into 291 - * account any labeling overhead, since we don't know 292 - * the exact overhead at this point we'll use the worst 293 - * case value which is 40 bytes for IPv4 */ 294 - struct inet_connection_sock *sk_conn = inet_csk(sk); 295 - sk_conn->icsk_ext_hdr_len += 40 - 296 - (sk_inet->opt ? sk_inet->opt->optlen : 0); 297 - sk_conn->icsk_sync_mss(sk, sk_conn->icsk_pmtu_cookie); 298 - 299 - sksec->nlbl_state = NLBL_REQSKB; 300 - } else 301 - sksec->nlbl_state = NLBL_CONNLABELED; 302 - break; 303 - default: 304 - /* note that we are failing to label the socket which could be 305 - * a bad thing since it means traffic could leave the system 306 - * without the desired labeling, however, all is not lost as 307 - * we have a check in selinux_netlbl_inode_permission() to 308 - * pick up the pieces that we might drop here because we can't 309 - * return an error code */ 310 - break; 311 - } 328 + else 329 + sksec->nlbl_state = NLBL_UNSET; 312 330 } 313 331 314 332 /** 315 333 * selinux_netlbl_socket_post_create - Label a socket using NetLabel 316 334 * @sock: the socket to label 335 + * @family: protocol family 317 336 * 318 337 * Description: 319 338 * Attempt to label a socket using the NetLabel mechanism using the given 320 339 * SID. Returns zero values on success, negative values on failure. 321 340 * 322 341 */ 323 - int selinux_netlbl_socket_post_create(struct socket *sock) 324 - { 325 - return selinux_netlbl_sock_setsid(sock->sk); 326 - } 327 - 328 - /** 329 - * selinux_netlbl_inode_permission - Verify the socket is NetLabel labeled 330 - * @inode: the file descriptor's inode 331 - * @mask: the permission mask 332 - * 333 - * Description: 334 - * Looks at a file's inode and if it is marked as a socket protected by 335 - * NetLabel then verify that the socket has been labeled, if not try to label 336 - * the socket now with the inode's SID. Returns zero on success, negative 337 - * values on failure. 338 - * 339 - */ 340 - int selinux_netlbl_inode_permission(struct inode *inode, int mask) 342 + int selinux_netlbl_socket_post_create(struct sock *sk, u16 family) 341 343 { 342 344 int rc; 343 - struct sock *sk; 344 - struct socket *sock; 345 - struct sk_security_struct *sksec; 345 + struct sk_security_struct *sksec = sk->sk_security; 346 + struct netlbl_lsm_secattr *secattr; 346 347 347 - if (!S_ISSOCK(inode->i_mode) || 348 - ((mask & (MAY_WRITE | MAY_APPEND)) == 0)) 349 - return 0; 350 - sock = SOCKET_I(inode); 351 - sk = sock->sk; 352 - if (sk == NULL) 353 - return 0; 354 - sksec = sk->sk_security; 355 - if (sksec == NULL || sksec->nlbl_state != NLBL_REQUIRE) 348 + if (family != PF_INET) 356 349 return 0; 357 350 358 - local_bh_disable(); 359 - bh_lock_sock_nested(sk); 360 - if (likely(sksec->nlbl_state == NLBL_REQUIRE)) 361 - rc = selinux_netlbl_sock_setsid(sk); 362 - else 351 + secattr = selinux_netlbl_sock_genattr(sk); 352 + if (secattr == NULL) 353 + return -ENOMEM; 354 + rc = netlbl_sock_setattr(sk, family, secattr); 355 + switch (rc) { 356 + case 0: 357 + sksec->nlbl_state = NLBL_LABELED; 358 + break; 359 + case -EDESTADDRREQ: 360 + sksec->nlbl_state = NLBL_REQSKB; 363 361 rc = 0; 364 - bh_unlock_sock(sk); 365 - local_bh_enable(); 362 + break; 363 + } 366 364 367 365 return rc; 368 366 }
+1 -1
security/smack/smack_lsm.c
··· 1387 1387 else { 1388 1388 netlbl_secattr_init(&secattr); 1389 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 1391 netlbl_secattr_destroy(&secattr); 1392 1392 } 1393 1393