--- /dev/null
+From stable-bounces@linux.kernel.org Thu Sep 1 18:03:15 2005
+Date: Fri, 2 Sep 2005 11:02:57 +1000
+To: stable@kernel.org
+From: Herbert Xu <herbert@gondor.apana.org.au>
+Cc: "David S. Miller" <davem@davemloft.net>
+Subject: [stable] [TCP] Fix sk_forward_alloc underflow in tcp_sendmsg
+
+This patch fixes an sk_forward_alloc underflow in the TCP stack.
+The underflow could potentially cause assertion failures and other
+unhealthy symptoms.
+
+When tcp_sendmsg tacks on extra bits to an existing TCP_PAGE we don't
+check sk_forward_alloc even though a large amount of time may have
+elapsed since we allocated the page. In the mean time someone could've
+come along and liberated packets and reclaimed sk_forward_alloc memory.
+
+This patch makes tcp_sendmsg check sk_forward_alloc every time as we
+do in do_tcp_sendpages.
+
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Chris Wright <chrisw@osdl.org>
+---
+ include/net/sock.h | 5 ++---
+ net/ipv4/tcp.c | 14 +++++++++-----
+ 2 files changed, 11 insertions(+), 8 deletions(-)
+
+Index: linux-2.6.13.y/include/net/sock.h
+===================================================================
+--- linux-2.6.13.y.orig/include/net/sock.h
++++ linux-2.6.13.y/include/net/sock.h
+@@ -1178,9 +1178,8 @@ static inline struct page *sk_stream_all
+ {
+ struct page *page = NULL;
+
+- if (sk_stream_wmem_schedule(sk, PAGE_SIZE))
+- page = alloc_pages(sk->sk_allocation, 0);
+- else {
++ page = alloc_pages(sk->sk_allocation, 0);
++ if (!page) {
+ sk->sk_prot->enter_memory_pressure();
+ sk_stream_moderate_sndbuf(sk);
+ }
+Index: linux-2.6.13.y/net/ipv4/tcp.c
+===================================================================
+--- linux-2.6.13.y.orig/net/ipv4/tcp.c
++++ linux-2.6.13.y/net/ipv4/tcp.c
+@@ -882,19 +882,23 @@ new_segment:
+ if (off == PAGE_SIZE) {
+ put_page(page);
+ TCP_PAGE(sk) = page = NULL;
++ TCP_OFF(sk) = off = 0;
+ }
+- }
++ } else
++ BUG_ON(off);
++
++ if (copy > PAGE_SIZE - off)
++ copy = PAGE_SIZE - off;
++
++ if (!sk_stream_wmem_schedule(sk, copy))
++ goto wait_for_memory;
+
+ if (!page) {
+ /* Allocate new cache page. */
+ if (!(page = sk_stream_alloc_page(sk)))
+ goto wait_for_memory;
+- off = 0;
+ }
+
+- if (copy > PAGE_SIZE - off)
+- copy = PAGE_SIZE - off;
+-
+ /* Time to copy data. We are close to
+ * the end! */
+ err = skb_copy_to_page(sk, from, skb, page,