aboutsummaryrefslogtreecommitdiffstats
path: root/security/selinux
diff options
context:
space:
mode:
authorPaul Moore <paul.moore@hp.com>2008-01-29 08:38:23 -0500
committerJames Morris <jmorris@namei.org>2008-01-29 16:17:25 -0500
commit220deb966ea51e0dedb6a187c0763120809f3e64 (patch)
tree7d0e5dd8048907c364b4eeff294991937b466c7e /security/selinux
parentf67f4f315f31e7907779adb3296fb6682e755342 (diff)
SELinux: Better integration between peer labeling subsystems
Rework the handling of network peer labels so that the different peer labeling subsystems work better together. This includes moving both subsystems to a single "peer" object class which involves not only changes to the permission checks but an improved method of consolidating multiple packet peer labels. As part of this work the inbound packet permission check code has been heavily modified to handle both the old and new behavior in as sane a fashion as possible. Signed-off-by: Paul Moore <paul.moore@hp.com> Signed-off-by: James Morris <jmorris@namei.org>
Diffstat (limited to 'security/selinux')
-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;