diff options
author | Chuck Lever <chuck.lever@oracle.com> | 2009-04-23 19:31:25 -0400 |
---|---|---|
committer | J. Bruce Fields <bfields@citi.umich.edu> | 2009-04-28 13:54:25 -0400 |
commit | abc5c44d6284fab8fb21bcfc52c0f16f980637df (patch) | |
tree | 98825098d3f6488a1a8fb55ec40131313b1d25e9 | |
parent | dcf1a3573eae69937fb14462369c4d3e6f4a37f1 (diff) |
SUNRPC: Fix error return value of svc_addr_len()
The svc_addr_len() helper function returns -EAFNOSUPPORT if it doesn't
recognize the address family of the passed-in socket address. However,
the return type of this function is size_t, which means -EAFNOSUPPORT
is turned into a very large positive value in this case.
The check in svc_udp_recvfrom() to see if the return value is less
than zero therefore won't work at all.
Additionally, handle_connect_req() passes this value directly to
memset(). This could cause memset() to clobber a large chunk of memory
if svc_addr_len() has returned an error. Currently the address family
of these addresses, however, is known to be supported long before
handle_connect_req() is called, so this isn't a real risk.
Change the error return value of svc_addr_len() to zero, which fits in
the range of size_t, and is safer to pass to memset() directly.
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
-rw-r--r-- | include/linux/sunrpc/svc_xprt.h | 5 | ||||
-rw-r--r-- | net/sunrpc/svcsock.c | 7 |
2 files changed, 7 insertions, 5 deletions
diff --git a/include/linux/sunrpc/svc_xprt.h b/include/linux/sunrpc/svc_xprt.h index 0d9cb6ef28b0..d790c52525cc 100644 --- a/include/linux/sunrpc/svc_xprt.h +++ b/include/linux/sunrpc/svc_xprt.h | |||
@@ -118,7 +118,7 @@ static inline unsigned short svc_addr_port(const struct sockaddr *sa) | |||
118 | return 0; | 118 | return 0; |
119 | } | 119 | } |
120 | 120 | ||
121 | static inline size_t svc_addr_len(struct sockaddr *sa) | 121 | static inline size_t svc_addr_len(const struct sockaddr *sa) |
122 | { | 122 | { |
123 | switch (sa->sa_family) { | 123 | switch (sa->sa_family) { |
124 | case AF_INET: | 124 | case AF_INET: |
@@ -126,7 +126,8 @@ static inline size_t svc_addr_len(struct sockaddr *sa) | |||
126 | case AF_INET6: | 126 | case AF_INET6: |
127 | return sizeof(struct sockaddr_in6); | 127 | return sizeof(struct sockaddr_in6); |
128 | } | 128 | } |
129 | return -EAFNOSUPPORT; | 129 | |
130 | return 0; | ||
130 | } | 131 | } |
131 | 132 | ||
132 | static inline unsigned short svc_xprt_local_port(const struct svc_xprt *xprt) | 133 | static inline unsigned short svc_xprt_local_port(const struct svc_xprt *xprt) |
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index af3198814c15..8b0832834135 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c | |||
@@ -426,13 +426,14 @@ static int svc_udp_recvfrom(struct svc_rqst *rqstp) | |||
426 | long all[SVC_PKTINFO_SPACE / sizeof(long)]; | 426 | long all[SVC_PKTINFO_SPACE / sizeof(long)]; |
427 | } buffer; | 427 | } buffer; |
428 | struct cmsghdr *cmh = &buffer.hdr; | 428 | struct cmsghdr *cmh = &buffer.hdr; |
429 | int err, len; | ||
430 | struct msghdr msg = { | 429 | struct msghdr msg = { |
431 | .msg_name = svc_addr(rqstp), | 430 | .msg_name = svc_addr(rqstp), |
432 | .msg_control = cmh, | 431 | .msg_control = cmh, |
433 | .msg_controllen = sizeof(buffer), | 432 | .msg_controllen = sizeof(buffer), |
434 | .msg_flags = MSG_DONTWAIT, | 433 | .msg_flags = MSG_DONTWAIT, |
435 | }; | 434 | }; |
435 | size_t len; | ||
436 | int err; | ||
436 | 437 | ||
437 | if (test_and_clear_bit(XPT_CHNGBUF, &svsk->sk_xprt.xpt_flags)) | 438 | if (test_and_clear_bit(XPT_CHNGBUF, &svsk->sk_xprt.xpt_flags)) |
438 | /* udp sockets need large rcvbuf as all pending | 439 | /* udp sockets need large rcvbuf as all pending |
@@ -464,8 +465,8 @@ static int svc_udp_recvfrom(struct svc_rqst *rqstp) | |||
464 | return -EAGAIN; | 465 | return -EAGAIN; |
465 | } | 466 | } |
466 | len = svc_addr_len(svc_addr(rqstp)); | 467 | len = svc_addr_len(svc_addr(rqstp)); |
467 | if (len < 0) | 468 | if (len == 0) |
468 | return len; | 469 | return -EAFNOSUPPORT; |
469 | rqstp->rq_addrlen = len; | 470 | rqstp->rq_addrlen = len; |
470 | if (skb->tstamp.tv64 == 0) { | 471 | if (skb->tstamp.tv64 == 0) { |
471 | skb->tstamp = ktime_get_real(); | 472 | skb->tstamp = ktime_get_real(); |