From: Greg KH <gregkh@suse.de>
To: linux-kernel@vger.kernel.org, stable@kernel.org
Cc: Justin Forbes <jmforbes@linuxtx.org>,
Zwane Mwaikambo <zwane@arm.linux.org.uk>,
"Theodore Ts'o" <tytso@mit.edu>,
Randy Dunlap <rdunlap@xenotime.net>,
Dave Jones <davej@redhat.com>,
Chuck Wolber <chuckw@quantumlinux.com>,
Chris Wedgwood <reviews@ml.cw.f00f.org>,
torvalds@osdl.org, akpm@osdl.org, alan@lxorguk.ukuu.org.uk,
netdev@vger.kernel.org, David Miller <davem@davemloft.net>,
Herbert Xu <herbert@gondor.apana.org.au>,
Greg Kroah-Hartman <gregkh@suse.de>
Subject: [patch 09/23] : Update frag_list in pskb_trim
Date: Thu, 3 Aug 2006 22:39:20 -0700 [thread overview]
Message-ID: <20060804053920.GJ769@kroah.com> (raw)
In-Reply-To: <20060804053807.GA769@kroah.com>
[-- Attachment #1: update-frag_list-in-pskb_trim.patch --]
[-- Type: text/plain, Size: 6091 bytes --]
-stable review patch. If anyone has any objections, please let us know.
------------------
From: Herbert Xu <herbert@gondor.apana.org.au>
[NET]: Update frag_list in pskb_trim
When pskb_trim has to defer to ___pksb_trim to trim the frag_list part of
the packet, the frag_list is not updated to reflect the trimming. This
will usually work fine until you hit something that uses the packet length
or tail from the frag_list.
Examples include esp_output and ip_fragment.
Another problem caused by this is that you can end up with a linear packet
with a frag_list attached.
It is possible to get away with this if we audit everything to make sure
that they always consult skb->len before going down onto frag_list. In
fact we can do the samething for the paged part as well to avoid copying
the data area of the skb. For now though, let's do the conservative fix
and update frag_list.
Many thanks to Marco Berizzi for helping me to track down this bug.
This 4-year old bug took 3 months to track down. Marco was very patient
indeed :)
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
include/linux/skbuff.h | 24 +++++------
net/core/skbuff.c | 106 ++++++++++++++++++++++++++++++++++---------------
2 files changed, 86 insertions(+), 44 deletions(-)
--- linux-2.6.17.7.orig/include/linux/skbuff.h
+++ linux-2.6.17.7/include/linux/skbuff.h
@@ -967,15 +967,16 @@ static inline void skb_reserve(struct sk
#define NET_SKB_PAD 16
#endif
-extern int ___pskb_trim(struct sk_buff *skb, unsigned int len, int realloc);
+extern int ___pskb_trim(struct sk_buff *skb, unsigned int len);
static inline void __skb_trim(struct sk_buff *skb, unsigned int len)
{
- if (!skb->data_len) {
- skb->len = len;
- skb->tail = skb->data + len;
- } else
- ___pskb_trim(skb, len, 0);
+ if (unlikely(skb->data_len)) {
+ WARN_ON(1);
+ return;
+ }
+ skb->len = len;
+ skb->tail = skb->data + len;
}
/**
@@ -985,6 +986,7 @@ static inline void __skb_trim(struct sk_
*
* Cut the length of a buffer down by removing data from the tail. If
* the buffer is already under the length specified it is not modified.
+ * The skb must be linear.
*/
static inline void skb_trim(struct sk_buff *skb, unsigned int len)
{
@@ -995,12 +997,10 @@ static inline void skb_trim(struct sk_bu
static inline int __pskb_trim(struct sk_buff *skb, unsigned int len)
{
- if (!skb->data_len) {
- skb->len = len;
- skb->tail = skb->data+len;
- return 0;
- }
- return ___pskb_trim(skb, len, 1);
+ if (skb->data_len)
+ return ___pskb_trim(skb, len);
+ __skb_trim(skb, len);
+ return 0;
}
static inline int pskb_trim(struct sk_buff *skb, unsigned int len)
--- linux-2.6.17.7.orig/net/core/skbuff.c
+++ linux-2.6.17.7/net/core/skbuff.c
@@ -251,11 +251,11 @@ nodata:
}
-static void skb_drop_fraglist(struct sk_buff *skb)
+static void skb_drop_list(struct sk_buff **listp)
{
- struct sk_buff *list = skb_shinfo(skb)->frag_list;
+ struct sk_buff *list = *listp;
- skb_shinfo(skb)->frag_list = NULL;
+ *listp = NULL;
do {
struct sk_buff *this = list;
@@ -264,6 +264,11 @@ static void skb_drop_fraglist(struct sk_
} while (list);
}
+static inline void skb_drop_fraglist(struct sk_buff *skb)
+{
+ skb_drop_list(&skb_shinfo(skb)->frag_list);
+}
+
static void skb_clone_fraglist(struct sk_buff *skb)
{
struct sk_buff *list;
@@ -802,49 +807,86 @@ struct sk_buff *skb_pad(struct sk_buff *
return nskb;
}
-/* Trims skb to length len. It can change skb pointers, if "realloc" is 1.
- * If realloc==0 and trimming is impossible without change of data,
- * it is BUG().
+/* Trims skb to length len. It can change skb pointers.
*/
-int ___pskb_trim(struct sk_buff *skb, unsigned int len, int realloc)
+int ___pskb_trim(struct sk_buff *skb, unsigned int len)
{
+ struct sk_buff **fragp;
+ struct sk_buff *frag;
int offset = skb_headlen(skb);
int nfrags = skb_shinfo(skb)->nr_frags;
int i;
+ int err;
- for (i = 0; i < nfrags; i++) {
+ if (skb_cloned(skb) &&
+ unlikely((err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC))))
+ return err;
+
+ i = 0;
+ if (offset >= len)
+ goto drop_pages;
+
+ for (; i < nfrags; i++) {
int end = offset + skb_shinfo(skb)->frags[i].size;
- if (end > len) {
- if (skb_cloned(skb)) {
- BUG_ON(!realloc);
- if (pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
- return -ENOMEM;
- }
- if (len <= offset) {
- put_page(skb_shinfo(skb)->frags[i].page);
- skb_shinfo(skb)->nr_frags--;
- } else {
- skb_shinfo(skb)->frags[i].size = len - offset;
- }
+
+ if (end < len) {
+ offset = end;
+ continue;
+ }
+
+ skb_shinfo(skb)->frags[i++].size = len - offset;
+
+drop_pages:
+ skb_shinfo(skb)->nr_frags = i;
+
+ for (; i < nfrags; i++)
+ put_page(skb_shinfo(skb)->frags[i].page);
+
+ if (skb_shinfo(skb)->frag_list)
+ skb_drop_fraglist(skb);
+ goto done;
+ }
+
+ for (fragp = &skb_shinfo(skb)->frag_list; (frag = *fragp);
+ fragp = &frag->next) {
+ int end = offset + frag->len;
+
+ if (skb_shared(frag)) {
+ struct sk_buff *nfrag;
+
+ nfrag = skb_clone(frag, GFP_ATOMIC);
+ if (unlikely(!nfrag))
+ return -ENOMEM;
+
+ nfrag->next = frag->next;
+ kfree_skb(frag);
+ frag = nfrag;
+ *fragp = frag;
}
- offset = end;
+
+ if (end < len) {
+ offset = end;
+ continue;
+ }
+
+ if (end > len &&
+ unlikely((err = pskb_trim(frag, len - offset))))
+ return err;
+
+ if (frag->next)
+ skb_drop_list(&frag->next);
+ break;
}
- if (offset < len) {
+done:
+ if (len > skb_headlen(skb)) {
skb->data_len -= skb->len - len;
skb->len = len;
} else {
- if (len <= skb_headlen(skb)) {
- skb->len = len;
- skb->data_len = 0;
- skb->tail = skb->data + len;
- if (skb_shinfo(skb)->frag_list && !skb_cloned(skb))
- skb_drop_fraglist(skb);
- } else {
- skb->data_len -= skb->len - len;
- skb->len = len;
- }
+ skb->len = len;
+ skb->data_len = 0;
+ skb->tail = skb->data + len;
}
return 0;
--
next prev parent reply other threads:[~2006-08-04 5:44 UTC|newest]
Thread overview: 49+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <20060804053258.391158155@quad.kroah.org>
2006-08-04 5:38 ` [patch 00/23] -stable review Greg KH
2006-08-04 5:38 ` [patch 01/23] PCI: fix issues with extended conf space when MMCONFIG disabled because of e820 Greg KH
2006-08-04 5:38 ` [patch 02/23] Dont allow chmod() on the /proc/<pid>/ files Greg KH
2006-08-04 5:38 ` [patch 03/23] : H.323 helper: fix possible NULL-ptr dereference Greg KH
2006-08-04 5:38 ` [patch 04/23] scx200_acb: Fix the state machine Greg KH
2006-08-04 5:38 ` [patch 05/23] scx200_acb: Fix the block transactions Greg KH
2006-08-04 5:38 ` [patch 06/23] i2c: Fix ignore module parameter handling in i2c-core Greg KH
2006-08-04 5:39 ` [patch 07/23] sky2: NAPI bug Greg KH
2006-08-04 5:39 ` [patch 08/23] UHCI: Fix handling of short last packet Greg KH
2006-08-04 5:39 ` Greg KH [this message]
2006-08-04 5:39 ` [patch 10/23] VLAN state handling fix Greg KH
2006-08-04 5:39 ` [patch 11/23] Sparc64 quad-float emulation fix Greg KH
2006-08-04 5:39 ` [patch 12/23] invalidate_bdev() speedup Greg KH
2006-08-04 8:50 ` Christoph Hellwig
2006-08-04 9:04 ` Andrew Morton
2006-08-04 13:08 ` Arjan van de Ven
2006-08-04 13:25 ` Jes Sorensen
2006-08-04 15:18 ` Andrew Morton
2006-08-04 5:39 ` [patch 13/23] ieee1394: sbp2: enable auto spin-up for Maxtor disks Greg KH
2006-08-04 5:39 ` [patch 14/23] Fix race related problem when adding items to and svcrpc auth cache Greg KH
2006-08-04 5:39 ` Greg KH
2006-08-04 5:40 ` [patch 15/23] ext3 -nobh option causes oops Greg KH
2006-11-16 22:51 ` Adrian Bunk
2006-11-16 23:07 ` Badari Pulavarty
2006-11-17 16:47 ` Adrian Bunk
2006-08-04 5:40 ` [patch 16/23] ext3: avoid triggering ext3_error on bad NFS file handle Greg KH
2006-08-04 14:45 ` Eric Sandeen
2006-08-04 14:52 ` Christoph Hellwig
2006-08-04 15:35 ` Eric Sandeen
2006-08-05 1:28 ` Theodore Tso
2006-08-10 5:38 ` [stable] " Greg KH
2006-08-04 5:40 ` [patch 17/23] e1000: add forgotten PCI ID for supported device Greg KH
2006-08-04 5:40 ` [patch 18/23] cond_resched() fix Greg KH
2006-08-04 5:40 ` [patch 19/23] Fix budget-av compile failure Greg KH
2006-08-04 5:40 ` [patch 20/23] S390: fix futex_atomic_cmpxchg_inatomic Greg KH
2006-08-07 8:39 ` Martin Schwidefsky
2006-08-04 5:40 ` [patch 21/23] tty serialize flush_to_ldisc Greg KH
2006-08-04 5:40 ` [patch 22/23] Add stable branch to maintainers file Greg KH
2006-08-04 5:41 ` [patch 23/23] Have ext2 reject file handles with bad inode numbers early Greg KH
2006-08-04 7:18 ` [patch 00/23] -stable review Grant Coady
2006-08-04 7:20 ` Greg KH
2006-08-04 9:04 ` Jesper Juhl
2006-08-04 9:10 ` Patrick McHardy
2006-08-04 9:19 ` Jesper Juhl
2006-08-04 9:24 ` Patrick McHardy
2006-08-04 9:31 ` Jesper Juhl
2006-08-04 9:19 ` Andrew Morton
2006-08-04 9:22 ` Jesper Juhl
2006-08-04 13:50 ` Auke Kok
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20060804053920.GJ769@kroah.com \
--to=gregkh@suse.de \
--cc=akpm@osdl.org \
--cc=alan@lxorguk.ukuu.org.uk \
--cc=chuckw@quantumlinux.com \
--cc=davej@redhat.com \
--cc=davem@davemloft.net \
--cc=herbert@gondor.apana.org.au \
--cc=jmforbes@linuxtx.org \
--cc=linux-kernel@vger.kernel.org \
--cc=netdev@vger.kernel.org \
--cc=rdunlap@xenotime.net \
--cc=reviews@ml.cw.f00f.org \
--cc=stable@kernel.org \
--cc=torvalds@osdl.org \
--cc=tytso@mit.edu \
--cc=zwane@arm.linux.org.uk \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.