diff options
author | Paul Moore <pmoore@redhat.com> | 2013-12-10 14:58:01 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2014-01-09 15:24:24 -0500 |
commit | 0fdb9385a5909c218fa2cf0cf62896ebe0fcf30e (patch) | |
tree | 7cfeda1086e30884e1a5ffe6c2a44084eac5c5aa | |
parent | 070357081f37bb70ff1a09630c50529188846280 (diff) |
selinux: process labeled IPsec TCP SYN-ACK packets properly in selinux_ip_postroute()
commit c0828e50485932b7e019df377a6b0a8d1ebd3080 upstream.
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>
Signed-off-by: Paul Moore <pmoore@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r-- | security/selinux/hooks.c | 43 |
1 files changed, 36 insertions, 7 deletions
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index ec39490ec8fd..57f14185cf18 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
@@ -4742,22 +4742,32 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex, | |||
4742 | * as fast and as clean as possible. */ | 4742 | * as fast and as clean as possible. */ |
4743 | if (!selinux_policycap_netpeer) | 4743 | if (!selinux_policycap_netpeer) |
4744 | return selinux_ip_postroute_compat(skb, ifindex, family); | 4744 | return selinux_ip_postroute_compat(skb, ifindex, family); |
4745 | |||
4746 | secmark_active = selinux_secmark_enabled(); | ||
4747 | peerlbl_active = netlbl_enabled() || selinux_xfrm_enabled(); | ||
4748 | if (!secmark_active && !peerlbl_active) | ||
4749 | return NF_ACCEPT; | ||
4750 | |||
4751 | sk = skb->sk; | ||
4752 | |||
4745 | #ifdef CONFIG_XFRM | 4753 | #ifdef CONFIG_XFRM |
4746 | /* If skb->dst->xfrm is non-NULL then the packet is undergoing an IPsec | 4754 | /* If skb->dst->xfrm is non-NULL then the packet is undergoing an IPsec |
4747 | * packet transformation so allow the packet to pass without any checks | 4755 | * packet transformation so allow the packet to pass without any checks |
4748 | * since we'll have another chance to perform access control checks | 4756 | * since we'll have another chance to perform access control checks |
4749 | * when the packet is on it's final way out. | 4757 | * when the packet is on it's final way out. |
4750 | * NOTE: there appear to be some IPv6 multicast cases where skb->dst | 4758 | * NOTE: there appear to be some IPv6 multicast cases where skb->dst |
4751 | * is NULL, in this case go ahead and apply access control. */ | 4759 | * is NULL, in this case go ahead and apply access control. |
4752 | if (skb_dst(skb) != NULL && skb_dst(skb)->xfrm != NULL) | 4760 | * is NULL, in this case go ahead and apply access control. |
4761 | * NOTE: if this is a local socket (skb->sk != NULL) that is in the | ||
4762 | * TCP listening state we cannot wait until the XFRM processing | ||
4763 | * is done as we will miss out on the SA label if we do; | ||
4764 | * unfortunately, this means more work, but it is only once per | ||
4765 | * connection. */ | ||
4766 | if (skb_dst(skb) != NULL && skb_dst(skb)->xfrm != NULL && | ||
4767 | !(sk != NULL && sk->sk_state == TCP_LISTEN)) | ||
4753 | return NF_ACCEPT; | 4768 | return NF_ACCEPT; |
4754 | #endif | 4769 | #endif |
4755 | secmark_active = selinux_secmark_enabled(); | ||
4756 | peerlbl_active = netlbl_enabled() || selinux_xfrm_enabled(); | ||
4757 | if (!secmark_active && !peerlbl_active) | ||
4758 | return NF_ACCEPT; | ||
4759 | 4770 | ||
4760 | sk = skb->sk; | ||
4761 | if (sk == NULL) { | 4771 | if (sk == NULL) { |
4762 | /* Without an associated socket the packet is either coming | 4772 | /* Without an associated socket the packet is either coming |
4763 | * from the kernel or it is being forwarded; check the packet | 4773 | * from the kernel or it is being forwarded; check the packet |
@@ -4785,6 +4795,25 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex, | |||
4785 | struct sk_security_struct *sksec = sk->sk_security; | 4795 | struct sk_security_struct *sksec = sk->sk_security; |
4786 | if (selinux_skb_peerlbl_sid(skb, family, &skb_sid)) | 4796 | if (selinux_skb_peerlbl_sid(skb, family, &skb_sid)) |
4787 | return NF_DROP; | 4797 | return NF_DROP; |
4798 | /* At this point, if the returned skb peerlbl is SECSID_NULL | ||
4799 | * and the packet has been through at least one XFRM | ||
4800 | * transformation then we must be dealing with the "final" | ||
4801 | * form of labeled IPsec packet; since we've already applied | ||
4802 | * all of our access controls on this packet we can safely | ||
4803 | * pass the packet. */ | ||
4804 | if (skb_sid == SECSID_NULL) { | ||
4805 | switch (family) { | ||
4806 | case PF_INET: | ||
4807 | if (IPCB(skb)->flags & IPSKB_XFRM_TRANSFORMED) | ||
4808 | return NF_ACCEPT; | ||
4809 | break; | ||
4810 | case PF_INET6: | ||
4811 | if (IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) | ||
4812 | return NF_ACCEPT; | ||
4813 | default: | ||
4814 | return NF_DROP_ERR(-ECONNREFUSED); | ||
4815 | } | ||
4816 | } | ||
4788 | if (selinux_conn_sid(sksec->sid, skb_sid, &peer_sid)) | 4817 | if (selinux_conn_sid(sksec->sid, skb_sid, &peer_sid)) |
4789 | return NF_DROP; | 4818 | return NF_DROP; |
4790 | secmark_perm = PACKET__SEND; | 4819 | secmark_perm = PACKET__SEND; |