LKML Archive on lore.kernel.org
help / color / mirror / Atom feed
* [PATCH] tcp_sendpage(): fix broken page iteration
@ 2007-03-18 12:43 Dan Aloni
  2007-03-18 12:50 ` Dan Aloni
  2007-03-18 21:49 ` David Miller
  0 siblings, 2 replies; 4+ messages in thread
From: Dan Aloni @ 2007-03-18 12:43 UTC (permalink / raw)
  To: Linux Kernel List; +Cc: netdev

do_tcp_sendpages() should not iterate 'pages' as an array since 
it is not an array of 'struct page *', but a pointer to a single 
entity of 'struct page *' passed on the stack as a parameter to 
tcp_send_page() (hence it would crash if poffset + psize > PAGE_SIZE,
because pages[1] and beyond most probably not constitutes a valid 
'struct page *').

Since 'page' points to an array of 'struct page', the obvious fix 
is to iterate that array instead, and that's what the function
should have done in the first place.

Applies to 2.6.21-rc4 and above.


diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 3834b10..4881c8d 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -501,7 +501,7 @@ static inline void tcp_push(struct sock *sk, struct tcp_sock *tp, int flags,
 	}
 }
 
-static ssize_t do_tcp_sendpages(struct sock *sk, struct page **pages, int poffset,
+static ssize_t do_tcp_sendpages(struct sock *sk, struct page *pages, int poffset,
 			 size_t psize, int flags)
 {
 	struct tcp_sock *tp = tcp_sk(sk);
@@ -527,7 +527,7 @@ static ssize_t do_tcp_sendpages(struct sock *sk, struct page **pages, int poffse
 
 	while (psize > 0) {
 		struct sk_buff *skb = sk->sk_write_queue.prev;
-		struct page *page = pages[poffset / PAGE_SIZE];
+		struct page *page = &pages[poffset / PAGE_SIZE];
 		int copy, i, can_coalesce;
 		int offset = poffset % PAGE_SIZE;
 		int size = min_t(size_t, psize, PAGE_SIZE - offset);
@@ -630,7 +630,7 @@ ssize_t tcp_sendpage(struct socket *sock, struct page *page, int offset,
 
 	lock_sock(sk);
 	TCP_CHECK_TIMER(sk);
-	res = do_tcp_sendpages(sk, &page, offset, size, flags);
+	res = do_tcp_sendpages(sk, page, offset, size, flags);
 	TCP_CHECK_TIMER(sk);
 	release_sock(sk);
 	return res;


-- 
Dan Aloni
XIV LTD, http://www.xivstorage.com
da-x (at) monatomic.org, dan (at) xiv.co.il

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH] tcp_sendpage(): fix broken page iteration
  2007-03-18 12:43 [PATCH] tcp_sendpage(): fix broken page iteration Dan Aloni
@ 2007-03-18 12:50 ` Dan Aloni
  2007-03-18 21:49 ` David Miller
  1 sibling, 0 replies; 4+ messages in thread
From: Dan Aloni @ 2007-03-18 12:50 UTC (permalink / raw)
  To: Linux Kernel List; +Cc: netdev

On Sun, Mar 18, 2007 at 02:43:46PM +0200, Dan Aloni wrote:
> do_tcp_sendpages() should not iterate 'pages' as an array since 
> it is not an array of 'struct page *', but a pointer to a single 
> entity of 'struct page *' passed on the stack as a parameter to 
> tcp_send_page() (hence it would crash if poffset + psize > PAGE_SIZE,
> because pages[1] and beyond most probably not constitutes a valid 
> 'struct page *').
> 
> Since 'page' points to an array of 'struct page', the obvious fix 
> is to iterate that array instead, and that's what the function
> should have done in the first place.
> 
> Applies to 2.6.21-rc4 and above.

Oops, forgot the obligtory signed-off:

Signed-off-by: Dan Aloni <da-x@monatomic.org>

diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 3834b10..4881c8d 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -501,7 +501,7 @@ static inline void tcp_push(struct sock *sk, struct tcp_sock *tp, int flags,
 	}
 }
 
-static ssize_t do_tcp_sendpages(struct sock *sk, struct page **pages, int poffset,
+static ssize_t do_tcp_sendpages(struct sock *sk, struct page *pages, int poffset,
 			 size_t psize, int flags)
 {
 	struct tcp_sock *tp = tcp_sk(sk);
@@ -527,7 +527,7 @@ static ssize_t do_tcp_sendpages(struct sock *sk, struct page **pages, int poffse
 
 	while (psize > 0) {
 		struct sk_buff *skb = sk->sk_write_queue.prev;
-		struct page *page = pages[poffset / PAGE_SIZE];
+		struct page *page = &pages[poffset / PAGE_SIZE];
 		int copy, i, can_coalesce;
 		int offset = poffset % PAGE_SIZE;
 		int size = min_t(size_t, psize, PAGE_SIZE - offset);
@@ -630,7 +630,7 @@ ssize_t tcp_sendpage(struct socket *sock, struct page *page, int offset,
 
 	lock_sock(sk);
 	TCP_CHECK_TIMER(sk);
-	res = do_tcp_sendpages(sk, &page, offset, size, flags);
+	res = do_tcp_sendpages(sk, page, offset, size, flags);
 	TCP_CHECK_TIMER(sk);
 	release_sock(sk);
 	return res;


-- 
Dan Aloni
XIV LTD, http://www.xivstorage.com
da-x (at) monatomic.org, dan (at) xiv.co.il

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH] tcp_sendpage(): fix broken page iteration
  2007-03-18 12:43 [PATCH] tcp_sendpage(): fix broken page iteration Dan Aloni
  2007-03-18 12:50 ` Dan Aloni
@ 2007-03-18 21:49 ` David Miller
  2007-03-18 22:40   ` Dan Aloni
  1 sibling, 1 reply; 4+ messages in thread
From: David Miller @ 2007-03-18 21:49 UTC (permalink / raw)
  To: da-x; +Cc: linux-kernel, netdev

From: Dan Aloni <da-x@monatomic.org>
Date: Sun, 18 Mar 2007 14:43:46 +0200

> do_tcp_sendpages() should not iterate 'pages' as an array since 
> it is not an array of 'struct page *', but a pointer to a single 
> entity of 'struct page *' passed on the stack as a parameter to 
> tcp_send_page() (hence it would crash if poffset + psize > PAGE_SIZE,
> because pages[1] and beyond most probably not constitutes a valid 
> 'struct page *').

do_tcp_sendpages() should never get passed poffset+psize>PAGE_SIZE,
that would be a bug.

Feel free to add a BUG() check for that if you wish, and a fix for any
caller which violates this.

The code is perfectly fine as-is.  It was originally written to accept
page arrays, but once it was decided that ->sendpage() would only pass
in one page, we simply modified to caller of do_tcp_sendpages() to
accomodate this argument passing change, instead of changing
do_tcp_sendpages() which is totally unnecessary.

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] tcp_sendpage(): fix broken page iteration
  2007-03-18 21:49 ` David Miller
@ 2007-03-18 22:40   ` Dan Aloni
  0 siblings, 0 replies; 4+ messages in thread
From: Dan Aloni @ 2007-03-18 22:40 UTC (permalink / raw)
  To: David Miller; +Cc: linux-kernel, netdev

On Sun, Mar 18, 2007 at 02:49:27PM -0700, David Miller wrote:
> From: Dan Aloni <da-x@monatomic.org>
> Date: Sun, 18 Mar 2007 14:43:46 +0200
> 
> > do_tcp_sendpages() should not iterate 'pages' as an array since 
> > it is not an array of 'struct page *', but a pointer to a single 
> > entity of 'struct page *' passed on the stack as a parameter to 
> > tcp_send_page() (hence it would crash if poffset + psize > PAGE_SIZE,
> > because pages[1] and beyond most probably not constitutes a valid 
> > 'struct page *').
> 
> do_tcp_sendpages() should never get passed poffset+psize>PAGE_SIZE,
> that would be a bug.

Oh, then the name of that function was quite misleading...

Anyway, I thought it would make a valid case for a situation where
you have a kmalloc'ed buffer that happens to cross a page boundery 
and you want to call ->sendpage() to send it over using network
DMA. 

As I see it, with this constraint you either call sendpage twice or
you use kernel_sendmsg(), I am not sure which would me more 
efficient - I guess it depends on psize. I wish there was a better
interface than sendpage that would have factored it in...

Thanks anyway for the heads up.

-- 
Dan Aloni
XIV LTD, http://www.xivstorage.com
da-x (at) monatomic.org, dan (at) xiv.co.il

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2007-03-18 22:40 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2007-03-18 12:43 [PATCH] tcp_sendpage(): fix broken page iteration Dan Aloni
2007-03-18 12:50 ` Dan Aloni
2007-03-18 21:49 ` David Miller
2007-03-18 22:40   ` Dan Aloni

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).