]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blame - releases/2.6.32.17/sunrpc-fix-a-re-entrancy-bug-in-xs_tcp_read_calldir.patch
4.9-stable patches
[thirdparty/kernel/stable-queue.git] / releases / 2.6.32.17 / sunrpc-fix-a-re-entrancy-bug-in-xs_tcp_read_calldir.patch
CommitLineData
a0402406
GKH
1From b76ce56192bcf618013fb9aecd83488cffd645cc Mon Sep 17 00:00:00 2001
2From: Trond Myklebust <Trond.Myklebust@netapp.com>
3Date: Wed, 16 Jun 2010 13:57:32 -0400
4Subject: SUNRPC: Fix a re-entrancy bug in xs_tcp_read_calldir()
5
6From: Trond Myklebust <Trond.Myklebust@netapp.com>
7
8commit b76ce56192bcf618013fb9aecd83488cffd645cc upstream.
9
10If the attempt to read the calldir fails, then instead of storing the read
11bytes, we currently discard them. This leads to a garbage final result when
12upon re-entry to the same routine, we read the remaining bytes.
13
14Fixes the regression in bugzilla number 16213. Please see
15 https://bugzilla.kernel.org/show_bug.cgi?id=16213
16
17Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
18Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
19
20---
21 net/sunrpc/xprtsock.c | 38 ++++++++++++++++++++++----------------
22 1 file changed, 22 insertions(+), 16 deletions(-)
23
24--- a/net/sunrpc/xprtsock.c
25+++ b/net/sunrpc/xprtsock.c
26@@ -238,7 +238,8 @@ struct sock_xprt {
27 * State of TCP reply receive
28 */
29 __be32 tcp_fraghdr,
30- tcp_xid;
31+ tcp_xid,
32+ tcp_calldir;
33
34 u32 tcp_offset,
35 tcp_reclen;
36@@ -961,7 +962,7 @@ static inline void xs_tcp_read_calldir(s
37 {
38 size_t len, used;
39 u32 offset;
40- __be32 calldir;
41+ char *p;
42
43 /*
44 * We want transport->tcp_offset to be 8 at the end of this routine
45@@ -970,26 +971,33 @@ static inline void xs_tcp_read_calldir(s
46 * transport->tcp_offset is 4 (after having already read the xid).
47 */
48 offset = transport->tcp_offset - sizeof(transport->tcp_xid);
49- len = sizeof(calldir) - offset;
50+ len = sizeof(transport->tcp_calldir) - offset;
51 dprintk("RPC: reading CALL/REPLY flag (%Zu bytes)\n", len);
52- used = xdr_skb_read_bits(desc, &calldir, len);
53+ p = ((char *) &transport->tcp_calldir) + offset;
54+ used = xdr_skb_read_bits(desc, p, len);
55 transport->tcp_offset += used;
56 if (used != len)
57 return;
58 transport->tcp_flags &= ~TCP_RCV_READ_CALLDIR;
59- transport->tcp_flags |= TCP_RCV_COPY_CALLDIR;
60- transport->tcp_flags |= TCP_RCV_COPY_DATA;
61 /*
62 * We don't yet have the XDR buffer, so we will write the calldir
63 * out after we get the buffer from the 'struct rpc_rqst'
64 */
65- if (ntohl(calldir) == RPC_REPLY)
66+ switch (ntohl(transport->tcp_calldir)) {
67+ case RPC_REPLY:
68+ transport->tcp_flags |= TCP_RCV_COPY_CALLDIR;
69+ transport->tcp_flags |= TCP_RCV_COPY_DATA;
70 transport->tcp_flags |= TCP_RPC_REPLY;
71- else
72+ break;
73+ case RPC_CALL:
74+ transport->tcp_flags |= TCP_RCV_COPY_CALLDIR;
75+ transport->tcp_flags |= TCP_RCV_COPY_DATA;
76 transport->tcp_flags &= ~TCP_RPC_REPLY;
77- dprintk("RPC: reading %s CALL/REPLY flag %08x\n",
78- (transport->tcp_flags & TCP_RPC_REPLY) ?
79- "reply for" : "request with", calldir);
80+ break;
81+ default:
82+ dprintk("RPC: invalid request message type\n");
83+ xprt_force_disconnect(&transport->xprt);
84+ }
85 xs_tcp_check_fraghdr(transport);
86 }
87
88@@ -1009,12 +1017,10 @@ static inline void xs_tcp_read_common(st
89 /*
90 * Save the RPC direction in the XDR buffer
91 */
92- __be32 calldir = transport->tcp_flags & TCP_RPC_REPLY ?
93- htonl(RPC_REPLY) : 0;
94-
95 memcpy(rcvbuf->head[0].iov_base + transport->tcp_copied,
96- &calldir, sizeof(calldir));
97- transport->tcp_copied += sizeof(calldir);
98+ &transport->tcp_calldir,
99+ sizeof(transport->tcp_calldir));
100+ transport->tcp_copied += sizeof(transport->tcp_calldir);
101 transport->tcp_flags &= ~TCP_RCV_COPY_CALLDIR;
102 }
103