aboutsummaryrefslogtreecommitdiffstats
path: root/security/selinux/hooks.c
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/hooks.c
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/hooks.c')
-rw-r--r--security/selinux/hooks.c204
1 files changed, 112 insertions, 92 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,