diff options
-rw-r--r-- | security/selinux/hooks.c | 204 | ||||
-rw-r--r-- | security/selinux/include/netlabel.h | 3 | ||||
-rw-r--r-- | security/selinux/include/objsec.h | 2 | ||||
-rw-r--r-- | security/selinux/include/security.h | 4 | ||||
-rw-r--r-- | security/selinux/netlabel.c | 10 | ||||
-rw-r--r-- | security/selinux/ss/services.c | 85 |
6 files changed, 208 insertions, 100 deletions
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 4bca0af4f2af..bfe9a05db3a2 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
@@ -50,6 +50,7 @@ | |||
50 | #include <net/icmp.h> | 50 | #include <net/icmp.h> |
51 | #include <net/ip.h> /* for local_port_range[] */ | 51 | #include <net/ip.h> /* for local_port_range[] */ |
52 | #include <net/tcp.h> /* struct or_callable used in sock_rcv_skb */ | 52 | #include <net/tcp.h> /* struct or_callable used in sock_rcv_skb */ |
53 | #include <net/net_namespace.h> | ||
53 | #include <asm/uaccess.h> | 54 | #include <asm/uaccess.h> |
54 | #include <asm/ioctls.h> | 55 | #include <asm/ioctls.h> |
55 | #include <linux/bitops.h> | 56 | #include <linux/bitops.h> |
@@ -3426,36 +3427,39 @@ static int selinux_parse_skb(struct sk_buff *skb, struct avc_audit_data *ad, | |||
3426 | } | 3427 | } |
3427 | 3428 | ||
3428 | /** | 3429 | /** |
3429 | * selinux_skb_extlbl_sid - Determine the external label of a packet | 3430 | * selinux_skb_peerlbl_sid - Determine the peer label of a packet |
3430 | * @skb: the packet | 3431 | * @skb: the packet |
3431 | * @family: protocol family | 3432 | * @family: protocol family |
3432 | * @sid: the packet's SID | 3433 | * @sid: the packet's peer label SID |
3433 | * | 3434 | * |
3434 | * Description: | 3435 | * Description: |
3435 | * Check the various different forms of external packet labeling and determine | 3436 | * Check the various different forms of network peer labeling and determine |
3436 | * the external SID for the packet. If only one form of external labeling is | 3437 | * the peer label/SID for the packet; most of the magic actually occurs in |
3437 | * present then it is used, if both labeled IPsec and NetLabel labels are | 3438 | * the security server function security_net_peersid_cmp(). The function |
3438 | * present then the SELinux type information is taken from the labeled IPsec | 3439 | * returns zero if the value in @sid is valid (although it may be SECSID_NULL) |
3439 | * SA and the MLS sensitivity label information is taken from the NetLabel | 3440 | * or -EACCES if @sid is invalid due to inconsistencies with the different |
3440 | * security attributes. This bit of "magic" is done in the call to | 3441 | * peer labels. |
3441 | * selinux_netlbl_skbuff_getsid(). | ||
3442 | * | 3442 | * |
3443 | */ | 3443 | */ |
3444 | static void selinux_skb_extlbl_sid(struct sk_buff *skb, | 3444 | static int selinux_skb_peerlbl_sid(struct sk_buff *skb, u16 family, u32 *sid) |
3445 | u16 family, | ||
3446 | u32 *sid) | ||
3447 | { | 3445 | { |
3448 | u32 xfrm_sid; | 3446 | u32 xfrm_sid; |
3449 | u32 nlbl_sid; | 3447 | u32 nlbl_sid; |
3448 | u32 nlbl_type; | ||
3450 | 3449 | ||
3451 | selinux_skb_xfrm_sid(skb, &xfrm_sid); | 3450 | selinux_skb_xfrm_sid(skb, &xfrm_sid); |
3452 | if (selinux_netlbl_skbuff_getsid(skb, | 3451 | selinux_netlbl_skbuff_getsid(skb, |
3453 | family, | 3452 | family, |
3454 | (xfrm_sid == SECSID_NULL ? | 3453 | SECINITSID_NETMSG, |
3455 | SECINITSID_NETMSG : xfrm_sid), | 3454 | &nlbl_type, |
3456 | &nlbl_sid) != 0) | 3455 | &nlbl_sid); |
3457 | nlbl_sid = SECSID_NULL; | 3456 | |
3458 | *sid = (nlbl_sid == SECSID_NULL ? xfrm_sid : nlbl_sid); | 3457 | if (security_net_peersid_resolve(nlbl_sid, nlbl_type, |
3458 | xfrm_sid, | ||
3459 | sid) != 0) | ||
3460 | return -EACCES; | ||
3461 | |||
3462 | return 0; | ||
3459 | } | 3463 | } |
3460 | 3464 | ||
3461 | /* socket security operations */ | 3465 | /* socket security operations */ |
@@ -3521,6 +3525,7 @@ static int selinux_socket_post_create(struct socket *sock, int family, | |||
3521 | if (sock->sk) { | 3525 | if (sock->sk) { |
3522 | sksec = sock->sk->sk_security; | 3526 | sksec = sock->sk->sk_security; |
3523 | sksec->sid = isec->sid; | 3527 | sksec->sid = isec->sid; |
3528 | sksec->sclass = isec->sclass; | ||
3524 | err = selinux_netlbl_socket_post_create(sock); | 3529 | err = selinux_netlbl_socket_post_create(sock); |
3525 | } | 3530 | } |
3526 | 3531 | ||
@@ -3824,104 +3829,114 @@ static int selinux_socket_unix_may_send(struct socket *sock, | |||
3824 | return 0; | 3829 | return 0; |
3825 | } | 3830 | } |
3826 | 3831 | ||
3827 | static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb, | 3832 | static int selinux_sock_rcv_skb_iptables_compat(struct sock *sk, |
3828 | struct avc_audit_data *ad, | 3833 | struct sk_buff *skb, |
3829 | u16 family, char *addrp) | 3834 | struct avc_audit_data *ad, |
3835 | u16 family, | ||
3836 | char *addrp) | ||
3830 | { | 3837 | { |
3831 | int err = 0; | 3838 | int err; |
3832 | u32 netif_perm, node_perm, node_sid, if_sid, recv_perm = 0; | 3839 | struct sk_security_struct *sksec = sk->sk_security; |
3833 | struct socket *sock; | 3840 | u16 sk_class; |
3834 | u16 sock_class = 0; | 3841 | u32 netif_perm, node_perm, recv_perm; |
3835 | u32 sock_sid = 0; | 3842 | u32 port_sid, node_sid, if_sid, sk_sid; |
3836 | |||
3837 | read_lock_bh(&sk->sk_callback_lock); | ||
3838 | sock = sk->sk_socket; | ||
3839 | if (sock) { | ||
3840 | struct inode *inode; | ||
3841 | inode = SOCK_INODE(sock); | ||
3842 | if (inode) { | ||
3843 | struct inode_security_struct *isec; | ||
3844 | isec = inode->i_security; | ||
3845 | sock_sid = isec->sid; | ||
3846 | sock_class = isec->sclass; | ||
3847 | } | ||
3848 | } | ||
3849 | read_unlock_bh(&sk->sk_callback_lock); | ||
3850 | if (!sock_sid) | ||
3851 | goto out; | ||
3852 | |||
3853 | if (!skb->dev) | ||
3854 | goto out; | ||
3855 | 3843 | ||
3856 | err = sel_netif_sid(skb->iif, &if_sid); | 3844 | sk_sid = sksec->sid; |
3857 | if (err) | 3845 | sk_class = sksec->sclass; |
3858 | goto out; | ||
3859 | 3846 | ||
3860 | switch (sock_class) { | 3847 | switch (sk_class) { |
3861 | case SECCLASS_UDP_SOCKET: | 3848 | case SECCLASS_UDP_SOCKET: |
3862 | netif_perm = NETIF__UDP_RECV; | 3849 | netif_perm = NETIF__UDP_RECV; |
3863 | node_perm = NODE__UDP_RECV; | 3850 | node_perm = NODE__UDP_RECV; |
3864 | recv_perm = UDP_SOCKET__RECV_MSG; | 3851 | recv_perm = UDP_SOCKET__RECV_MSG; |
3865 | break; | 3852 | break; |
3866 | |||
3867 | case SECCLASS_TCP_SOCKET: | 3853 | case SECCLASS_TCP_SOCKET: |
3868 | netif_perm = NETIF__TCP_RECV; | 3854 | netif_perm = NETIF__TCP_RECV; |
3869 | node_perm = NODE__TCP_RECV; | 3855 | node_perm = NODE__TCP_RECV; |
3870 | recv_perm = TCP_SOCKET__RECV_MSG; | 3856 | recv_perm = TCP_SOCKET__RECV_MSG; |
3871 | break; | 3857 | break; |
3872 | |||
3873 | case SECCLASS_DCCP_SOCKET: | 3858 | case SECCLASS_DCCP_SOCKET: |
3874 | netif_perm = NETIF__DCCP_RECV; | 3859 | netif_perm = NETIF__DCCP_RECV; |
3875 | node_perm = NODE__DCCP_RECV; | 3860 | node_perm = NODE__DCCP_RECV; |
3876 | recv_perm = DCCP_SOCKET__RECV_MSG; | 3861 | recv_perm = DCCP_SOCKET__RECV_MSG; |
3877 | break; | 3862 | break; |
3878 | |||
3879 | default: | 3863 | default: |
3880 | netif_perm = NETIF__RAWIP_RECV; | 3864 | netif_perm = NETIF__RAWIP_RECV; |
3881 | node_perm = NODE__RAWIP_RECV; | 3865 | node_perm = NODE__RAWIP_RECV; |
3866 | recv_perm = 0; | ||
3882 | break; | 3867 | break; |
3883 | } | 3868 | } |
3884 | 3869 | ||
3885 | err = avc_has_perm(sock_sid, if_sid, SECCLASS_NETIF, netif_perm, ad); | 3870 | err = sel_netif_sid(skb->iif, &if_sid); |
3886 | if (err) | 3871 | if (err) |
3887 | goto out; | 3872 | return err; |
3873 | err = avc_has_perm(sk_sid, if_sid, SECCLASS_NETIF, netif_perm, ad); | ||
3874 | if (err) | ||
3875 | return err; | ||
3888 | 3876 | ||
3889 | err = sel_netnode_sid(addrp, family, &node_sid); | 3877 | err = sel_netnode_sid(addrp, family, &node_sid); |
3890 | if (err) | 3878 | if (err) |
3891 | goto out; | 3879 | return err; |
3892 | 3880 | err = avc_has_perm(sk_sid, node_sid, SECCLASS_NODE, node_perm, ad); | |
3893 | err = avc_has_perm(sock_sid, node_sid, SECCLASS_NODE, node_perm, ad); | ||
3894 | if (err) | 3881 | if (err) |
3895 | goto out; | 3882 | return err; |
3896 | 3883 | ||
3897 | if (recv_perm) { | 3884 | if (!recv_perm) |
3898 | u32 port_sid; | 3885 | return 0; |
3886 | err = security_port_sid(sk->sk_family, sk->sk_type, | ||
3887 | sk->sk_protocol, ntohs(ad->u.net.sport), | ||
3888 | &port_sid); | ||
3889 | if (err) | ||
3890 | return err; | ||
3891 | return avc_has_perm(sk_sid, port_sid, sk_class, recv_perm, ad); | ||
3892 | } | ||
3899 | 3893 | ||
3900 | err = security_port_sid(sk->sk_family, sk->sk_type, | 3894 | static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb, |
3901 | sk->sk_protocol, ntohs(ad->u.net.sport), | 3895 | struct avc_audit_data *ad, |
3902 | &port_sid); | 3896 | u16 family, char *addrp) |
3903 | if (err) | 3897 | { |
3904 | goto out; | 3898 | int err; |
3899 | struct sk_security_struct *sksec = sk->sk_security; | ||
3900 | u32 peer_sid; | ||
3901 | u32 sk_sid = sksec->sid; | ||
3902 | |||
3903 | if (selinux_compat_net) | ||
3904 | err = selinux_sock_rcv_skb_iptables_compat(sk, skb, ad, | ||
3905 | family, addrp); | ||
3906 | else | ||
3907 | err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET, | ||
3908 | PACKET__RECV, ad); | ||
3909 | if (err) | ||
3910 | return err; | ||
3905 | 3911 | ||
3906 | err = avc_has_perm(sock_sid, port_sid, | 3912 | if (selinux_policycap_netpeer) { |
3907 | sock_class, recv_perm, ad); | 3913 | err = selinux_skb_peerlbl_sid(skb, family, &peer_sid); |
3914 | if (err) | ||
3915 | return err; | ||
3916 | err = avc_has_perm(sk_sid, peer_sid, | ||
3917 | SECCLASS_PEER, PEER__RECV, ad); | ||
3918 | } else { | ||
3919 | err = selinux_netlbl_sock_rcv_skb(sksec, skb, family, ad); | ||
3920 | if (err) | ||
3921 | return err; | ||
3922 | err = selinux_xfrm_sock_rcv_skb(sksec->sid, skb, ad); | ||
3908 | } | 3923 | } |
3909 | 3924 | ||
3910 | out: | ||
3911 | return err; | 3925 | return err; |
3912 | } | 3926 | } |
3913 | 3927 | ||
3914 | static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) | 3928 | static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) |
3915 | { | 3929 | { |
3916 | u16 family; | 3930 | int err; |
3917 | char *addrp; | ||
3918 | int err = 0; | ||
3919 | struct avc_audit_data ad; | ||
3920 | struct sk_security_struct *sksec = sk->sk_security; | 3931 | struct sk_security_struct *sksec = sk->sk_security; |
3932 | u16 family = sk->sk_family; | ||
3933 | u32 sk_sid = sksec->sid; | ||
3934 | u32 peer_sid; | ||
3935 | struct avc_audit_data ad; | ||
3936 | char *addrp; | ||
3921 | 3937 | ||
3922 | family = sk->sk_family; | ||
3923 | if (family != PF_INET && family != PF_INET6) | 3938 | if (family != PF_INET && family != PF_INET6) |
3924 | goto out; | 3939 | return 0; |
3925 | 3940 | ||
3926 | /* Handle mapped IPv4 packets arriving via IPv6 sockets */ | 3941 | /* Handle mapped IPv4 packets arriving via IPv6 sockets */ |
3927 | if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP)) | 3942 | if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP)) |
@@ -3930,26 +3945,27 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) | |||
3930 | AVC_AUDIT_DATA_INIT(&ad, NET); | 3945 | AVC_AUDIT_DATA_INIT(&ad, NET); |
3931 | ad.u.net.netif = skb->iif; | 3946 | ad.u.net.netif = skb->iif; |
3932 | ad.u.net.family = family; | 3947 | ad.u.net.family = family; |
3933 | |||
3934 | err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL); | 3948 | err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL); |
3935 | if (err) | 3949 | if (err) |
3936 | goto out; | 3950 | return err; |
3937 | 3951 | ||
3938 | if (selinux_compat_net) | 3952 | /* If any sort of compatibility mode is enabled then handoff processing |
3939 | err = selinux_sock_rcv_skb_compat(sk, skb, &ad, family, addrp); | 3953 | * to the selinux_sock_rcv_skb_compat() function to deal with the |
3940 | else | 3954 | * special handling. We do this in an attempt to keep this function |
3941 | err = avc_has_perm(sksec->sid, skb->secmark, SECCLASS_PACKET, | 3955 | * as fast and as clean as possible. */ |
3942 | PACKET__RECV, &ad); | 3956 | if (selinux_compat_net || !selinux_policycap_netpeer) |
3943 | if (err) | 3957 | return selinux_sock_rcv_skb_compat(sk, skb, &ad, |
3944 | goto out; | 3958 | family, addrp); |
3945 | 3959 | ||
3946 | err = selinux_netlbl_sock_rcv_skb(sksec, skb, family, &ad); | 3960 | err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET, |
3961 | PACKET__RECV, &ad); | ||
3947 | if (err) | 3962 | if (err) |
3948 | goto out; | 3963 | return err; |
3949 | 3964 | ||
3950 | err = selinux_xfrm_sock_rcv_skb(sksec->sid, skb, &ad); | 3965 | err = selinux_skb_peerlbl_sid(skb, family, &peer_sid); |
3951 | out: | 3966 | if (err) |
3952 | return err; | 3967 | return err; |
3968 | return avc_has_perm(sk_sid, peer_sid, SECCLASS_PEER, PEER__RECV, &ad); | ||
3953 | } | 3969 | } |
3954 | 3970 | ||
3955 | static int selinux_socket_getpeersec_stream(struct socket *sock, char __user *optval, | 3971 | static int selinux_socket_getpeersec_stream(struct socket *sock, char __user *optval, |
@@ -4011,7 +4027,7 @@ static int selinux_socket_getpeersec_dgram(struct socket *sock, struct sk_buff * | |||
4011 | if (sock && family == PF_UNIX) | 4027 | if (sock && family == PF_UNIX) |
4012 | selinux_get_inode_sid(SOCK_INODE(sock), &peer_secid); | 4028 | selinux_get_inode_sid(SOCK_INODE(sock), &peer_secid); |
4013 | else if (skb) | 4029 | else if (skb) |
4014 | selinux_skb_extlbl_sid(skb, family, &peer_secid); | 4030 | selinux_skb_peerlbl_sid(skb, family, &peer_secid); |
4015 | 4031 | ||
4016 | out: | 4032 | out: |
4017 | *secid = peer_secid; | 4033 | *secid = peer_secid; |
@@ -4037,6 +4053,7 @@ static void selinux_sk_clone_security(const struct sock *sk, struct sock *newsk) | |||
4037 | 4053 | ||
4038 | newssec->sid = ssec->sid; | 4054 | newssec->sid = ssec->sid; |
4039 | newssec->peer_sid = ssec->peer_sid; | 4055 | newssec->peer_sid = ssec->peer_sid; |
4056 | newssec->sclass = ssec->sclass; | ||
4040 | 4057 | ||
4041 | selinux_netlbl_sk_security_clone(ssec, newssec); | 4058 | selinux_netlbl_sk_security_clone(ssec, newssec); |
4042 | } | 4059 | } |
@@ -4060,6 +4077,7 @@ static void selinux_sock_graft(struct sock* sk, struct socket *parent) | |||
4060 | if (sk->sk_family == PF_INET || sk->sk_family == PF_INET6 || | 4077 | if (sk->sk_family == PF_INET || sk->sk_family == PF_INET6 || |
4061 | sk->sk_family == PF_UNIX) | 4078 | sk->sk_family == PF_UNIX) |
4062 | isec->sid = sksec->sid; | 4079 | isec->sid = sksec->sid; |
4080 | sksec->sclass = isec->sclass; | ||
4063 | 4081 | ||
4064 | selinux_netlbl_sock_graft(sk, parent); | 4082 | selinux_netlbl_sock_graft(sk, parent); |
4065 | } | 4083 | } |
@@ -4072,7 +4090,9 @@ static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb, | |||
4072 | u32 newsid; | 4090 | u32 newsid; |
4073 | u32 peersid; | 4091 | u32 peersid; |
4074 | 4092 | ||
4075 | selinux_skb_extlbl_sid(skb, sk->sk_family, &peersid); | 4093 | err = selinux_skb_peerlbl_sid(skb, sk->sk_family, &peersid); |
4094 | if (err) | ||
4095 | return err; | ||
4076 | if (peersid == SECSID_NULL) { | 4096 | if (peersid == SECSID_NULL) { |
4077 | req->secid = sksec->sid; | 4097 | req->secid = sksec->sid; |
4078 | req->peer_secid = SECSID_NULL; | 4098 | req->peer_secid = SECSID_NULL; |
@@ -4110,7 +4130,7 @@ static void selinux_inet_conn_established(struct sock *sk, | |||
4110 | { | 4130 | { |
4111 | struct sk_security_struct *sksec = sk->sk_security; | 4131 | struct sk_security_struct *sksec = sk->sk_security; |
4112 | 4132 | ||
4113 | selinux_skb_extlbl_sid(skb, sk->sk_family, &sksec->peer_sid); | 4133 | selinux_skb_peerlbl_sid(skb, sk->sk_family, &sksec->peer_sid); |
4114 | } | 4134 | } |
4115 | 4135 | ||
4116 | static void selinux_req_classify_flow(const struct request_sock *req, | 4136 | 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 272769a1cb96..c8c05a6f298c 100644 --- a/security/selinux/include/netlabel.h +++ b/security/selinux/include/netlabel.h | |||
@@ -49,6 +49,7 @@ void selinux_netlbl_sk_security_clone(struct sk_security_struct *ssec, | |||
49 | int selinux_netlbl_skbuff_getsid(struct sk_buff *skb, | 49 | int selinux_netlbl_skbuff_getsid(struct sk_buff *skb, |
50 | u16 family, | 50 | u16 family, |
51 | u32 base_sid, | 51 | u32 base_sid, |
52 | u32 *type, | ||
52 | u32 *sid); | 53 | u32 *sid); |
53 | 54 | ||
54 | void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock); | 55 | void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock); |
@@ -89,8 +90,10 @@ static inline void selinux_netlbl_sk_security_clone( | |||
89 | static inline int selinux_netlbl_skbuff_getsid(struct sk_buff *skb, | 90 | static inline int selinux_netlbl_skbuff_getsid(struct sk_buff *skb, |
90 | u16 family, | 91 | u16 family, |
91 | u32 base_sid, | 92 | u32 base_sid, |
93 | u32 *type, | ||
92 | u32 *sid) | 94 | u32 *sid) |
93 | { | 95 | { |
96 | *type = NETLBL_NLTYPE_NONE; | ||
94 | *sid = SECSID_NULL; | 97 | *sid = SECSID_NULL; |
95 | return 0; | 98 | return 0; |
96 | } | 99 | } |
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h index 95fb5ec17354..c6c2bb4ebacc 100644 --- a/security/selinux/include/objsec.h +++ b/security/selinux/include/objsec.h | |||
@@ -113,8 +113,8 @@ struct sk_security_struct { | |||
113 | struct sock *sk; /* back pointer to sk object */ | 113 | struct sock *sk; /* back pointer to sk object */ |
114 | u32 sid; /* SID of this object */ | 114 | u32 sid; /* SID of this object */ |
115 | u32 peer_sid; /* SID of peer */ | 115 | u32 peer_sid; /* SID of peer */ |
116 | #ifdef CONFIG_NETLABEL | ||
117 | u16 sclass; /* sock security class */ | 116 | u16 sclass; /* sock security class */ |
117 | #ifdef CONFIG_NETLABEL | ||
118 | enum { /* NetLabel state */ | 118 | enum { /* NetLabel state */ |
119 | NLBL_UNSET = 0, | 119 | NLBL_UNSET = 0, |
120 | NLBL_REQUIRE, | 120 | NLBL_REQUIRE, |
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h index a22de9771806..9347e2daa8d4 100644 --- a/security/selinux/include/security.h +++ b/security/selinux/include/security.h | |||
@@ -99,6 +99,10 @@ int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid, | |||
99 | 99 | ||
100 | int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid); | 100 | int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid); |
101 | 101 | ||
102 | int security_net_peersid_resolve(u32 nlbl_sid, u32 nlbl_type, | ||
103 | u32 xfrm_sid, | ||
104 | u32 *peer_sid); | ||
105 | |||
102 | int security_get_classes(char ***classes, int *nclasses); | 106 | int security_get_classes(char ***classes, int *nclasses); |
103 | int security_get_permissions(char *class, char ***perms, int *nperms); | 107 | int security_get_permissions(char *class, char ***perms, int *nperms); |
104 | int security_get_reject_unknown(void); | 108 | int security_get_reject_unknown(void); |
diff --git a/security/selinux/netlabel.c b/security/selinux/netlabel.c index f4bcbf12a4c9..b54d28fd3b5d 100644 --- a/security/selinux/netlabel.c +++ b/security/selinux/netlabel.c | |||
@@ -137,7 +137,6 @@ void selinux_netlbl_sk_security_clone(struct sk_security_struct *ssec, | |||
137 | * lock as other threads could have access to ssec */ | 137 | * lock as other threads could have access to ssec */ |
138 | rcu_read_lock(); | 138 | rcu_read_lock(); |
139 | selinux_netlbl_sk_security_reset(newssec, ssec->sk->sk_family); | 139 | selinux_netlbl_sk_security_reset(newssec, ssec->sk->sk_family); |
140 | newssec->sclass = ssec->sclass; | ||
141 | rcu_read_unlock(); | 140 | rcu_read_unlock(); |
142 | } | 141 | } |
143 | 142 | ||
@@ -146,6 +145,7 @@ void selinux_netlbl_sk_security_clone(struct sk_security_struct *ssec, | |||
146 | * @skb: the packet | 145 | * @skb: the packet |
147 | * @family: protocol family | 146 | * @family: protocol family |
148 | * @base_sid: the SELinux SID to use as a context for MLS only attributes | 147 | * @base_sid: the SELinux SID to use as a context for MLS only attributes |
148 | * @type: NetLabel labeling protocol type | ||
149 | * @sid: the SID | 149 | * @sid: the SID |
150 | * | 150 | * |
151 | * Description: | 151 | * Description: |
@@ -157,6 +157,7 @@ void selinux_netlbl_sk_security_clone(struct sk_security_struct *ssec, | |||
157 | int selinux_netlbl_skbuff_getsid(struct sk_buff *skb, | 157 | int selinux_netlbl_skbuff_getsid(struct sk_buff *skb, |
158 | u16 family, | 158 | u16 family, |
159 | u32 base_sid, | 159 | u32 base_sid, |
160 | u32 *type, | ||
160 | u32 *sid) | 161 | u32 *sid) |
161 | { | 162 | { |
162 | int rc; | 163 | int rc; |
@@ -177,6 +178,7 @@ int selinux_netlbl_skbuff_getsid(struct sk_buff *skb, | |||
177 | netlbl_cache_add(skb, &secattr); | 178 | netlbl_cache_add(skb, &secattr); |
178 | } else | 179 | } else |
179 | *sid = SECSID_NULL; | 180 | *sid = SECSID_NULL; |
181 | *type = secattr.type; | ||
180 | netlbl_secattr_destroy(&secattr); | 182 | netlbl_secattr_destroy(&secattr); |
181 | 183 | ||
182 | return rc; | 184 | return rc; |
@@ -194,13 +196,10 @@ int selinux_netlbl_skbuff_getsid(struct sk_buff *skb, | |||
194 | */ | 196 | */ |
195 | void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock) | 197 | void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock) |
196 | { | 198 | { |
197 | struct inode_security_struct *isec = SOCK_INODE(sock)->i_security; | ||
198 | struct sk_security_struct *sksec = sk->sk_security; | 199 | struct sk_security_struct *sksec = sk->sk_security; |
199 | struct netlbl_lsm_secattr secattr; | 200 | struct netlbl_lsm_secattr secattr; |
200 | u32 nlbl_peer_sid; | 201 | u32 nlbl_peer_sid; |
201 | 202 | ||
202 | sksec->sclass = isec->sclass; | ||
203 | |||
204 | rcu_read_lock(); | 203 | rcu_read_lock(); |
205 | 204 | ||
206 | if (sksec->nlbl_state != NLBL_REQUIRE) { | 205 | if (sksec->nlbl_state != NLBL_REQUIRE) { |
@@ -238,11 +237,8 @@ int selinux_netlbl_socket_post_create(struct socket *sock) | |||
238 | { | 237 | { |
239 | int rc = 0; | 238 | int rc = 0; |
240 | struct sock *sk = sock->sk; | 239 | struct sock *sk = sock->sk; |
241 | struct inode_security_struct *isec = SOCK_INODE(sock)->i_security; | ||
242 | struct sk_security_struct *sksec = sk->sk_security; | 240 | struct sk_security_struct *sksec = sk->sk_security; |
243 | 241 | ||
244 | sksec->sclass = isec->sclass; | ||
245 | |||
246 | rcu_read_lock(); | 242 | rcu_read_lock(); |
247 | if (sksec->nlbl_state == NLBL_REQUIRE) | 243 | if (sksec->nlbl_state == NLBL_REQUIRE) |
248 | rc = selinux_netlbl_sock_setsid(sk, sksec->sid); | 244 | rc = selinux_netlbl_sock_setsid(sk, sksec->sid); |
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index 8ee04a424df7..7f0ee1b91e1d 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c | |||
@@ -2054,6 +2054,91 @@ out: | |||
2054 | return rc; | 2054 | return rc; |
2055 | } | 2055 | } |
2056 | 2056 | ||
2057 | /** | ||
2058 | * security_net_peersid_resolve - Compare and resolve two network peer SIDs | ||
2059 | * @nlbl_sid: NetLabel SID | ||
2060 | * @nlbl_type: NetLabel labeling protocol type | ||
2061 | * @xfrm_sid: XFRM SID | ||
2062 | * | ||
2063 | * Description: | ||
2064 | * Compare the @nlbl_sid and @xfrm_sid values and if the two SIDs can be | ||
2065 | * resolved into a single SID it is returned via @peer_sid and the function | ||
2066 | * returns zero. Otherwise @peer_sid is set to SECSID_NULL and the function | ||
2067 | * returns a negative value. A table summarizing the behavior is below: | ||
2068 | * | ||
2069 | * | function return | @sid | ||
2070 | * ------------------------------+-----------------+----------------- | ||
2071 | * no peer labels | 0 | SECSID_NULL | ||
2072 | * single peer label | 0 | <peer_label> | ||
2073 | * multiple, consistent labels | 0 | <peer_label> | ||
2074 | * multiple, inconsistent labels | -<errno> | SECSID_NULL | ||
2075 | * | ||
2076 | */ | ||
2077 | int security_net_peersid_resolve(u32 nlbl_sid, u32 nlbl_type, | ||
2078 | u32 xfrm_sid, | ||
2079 | u32 *peer_sid) | ||
2080 | { | ||
2081 | int rc; | ||
2082 | struct context *nlbl_ctx; | ||
2083 | struct context *xfrm_ctx; | ||
2084 | |||
2085 | /* handle the common (which also happens to be the set of easy) cases | ||
2086 | * right away, these two if statements catch everything involving a | ||
2087 | * single or absent peer SID/label */ | ||
2088 | if (xfrm_sid == SECSID_NULL) { | ||
2089 | *peer_sid = nlbl_sid; | ||
2090 | return 0; | ||
2091 | } | ||
2092 | /* NOTE: an nlbl_type == NETLBL_NLTYPE_UNLABELED is a "fallback" label | ||
2093 | * and is treated as if nlbl_sid == SECSID_NULL when a XFRM SID/label | ||
2094 | * is present */ | ||
2095 | if (nlbl_sid == SECSID_NULL || nlbl_type == NETLBL_NLTYPE_UNLABELED) { | ||
2096 | *peer_sid = xfrm_sid; | ||
2097 | return 0; | ||
2098 | } | ||
2099 | |||
2100 | /* we don't need to check ss_initialized here since the only way both | ||
2101 | * nlbl_sid and xfrm_sid are not equal to SECSID_NULL would be if the | ||
2102 | * security server was initialized and ss_initialized was true */ | ||
2103 | if (!selinux_mls_enabled) { | ||
2104 | *peer_sid = SECSID_NULL; | ||
2105 | return 0; | ||
2106 | } | ||
2107 | |||
2108 | POLICY_RDLOCK; | ||
2109 | |||
2110 | nlbl_ctx = sidtab_search(&sidtab, nlbl_sid); | ||
2111 | if (!nlbl_ctx) { | ||
2112 | printk(KERN_ERR | ||
2113 | "security_sid_mls_cmp: unrecognized SID %d\n", | ||
2114 | nlbl_sid); | ||
2115 | rc = -EINVAL; | ||
2116 | goto out_slowpath; | ||
2117 | } | ||
2118 | xfrm_ctx = sidtab_search(&sidtab, xfrm_sid); | ||
2119 | if (!xfrm_ctx) { | ||
2120 | printk(KERN_ERR | ||
2121 | "security_sid_mls_cmp: unrecognized SID %d\n", | ||
2122 | xfrm_sid); | ||
2123 | rc = -EINVAL; | ||
2124 | goto out_slowpath; | ||
2125 | } | ||
2126 | rc = (mls_context_cmp(nlbl_ctx, xfrm_ctx) ? 0 : -EACCES); | ||
2127 | |||
2128 | out_slowpath: | ||
2129 | POLICY_RDUNLOCK; | ||
2130 | if (rc == 0) | ||
2131 | /* at present NetLabel SIDs/labels really only carry MLS | ||
2132 | * information so if the MLS portion of the NetLabel SID | ||
2133 | * matches the MLS portion of the labeled XFRM SID/label | ||
2134 | * then pass along the XFRM SID as it is the most | ||
2135 | * expressive */ | ||
2136 | *peer_sid = xfrm_sid; | ||
2137 | else | ||
2138 | *peer_sid = SECSID_NULL; | ||
2139 | return rc; | ||
2140 | } | ||
2141 | |||
2057 | static int get_classes_callback(void *k, void *d, void *args) | 2142 | static int get_classes_callback(void *k, void *d, void *args) |
2058 | { | 2143 | { |
2059 | struct class_datum *datum = d; | 2144 | struct class_datum *datum = d; |