aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Dumazet <edumazet@google.com>2013-06-24 09:26:00 -0400
committerDavid S. Miller <davem@davemloft.net>2013-06-25 19:07:44 -0400
commitbd8a7036c06cf15779b31a5397d4afcb12be81ea (patch)
treed78794e12fb4ac0005f019e6a51e797230d38970
parent2b7a5db060f5e7d7f79bc45f818e08b8f244a3b8 (diff)
gre: fix a possible skb leak
commit 68c331631143 ("v4 GRE: Add TCP segmentation offload for GRE") added a possible skb leak, because it frees only the head of segment list, in case a skb_linearize() call fails. This patch adds a kfree_skb_list() helper to fix the bug. Signed-off-by: Eric Dumazet <edumazet@google.com> Cc: Pravin B Shelar <pshelar@nicira.com> Cc: Daniel Borkmann <dborkman@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/linux/skbuff.h1
-rw-r--r--net/core/skbuff.c20
-rw-r--r--net/ipv4/gre.c2
3 files changed, 14 insertions, 9 deletions
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 9c676eae3968..dec1748cd002 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -627,6 +627,7 @@ static inline struct rtable *skb_rtable(const struct sk_buff *skb)
627} 627}
628 628
629extern void kfree_skb(struct sk_buff *skb); 629extern void kfree_skb(struct sk_buff *skb);
630extern void kfree_skb_list(struct sk_buff *segs);
630extern void skb_tx_error(struct sk_buff *skb); 631extern void skb_tx_error(struct sk_buff *skb);
631extern void consume_skb(struct sk_buff *skb); 632extern void consume_skb(struct sk_buff *skb);
632extern void __kfree_skb(struct sk_buff *skb); 633extern void __kfree_skb(struct sk_buff *skb);
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index cfd777bd6bd0..1c1738cc4538 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -483,15 +483,8 @@ EXPORT_SYMBOL(skb_add_rx_frag);
483 483
484static void skb_drop_list(struct sk_buff **listp) 484static void skb_drop_list(struct sk_buff **listp)
485{ 485{
486 struct sk_buff *list = *listp; 486 kfree_skb_list(*listp);
487
488 *listp = NULL; 487 *listp = NULL;
489
490 do {
491 struct sk_buff *this = list;
492 list = list->next;
493 kfree_skb(this);
494 } while (list);
495} 488}
496 489
497static inline void skb_drop_fraglist(struct sk_buff *skb) 490static inline void skb_drop_fraglist(struct sk_buff *skb)
@@ -651,6 +644,17 @@ void kfree_skb(struct sk_buff *skb)
651} 644}
652EXPORT_SYMBOL(kfree_skb); 645EXPORT_SYMBOL(kfree_skb);
653 646
647void kfree_skb_list(struct sk_buff *segs)
648{
649 while (segs) {
650 struct sk_buff *next = segs->next;
651
652 kfree_skb(segs);
653 segs = next;
654 }
655}
656EXPORT_SYMBOL(kfree_skb_list);
657
654/** 658/**
655 * skb_tx_error - report an sk_buff xmit error 659 * skb_tx_error - report an sk_buff xmit error
656 * @skb: buffer that triggered an error 660 * @skb: buffer that triggered an error
diff --git a/net/ipv4/gre.c b/net/ipv4/gre.c
index b2e805af9b87..7856d1651d05 100644
--- a/net/ipv4/gre.c
+++ b/net/ipv4/gre.c
@@ -178,7 +178,7 @@ static struct sk_buff *gre_gso_segment(struct sk_buff *skb,
178 178
179 err = __skb_linearize(skb); 179 err = __skb_linearize(skb);
180 if (err) { 180 if (err) {
181 kfree_skb(segs); 181 kfree_skb_list(segs);
182 segs = ERR_PTR(err); 182 segs = ERR_PTR(err);
183 goto out; 183 goto out;
184 } 184 }