[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20100730175137.115021082@clark.site>
Date: Fri, 30 Jul 2010 10:50:56 -0700
From: Greg KH <gregkh@...e.de>
To: linux-kernel@...r.kernel.org, stable@...nel.org
Cc: stable-review@...nel.org, torvalds@...ux-foundation.org,
akpm@...ux-foundation.org, alan@...rguk.ukuu.org.uk,
Trond Myklebust <Trond.Myklebust@...app.com>
Subject: [039/205] SUNRPC: Fix a re-entrancy bug in xs_tcp_read_calldir()
2.6.34-stable review patch. If anyone has any objections, please let us know.
------------------
From: Trond Myklebust <Trond.Myklebust@...app.com>
commit b76ce56192bcf618013fb9aecd83488cffd645cc upstream.
If the attempt to read the calldir fails, then instead of storing the read
bytes, we currently discard them. This leads to a garbage final result when
upon re-entry to the same routine, we read the remaining bytes.
Fixes the regression in bugzilla number 16213. Please see
https://bugzilla.kernel.org/show_bug.cgi?id=16213
Signed-off-by: Trond Myklebust <Trond.Myklebust@...app.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@...e.de>
---
net/sunrpc/xprtsock.c | 38 ++++++++++++++++++++++----------------
1 file changed, 22 insertions(+), 16 deletions(-)
--- a/net/sunrpc/xprtsock.c
+++ b/net/sunrpc/xprtsock.c
@@ -224,7 +224,8 @@ struct sock_xprt {
* State of TCP reply receive
*/
__be32 tcp_fraghdr,
- tcp_xid;
+ tcp_xid,
+ tcp_calldir;
u32 tcp_offset,
tcp_reclen;
@@ -942,7 +943,7 @@ static inline void xs_tcp_read_calldir(s
{
size_t len, used;
u32 offset;
- __be32 calldir;
+ char *p;
/*
* We want transport->tcp_offset to be 8 at the end of this routine
@@ -951,26 +952,33 @@ static inline void xs_tcp_read_calldir(s
* transport->tcp_offset is 4 (after having already read the xid).
*/
offset = transport->tcp_offset - sizeof(transport->tcp_xid);
- len = sizeof(calldir) - offset;
+ len = sizeof(transport->tcp_calldir) - offset;
dprintk("RPC: reading CALL/REPLY flag (%Zu bytes)\n", len);
- used = xdr_skb_read_bits(desc, &calldir, len);
+ p = ((char *) &transport->tcp_calldir) + offset;
+ used = xdr_skb_read_bits(desc, p, len);
transport->tcp_offset += used;
if (used != len)
return;
transport->tcp_flags &= ~TCP_RCV_READ_CALLDIR;
- transport->tcp_flags |= TCP_RCV_COPY_CALLDIR;
- transport->tcp_flags |= TCP_RCV_COPY_DATA;
/*
* We don't yet have the XDR buffer, so we will write the calldir
* out after we get the buffer from the 'struct rpc_rqst'
*/
- if (ntohl(calldir) == RPC_REPLY)
+ switch (ntohl(transport->tcp_calldir)) {
+ case RPC_REPLY:
+ transport->tcp_flags |= TCP_RCV_COPY_CALLDIR;
+ transport->tcp_flags |= TCP_RCV_COPY_DATA;
transport->tcp_flags |= TCP_RPC_REPLY;
- else
+ break;
+ case RPC_CALL:
+ transport->tcp_flags |= TCP_RCV_COPY_CALLDIR;
+ transport->tcp_flags |= TCP_RCV_COPY_DATA;
transport->tcp_flags &= ~TCP_RPC_REPLY;
- dprintk("RPC: reading %s CALL/REPLY flag %08x\n",
- (transport->tcp_flags & TCP_RPC_REPLY) ?
- "reply for" : "request with", calldir);
+ break;
+ default:
+ dprintk("RPC: invalid request message type\n");
+ xprt_force_disconnect(&transport->xprt);
+ }
xs_tcp_check_fraghdr(transport);
}
@@ -990,12 +998,10 @@ static inline void xs_tcp_read_common(st
/*
* Save the RPC direction in the XDR buffer
*/
- __be32 calldir = transport->tcp_flags & TCP_RPC_REPLY ?
- htonl(RPC_REPLY) : 0;
-
memcpy(rcvbuf->head[0].iov_base + transport->tcp_copied,
- &calldir, sizeof(calldir));
- transport->tcp_copied += sizeof(calldir);
+ &transport->tcp_calldir,
+ sizeof(transport->tcp_calldir));
+ transport->tcp_copied += sizeof(transport->tcp_calldir);
transport->tcp_flags &= ~TCP_RCV_COPY_CALLDIR;
}
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
Powered by blists - more mailing lists