Browse Source

net: fix use-after-free in GRO with ESP

Since the addition of GRO for ESP, gro_receive can consume the skb and
return -EINPROGRESS. In that case, the lower layer GRO handler cannot
touch the skb anymore.

Commit 5f114163f2f5 ("net: Add a skb_gro_flush_final helper.") converted
some of the gro_receive handlers that can lead to ESP's gro_receive so
that they wouldn't access the skb when -EINPROGRESS is returned, but
missed other spots, mainly in tunneling protocols.

This patch finishes the conversion to using skb_gro_flush_final(), and
adds a new helper, skb_gro_flush_final_remcsum(), used in VXLAN and
GUE.

Fixes: 5f114163f2f5 ("net: Add a skb_gro_flush_final helper.")
Signed-off-by: Sabrina Dubroca <sd@queasysnail.net>
Reviewed-by: Stefano Brivio <sbrivio@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Sabrina Dubroca 7 years ago
parent
commit
603d4cf8fe
7 changed files with 26 additions and 10 deletions
  1. 1 1
      drivers/net/geneve.c
  2. 1 3
      drivers/net/vxlan.c
  3. 20 0
      include/linux/netdevice.h
  4. 1 1
      net/8021q/vlan.c
  5. 1 3
      net/ipv4/fou.c
  6. 1 1
      net/ipv4/gre_offload.c
  7. 1 1
      net/ipv4/udp_offload.c

+ 1 - 1
drivers/net/geneve.c

@@ -476,7 +476,7 @@ static struct sk_buff **geneve_gro_receive(struct sock *sk,
 out_unlock:
 out_unlock:
 	rcu_read_unlock();
 	rcu_read_unlock();
 out:
 out:
-	NAPI_GRO_CB(skb)->flush |= flush;
+	skb_gro_flush_final(skb, pp, flush);
 
 
 	return pp;
 	return pp;
 }
 }

+ 1 - 3
drivers/net/vxlan.c

@@ -623,9 +623,7 @@ static struct sk_buff **vxlan_gro_receive(struct sock *sk,
 	flush = 0;
 	flush = 0;
 
 
 out:
 out:
-	skb_gro_remcsum_cleanup(skb, &grc);
-	skb->remcsum_offload = 0;
-	NAPI_GRO_CB(skb)->flush |= flush;
+	skb_gro_flush_final_remcsum(skb, pp, flush, &grc);
 
 
 	return pp;
 	return pp;
 }
 }

+ 20 - 0
include/linux/netdevice.h

@@ -2789,11 +2789,31 @@ static inline void skb_gro_flush_final(struct sk_buff *skb, struct sk_buff **pp,
 	if (PTR_ERR(pp) != -EINPROGRESS)
 	if (PTR_ERR(pp) != -EINPROGRESS)
 		NAPI_GRO_CB(skb)->flush |= flush;
 		NAPI_GRO_CB(skb)->flush |= flush;
 }
 }
+static inline void skb_gro_flush_final_remcsum(struct sk_buff *skb,
+					       struct sk_buff **pp,
+					       int flush,
+					       struct gro_remcsum *grc)
+{
+	if (PTR_ERR(pp) != -EINPROGRESS) {
+		NAPI_GRO_CB(skb)->flush |= flush;
+		skb_gro_remcsum_cleanup(skb, grc);
+		skb->remcsum_offload = 0;
+	}
+}
 #else
 #else
 static inline void skb_gro_flush_final(struct sk_buff *skb, struct sk_buff **pp, int flush)
 static inline void skb_gro_flush_final(struct sk_buff *skb, struct sk_buff **pp, int flush)
 {
 {
 	NAPI_GRO_CB(skb)->flush |= flush;
 	NAPI_GRO_CB(skb)->flush |= flush;
 }
 }
+static inline void skb_gro_flush_final_remcsum(struct sk_buff *skb,
+					       struct sk_buff **pp,
+					       int flush,
+					       struct gro_remcsum *grc)
+{
+	NAPI_GRO_CB(skb)->flush |= flush;
+	skb_gro_remcsum_cleanup(skb, grc);
+	skb->remcsum_offload = 0;
+}
 #endif
 #endif
 
 
 static inline int dev_hard_header(struct sk_buff *skb, struct net_device *dev,
 static inline int dev_hard_header(struct sk_buff *skb, struct net_device *dev,

+ 1 - 1
net/8021q/vlan.c

@@ -693,7 +693,7 @@ static struct sk_buff **vlan_gro_receive(struct sk_buff **head,
 out_unlock:
 out_unlock:
 	rcu_read_unlock();
 	rcu_read_unlock();
 out:
 out:
-	NAPI_GRO_CB(skb)->flush |= flush;
+	skb_gro_flush_final(skb, pp, flush);
 
 
 	return pp;
 	return pp;
 }
 }

+ 1 - 3
net/ipv4/fou.c

@@ -448,9 +448,7 @@ next_proto:
 out_unlock:
 out_unlock:
 	rcu_read_unlock();
 	rcu_read_unlock();
 out:
 out:
-	NAPI_GRO_CB(skb)->flush |= flush;
-	skb_gro_remcsum_cleanup(skb, &grc);
-	skb->remcsum_offload = 0;
+	skb_gro_flush_final_remcsum(skb, pp, flush, &grc);
 
 
 	return pp;
 	return pp;
 }
 }

+ 1 - 1
net/ipv4/gre_offload.c

@@ -223,7 +223,7 @@ static struct sk_buff **gre_gro_receive(struct sk_buff **head,
 out_unlock:
 out_unlock:
 	rcu_read_unlock();
 	rcu_read_unlock();
 out:
 out:
-	NAPI_GRO_CB(skb)->flush |= flush;
+	skb_gro_flush_final(skb, pp, flush);
 
 
 	return pp;
 	return pp;
 }
 }

+ 1 - 1
net/ipv4/udp_offload.c

@@ -394,7 +394,7 @@ unflush:
 out_unlock:
 out_unlock:
 	rcu_read_unlock();
 	rcu_read_unlock();
 out:
 out:
-	NAPI_GRO_CB(skb)->flush |= flush;
+	skb_gro_flush_final(skb, pp, flush);
 	return pp;
 	return pp;
 }
 }
 EXPORT_SYMBOL(udp_gro_receive);
 EXPORT_SYMBOL(udp_gro_receive);