selinux: process labeled IPsec TCP SYN-ACK packets properly in selinux_ip_postroute()
Due to difficulty in arriving at the proper security label for TCP SYN-ACK packets in selinux_ip_postroute(), we need to check packets while/before they are undergoing XFRM transforms instead of waiting until afterwards so that we can determine the correct security label. Reported-by: Janak Desai <Janak.Desai@gtri.gatech.edu> Cc: stable@vger.kernel.org Signed-off-by: Paul Moore <pmoore@redhat.com>
This commit is contained in:
parent
5b67c49324
commit
5c6c26813a
1 changed files with 38 additions and 10 deletions
|
@ -4846,22 +4846,31 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
|
|||
* as fast and as clean as possible. */
|
||||
if (!selinux_policycap_netpeer)
|
||||
return selinux_ip_postroute_compat(skb, ifindex, family);
|
||||
#ifdef CONFIG_XFRM
|
||||
/* If skb->dst->xfrm is non-NULL then the packet is undergoing an IPsec
|
||||
* packet transformation so allow the packet to pass without any checks
|
||||
* since we'll have another chance to perform access control checks
|
||||
* when the packet is on it's final way out.
|
||||
* NOTE: there appear to be some IPv6 multicast cases where skb->dst
|
||||
* is NULL, in this case go ahead and apply access control. */
|
||||
if (skb_dst(skb) != NULL && skb_dst(skb)->xfrm != NULL)
|
||||
return NF_ACCEPT;
|
||||
#endif
|
||||
|
||||
secmark_active = selinux_secmark_enabled();
|
||||
peerlbl_active = selinux_peerlbl_enabled();
|
||||
if (!secmark_active && !peerlbl_active)
|
||||
return NF_ACCEPT;
|
||||
|
||||
sk = skb->sk;
|
||||
|
||||
#ifdef CONFIG_XFRM
|
||||
/* If skb->dst->xfrm is non-NULL then the packet is undergoing an IPsec
|
||||
* packet transformation so allow the packet to pass without any checks
|
||||
* since we'll have another chance to perform access control checks
|
||||
* when the packet is on it's final way out.
|
||||
* NOTE: there appear to be some IPv6 multicast cases where skb->dst
|
||||
* is NULL, in this case go ahead and apply access control.
|
||||
* NOTE: if this is a local socket (skb->sk != NULL) that is in the
|
||||
* TCP listening state we cannot wait until the XFRM processing
|
||||
* is done as we will miss out on the SA label if we do;
|
||||
* unfortunately, this means more work, but it is only once per
|
||||
* connection. */
|
||||
if (skb_dst(skb) != NULL && skb_dst(skb)->xfrm != NULL &&
|
||||
!(sk != NULL && sk->sk_state == TCP_LISTEN))
|
||||
return NF_ACCEPT;
|
||||
#endif
|
||||
|
||||
if (sk == NULL) {
|
||||
/* Without an associated socket the packet is either coming
|
||||
* from the kernel or it is being forwarded; check the packet
|
||||
|
@ -4889,6 +4898,25 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
|
|||
struct sk_security_struct *sksec = sk->sk_security;
|
||||
if (selinux_skb_peerlbl_sid(skb, family, &skb_sid))
|
||||
return NF_DROP;
|
||||
/* At this point, if the returned skb peerlbl is SECSID_NULL
|
||||
* and the packet has been through at least one XFRM
|
||||
* transformation then we must be dealing with the "final"
|
||||
* form of labeled IPsec packet; since we've already applied
|
||||
* all of our access controls on this packet we can safely
|
||||
* pass the packet. */
|
||||
if (skb_sid == SECSID_NULL) {
|
||||
switch (family) {
|
||||
case PF_INET:
|
||||
if (IPCB(skb)->flags & IPSKB_XFRM_TRANSFORMED)
|
||||
return NF_ACCEPT;
|
||||
break;
|
||||
case PF_INET6:
|
||||
if (IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED)
|
||||
return NF_ACCEPT;
|
||||
default:
|
||||
return NF_DROP_ERR(-ECONNREFUSED);
|
||||
}
|
||||
}
|
||||
if (selinux_conn_sid(sksec->sid, skb_sid, &peer_sid))
|
||||
return NF_DROP;
|
||||
secmark_perm = PACKET__SEND;
|
||||
|
|
Loading…
Reference in a new issue