Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c0828e50 authored by Paul Moore's avatar Paul Moore
Browse files

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: default avatarJanak Desai <Janak.Desai@gtri.gatech.edu>
Cc: stable@vger.kernel.org
Signed-off-by: default avatarPaul Moore <pmoore@redhat.com>
parent 817eff71
Loading
Loading
Loading
Loading
+35 −7
Original line number Diff line number Diff line
@@ -4850,22 +4850,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);

	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. */
	if (skb_dst(skb) != NULL && skb_dst(skb)->xfrm != NULL)
	 *       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
	secmark_active = selinux_secmark_enabled();
	peerlbl_active = selinux_peerlbl_enabled();
	if (!secmark_active && !peerlbl_active)
		return NF_ACCEPT;

	sk = skb->sk;
	if (sk == NULL) {
		/* Without an associated socket the packet is either coming
		 * from the kernel or it is being forwarded; check the packet
@@ -4893,6 +4902,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;