From 212cd0895330b775f2db49451f046a5ca4e5704b Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 5 Nov 2015 13:39:24 -0800 Subject: selinux: fix random read in selinux_ip_postroute_compat() In commit e446f9dfe17b ("net: synack packets can be attached to request sockets"), I missed one remaining case of invalid skb->sk->sk_security access. Dmitry Vyukov got a KASan report pointing to it. Add selinux_skb_sk() helper that is responsible to get back to the listener if skb is attached to a request socket, instead of duplicating the logic. Fixes: ca6fb0651883 ("tcp: attach SYNACK messages to request sockets instead of listener") Signed-off-by: Eric Dumazet Reported-by: Dmitry Vyukov Cc: Paul Moore Signed-off-by: David S. Miller --- security/selinux/hooks.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) (limited to 'security') diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 26f4039..c9b2d54 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -4931,11 +4931,23 @@ static unsigned int selinux_ipv4_output(void *priv, return selinux_ip_output(skb, PF_INET); } +/* SYNACK messages might be attached to request sockets. + * To get back to sk_security, we need to look at the listener. + */ +static struct sock *selinux_skb_sk(const struct sk_buff *skb) +{ + struct sock *sk = skb->sk; + + if (sk && sk->sk_state == TCP_NEW_SYN_RECV) + sk = inet_reqsk(sk)->rsk_listener; + return sk; +} + static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb, int ifindex, u16 family) { - struct sock *sk = skb->sk; + struct sock *sk = selinux_skb_sk(skb); struct sk_security_struct *sksec; struct common_audit_data ad; struct lsm_network_audit net = {0,}; @@ -4990,7 +5002,7 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, if (!secmark_active && !peerlbl_active) return NF_ACCEPT; - sk = skb->sk; + sk = selinux_skb_sk(skb); #ifdef CONFIG_XFRM /* If skb->dst->xfrm is non-NULL then the packet is undergoing an IPsec @@ -5035,8 +5047,6 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, u32 skb_sid; struct sk_security_struct *sksec; - if (sk->sk_state == TCP_NEW_SYN_RECV) - sk = inet_reqsk(sk)->rsk_listener; sksec = sk->sk_security; if (selinux_skb_peerlbl_sid(skb, family, &skb_sid)) return NF_DROP; -- cgit v1.1 From 54abc686c2d111e98228943a7e1e51cc256e35d9 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sun, 8 Nov 2015 10:54:07 -0800 Subject: net: add skb_to_full_sk() helper and use it in selinux_netlbl_skbuff_setsid() Generalize selinux_skb_sk() added in commit 212cd0895330 ("selinux: fix random read in selinux_ip_postroute_compat()") so that we can use it other contexts. Use it right away in selinux_netlbl_skbuff_setsid() Fixes: ca6fb0651883 ("tcp: attach SYNACK messages to request sockets instead of listener") Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- security/selinux/hooks.c | 16 ++-------------- security/selinux/netlabel.c | 2 +- 2 files changed, 3 insertions(+), 15 deletions(-) (limited to 'security') diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index c9b2d54..23307da 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -4931,23 +4931,11 @@ static unsigned int selinux_ipv4_output(void *priv, return selinux_ip_output(skb, PF_INET); } -/* SYNACK messages might be attached to request sockets. - * To get back to sk_security, we need to look at the listener. - */ -static struct sock *selinux_skb_sk(const struct sk_buff *skb) -{ - struct sock *sk = skb->sk; - - if (sk && sk->sk_state == TCP_NEW_SYN_RECV) - sk = inet_reqsk(sk)->rsk_listener; - return sk; -} - static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb, int ifindex, u16 family) { - struct sock *sk = selinux_skb_sk(skb); + struct sock *sk = skb_to_full_sk(skb); struct sk_security_struct *sksec; struct common_audit_data ad; struct lsm_network_audit net = {0,}; @@ -5002,7 +4990,7 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, if (!secmark_active && !peerlbl_active) return NF_ACCEPT; - sk = selinux_skb_sk(skb); + sk = skb_to_full_sk(skb); #ifdef CONFIG_XFRM /* If skb->dst->xfrm is non-NULL then the packet is undergoing an IPsec diff --git a/security/selinux/netlabel.c b/security/selinux/netlabel.c index 0364120..1f989a5 100644 --- a/security/selinux/netlabel.c +++ b/security/selinux/netlabel.c @@ -245,7 +245,7 @@ int selinux_netlbl_skbuff_setsid(struct sk_buff *skb, /* if this is a locally generated packet check to see if it is already * being labeled by it's parent socket, if it is just exit */ - sk = skb->sk; + sk = skb_to_full_sk(skb); if (sk != NULL) { struct sk_security_struct *sksec = sk->sk_security; if (sksec->nlbl_state != NLBL_REQSKB) -- cgit v1.1 From 8827d90e29e664aa959817467a3da72041ca2269 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sun, 8 Nov 2015 10:54:08 -0800 Subject: smack: use skb_to_full_sk() helper This module wants to access sk->sk_security, which is not available for request sockets. Fixes: ca6fb0651883 ("tcp: attach SYNACK messages to request sockets instead of listener") Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- security/smack/smack_netfilter.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'security') diff --git a/security/smack/smack_netfilter.c b/security/smack/smack_netfilter.c index 6d1706c..aa6bf1b 100644 --- a/security/smack/smack_netfilter.c +++ b/security/smack/smack_netfilter.c @@ -17,6 +17,7 @@ #include #include #include +#include #include "smack.h" #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) @@ -25,11 +26,12 @@ static unsigned int smack_ipv6_output(void *priv, struct sk_buff *skb, const struct nf_hook_state *state) { + struct sock *sk = skb_to_full_sk(skb); struct socket_smack *ssp; struct smack_known *skp; - if (skb && skb->sk && skb->sk->sk_security) { - ssp = skb->sk->sk_security; + if (sk && sk->sk_security) { + ssp = sk->sk_security; skp = ssp->smk_out; skb->secmark = skp->smk_secid; } @@ -42,11 +44,12 @@ static unsigned int smack_ipv4_output(void *priv, struct sk_buff *skb, const struct nf_hook_state *state) { + struct sock *sk = skb_to_full_sk(skb); struct socket_smack *ssp; struct smack_known *skp; - if (skb && skb->sk && skb->sk->sk_security) { - ssp = skb->sk->sk_security; + if (sk && sk->sk_security) { + ssp = sk->sk_security; skp = ssp->smk_out; skb->secmark = skp->smk_secid; } -- cgit v1.1