aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--security/selinux/hooks.c204
-rw-r--r--security/selinux/include/netlabel.h3
-rw-r--r--security/selinux/include/objsec.h2
-rw-r--r--security/selinux/include/security.h4
-rw-r--r--security/selinux/netlabel.c10
-rw-r--r--security/selinux/ss/services.c85
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 */
3444static void selinux_skb_extlbl_sid(struct sk_buff *skb, 3444static 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
3827static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb, 3832static 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, 3894static 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
3910out:
3911 return err; 3925 return err;
3912} 3926}
3913 3927
3914static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) 3928static 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);
3951out: 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
3955static int selinux_socket_getpeersec_stream(struct socket *sock, char __user *optval, 3971static 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
4016out: 4032out:
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
4116static void selinux_req_classify_flow(const struct request_sock *req, 4136static 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,
49int selinux_netlbl_skbuff_getsid(struct sk_buff *skb, 49int 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
54void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock); 55void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock);
@@ -89,8 +90,10 @@ static inline void selinux_netlbl_sk_security_clone(
89static inline int selinux_netlbl_skbuff_getsid(struct sk_buff *skb, 90static 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
100int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid); 100int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid);
101 101
102int security_net_peersid_resolve(u32 nlbl_sid, u32 nlbl_type,
103 u32 xfrm_sid,
104 u32 *peer_sid);
105
102int security_get_classes(char ***classes, int *nclasses); 106int security_get_classes(char ***classes, int *nclasses);
103int security_get_permissions(char *class, char ***perms, int *nperms); 107int security_get_permissions(char *class, char ***perms, int *nperms);
104int security_get_reject_unknown(void); 108int 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,
157int selinux_netlbl_skbuff_getsid(struct sk_buff *skb, 157int 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 */
195void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock) 197void 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 */
2077int 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
2128out_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
2057static int get_classes_callback(void *k, void *d, void *args) 2142static int get_classes_callback(void *k, void *d, void *args)
2058{ 2143{
2059 struct class_datum *datum = d; 2144 struct class_datum *datum = d;