diff options
author | Paul Moore <paul.moore@hp.com> | 2008-01-29 08:38:23 -0500 |
---|---|---|
committer | James Morris <jmorris@namei.org> | 2008-01-29 16:17:25 -0500 |
commit | 220deb966ea51e0dedb6a187c0763120809f3e64 (patch) | |
tree | 7d0e5dd8048907c364b4eeff294991937b466c7e /security/selinux | |
parent | f67f4f315f31e7907779adb3296fb6682e755342 (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.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; |