summary refs log tree commit diff
diff options
context:
space:
mode:
authorPaolo Abeni <pabeni@redhat.com>2019-02-21 17:43:59 +0100
committerDavid S. Miller <davem@davemloft.net>2019-02-22 16:05:11 -0800
commit424a7cd078401591fc45587ffb2c012d7f402fb7 (patch)
tree346f6616db687c22ad228fb260b4e6e47053e9e3
parent5de362df44d71fc8f6b153ae4eaa2a1284c84490 (diff)
downloadlinux-424a7cd078401591fc45587ffb2c012d7f402fb7.tar.gz
udpv6: fix possible user after free in error handler
Before derefencing the encap pointer, commit e7cc082455cb ("udp: Support
for error handlers of tunnels with arbitrary destination port") checks
for a NULL value, but the two fetch operation can race with removal.
Fix the above using a single access.
Also fix a couple of type annotations, to make sparse happy.

Fixes: e7cc082455cb ("udp: Support for error handlers of tunnels with arbitrary destination port")
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Acked-by: Stefano Brivio <sbrivio@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--net/ipv6/udp.c10
1 files changed, 6 insertions, 4 deletions
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index e6c52c27f354..b444483cdb2b 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -420,17 +420,19 @@ EXPORT_SYMBOL(udpv6_encap_enable);
  */
 static int __udp6_lib_err_encap_no_sk(struct sk_buff *skb,
 				      struct inet6_skb_parm *opt,
-				      u8 type, u8 code, int offset, u32 info)
+				      u8 type, u8 code, int offset, __be32 info)
 {
 	int i;
 
 	for (i = 0; i < MAX_IPTUN_ENCAP_OPS; i++) {
 		int (*handler)(struct sk_buff *skb, struct inet6_skb_parm *opt,
-			       u8 type, u8 code, int offset, u32 info);
+			       u8 type, u8 code, int offset, __be32 info);
+		const struct ip6_tnl_encap_ops *encap;
 
-		if (!ip6tun_encaps[i])
+		encap = rcu_dereference(ip6tun_encaps[i]);
+		if (!encap)
 			continue;
-		handler = rcu_dereference(ip6tun_encaps[i]->err_handler);
+		handler = encap->err_handler;
 		if (handler && !handler(skb, opt, type, code, offset, info))
 			return 0;
 	}