diff options
author | Sabrina Dubroca <sd@queasysnail.net> | 2018-06-30 11:38:55 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2018-07-02 07:34:04 -0400 |
commit | 603d4cf8fe095b1ee78f423d514427be507fb513 (patch) | |
tree | a4051b67f31ba061752f8c5326fa9c6aab528e7f | |
parent | 1236f22fbae15df3736ab4a984c64c0c6ee6254c (diff) |
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>
-rw-r--r-- | drivers/net/geneve.c | 2 | ||||
-rw-r--r-- | drivers/net/vxlan.c | 4 | ||||
-rw-r--r-- | include/linux/netdevice.h | 20 | ||||
-rw-r--r-- | net/8021q/vlan.c | 2 | ||||
-rw-r--r-- | net/ipv4/fou.c | 4 | ||||
-rw-r--r-- | net/ipv4/gre_offload.c | 2 | ||||
-rw-r--r-- | net/ipv4/udp_offload.c | 2 |
7 files changed, 26 insertions, 10 deletions
diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c index 750eaa53bf0c..ada33c2d9ac2 100644 --- a/drivers/net/geneve.c +++ b/drivers/net/geneve.c | |||
@@ -476,7 +476,7 @@ static struct sk_buff **geneve_gro_receive(struct sock *sk, | |||
476 | out_unlock: | 476 | out_unlock: |
477 | rcu_read_unlock(); | 477 | rcu_read_unlock(); |
478 | out: | 478 | out: |
479 | NAPI_GRO_CB(skb)->flush |= flush; | 479 | skb_gro_flush_final(skb, pp, flush); |
480 | 480 | ||
481 | return pp; | 481 | return pp; |
482 | } | 482 | } |
diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index aee0e60471f1..f6bb1d54d4bd 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c | |||
@@ -623,9 +623,7 @@ static struct sk_buff **vxlan_gro_receive(struct sock *sk, | |||
623 | flush = 0; | 623 | flush = 0; |
624 | 624 | ||
625 | out: | 625 | out: |
626 | skb_gro_remcsum_cleanup(skb, &grc); | 626 | skb_gro_flush_final_remcsum(skb, pp, flush, &grc); |
627 | skb->remcsum_offload = 0; | ||
628 | NAPI_GRO_CB(skb)->flush |= flush; | ||
629 | 627 | ||
630 | return pp; | 628 | return pp; |
631 | } | 629 | } |
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 3ec9850c7936..3d0cc0b5cec2 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h | |||
@@ -2789,11 +2789,31 @@ static inline void skb_gro_flush_final(struct sk_buff *skb, struct sk_buff **pp, | |||
2789 | if (PTR_ERR(pp) != -EINPROGRESS) | 2789 | if (PTR_ERR(pp) != -EINPROGRESS) |
2790 | NAPI_GRO_CB(skb)->flush |= flush; | 2790 | NAPI_GRO_CB(skb)->flush |= flush; |
2791 | } | 2791 | } |
2792 | static inline void skb_gro_flush_final_remcsum(struct sk_buff *skb, | ||
2793 | struct sk_buff **pp, | ||
2794 | int flush, | ||
2795 | struct gro_remcsum *grc) | ||
2796 | { | ||
2797 | if (PTR_ERR(pp) != -EINPROGRESS) { | ||
2798 | NAPI_GRO_CB(skb)->flush |= flush; | ||
2799 | skb_gro_remcsum_cleanup(skb, grc); | ||
2800 | skb->remcsum_offload = 0; | ||
2801 | } | ||
2802 | } | ||
2792 | #else | 2803 | #else |
2793 | static inline void skb_gro_flush_final(struct sk_buff *skb, struct sk_buff **pp, int flush) | 2804 | static inline void skb_gro_flush_final(struct sk_buff *skb, struct sk_buff **pp, int flush) |
2794 | { | 2805 | { |
2795 | NAPI_GRO_CB(skb)->flush |= flush; | 2806 | NAPI_GRO_CB(skb)->flush |= flush; |
2796 | } | 2807 | } |
2808 | static inline void skb_gro_flush_final_remcsum(struct sk_buff *skb, | ||
2809 | struct sk_buff **pp, | ||
2810 | int flush, | ||
2811 | struct gro_remcsum *grc) | ||
2812 | { | ||
2813 | NAPI_GRO_CB(skb)->flush |= flush; | ||
2814 | skb_gro_remcsum_cleanup(skb, grc); | ||
2815 | skb->remcsum_offload = 0; | ||
2816 | } | ||
2797 | #endif | 2817 | #endif |
2798 | 2818 | ||
2799 | static inline int dev_hard_header(struct sk_buff *skb, struct net_device *dev, | 2819 | static inline int dev_hard_header(struct sk_buff *skb, struct net_device *dev, |
diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index 73a65789271b..8ccee3d01822 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c | |||
@@ -693,7 +693,7 @@ static struct sk_buff **vlan_gro_receive(struct sk_buff **head, | |||
693 | out_unlock: | 693 | out_unlock: |
694 | rcu_read_unlock(); | 694 | rcu_read_unlock(); |
695 | out: | 695 | out: |
696 | NAPI_GRO_CB(skb)->flush |= flush; | 696 | skb_gro_flush_final(skb, pp, flush); |
697 | 697 | ||
698 | return pp; | 698 | return pp; |
699 | } | 699 | } |
diff --git a/net/ipv4/fou.c b/net/ipv4/fou.c index 1540db65241a..c9ec1603666b 100644 --- a/net/ipv4/fou.c +++ b/net/ipv4/fou.c | |||
@@ -448,9 +448,7 @@ next_proto: | |||
448 | out_unlock: | 448 | out_unlock: |
449 | rcu_read_unlock(); | 449 | rcu_read_unlock(); |
450 | out: | 450 | out: |
451 | NAPI_GRO_CB(skb)->flush |= flush; | 451 | skb_gro_flush_final_remcsum(skb, pp, flush, &grc); |
452 | skb_gro_remcsum_cleanup(skb, &grc); | ||
453 | skb->remcsum_offload = 0; | ||
454 | 452 | ||
455 | return pp; | 453 | return pp; |
456 | } | 454 | } |
diff --git a/net/ipv4/gre_offload.c b/net/ipv4/gre_offload.c index 1859c473b21a..6a7d980105f6 100644 --- a/net/ipv4/gre_offload.c +++ b/net/ipv4/gre_offload.c | |||
@@ -223,7 +223,7 @@ static struct sk_buff **gre_gro_receive(struct sk_buff **head, | |||
223 | out_unlock: | 223 | out_unlock: |
224 | rcu_read_unlock(); | 224 | rcu_read_unlock(); |
225 | out: | 225 | out: |
226 | NAPI_GRO_CB(skb)->flush |= flush; | 226 | skb_gro_flush_final(skb, pp, flush); |
227 | 227 | ||
228 | return pp; | 228 | return pp; |
229 | } | 229 | } |
diff --git a/net/ipv4/udp_offload.c b/net/ipv4/udp_offload.c index 92dc9e5a7ff3..69c54540d5b4 100644 --- a/net/ipv4/udp_offload.c +++ b/net/ipv4/udp_offload.c | |||
@@ -394,7 +394,7 @@ unflush: | |||
394 | out_unlock: | 394 | out_unlock: |
395 | rcu_read_unlock(); | 395 | rcu_read_unlock(); |
396 | out: | 396 | out: |
397 | NAPI_GRO_CB(skb)->flush |= flush; | 397 | skb_gro_flush_final(skb, pp, flush); |
398 | return pp; | 398 | return pp; |
399 | } | 399 | } |
400 | EXPORT_SYMBOL(udp_gro_receive); | 400 | EXPORT_SYMBOL(udp_gro_receive); |