Commit abc5c44d authored by Chuck Lever's avatar Chuck Lever Committed by J. Bruce Fields

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: default avatarChuck Lever <chuck.lever@oracle.com>
Signed-off-by: default avatarJ. Bruce Fields <bfields@citi.umich.edu>
parent dcf1a357
...@@ -118,7 +118,7 @@ static inline unsigned short svc_addr_port(const struct sockaddr *sa) ...@@ -118,7 +118,7 @@ static inline unsigned short svc_addr_port(const struct sockaddr *sa)
return 0; return 0;
} }
static inline size_t svc_addr_len(struct sockaddr *sa) static inline size_t svc_addr_len(const struct sockaddr *sa)
{ {
switch (sa->sa_family) { switch (sa->sa_family) {
case AF_INET: case AF_INET:
...@@ -126,7 +126,8 @@ static inline size_t svc_addr_len(struct sockaddr *sa) ...@@ -126,7 +126,8 @@ static inline size_t svc_addr_len(struct sockaddr *sa)
case AF_INET6: case AF_INET6:
return sizeof(struct sockaddr_in6); return sizeof(struct sockaddr_in6);
} }
return -EAFNOSUPPORT;
return 0;
} }
static inline unsigned short svc_xprt_local_port(const struct svc_xprt *xprt) static inline unsigned short svc_xprt_local_port(const struct svc_xprt *xprt)
......
...@@ -426,13 +426,14 @@ static int svc_udp_recvfrom(struct svc_rqst *rqstp) ...@@ -426,13 +426,14 @@ static int svc_udp_recvfrom(struct svc_rqst *rqstp)
long all[SVC_PKTINFO_SPACE / sizeof(long)]; long all[SVC_PKTINFO_SPACE / sizeof(long)];
} buffer; } buffer;
struct cmsghdr *cmh = &buffer.hdr; struct cmsghdr *cmh = &buffer.hdr;
int err, len;
struct msghdr msg = { struct msghdr msg = {
.msg_name = svc_addr(rqstp), .msg_name = svc_addr(rqstp),
.msg_control = cmh, .msg_control = cmh,
.msg_controllen = sizeof(buffer), .msg_controllen = sizeof(buffer),
.msg_flags = MSG_DONTWAIT, .msg_flags = MSG_DONTWAIT,
}; };
size_t len;
int err;
if (test_and_clear_bit(XPT_CHNGBUF, &svsk->sk_xprt.xpt_flags)) if (test_and_clear_bit(XPT_CHNGBUF, &svsk->sk_xprt.xpt_flags))
/* udp sockets need large rcvbuf as all pending /* udp sockets need large rcvbuf as all pending
...@@ -464,8 +465,8 @@ static int svc_udp_recvfrom(struct svc_rqst *rqstp) ...@@ -464,8 +465,8 @@ static int svc_udp_recvfrom(struct svc_rqst *rqstp)
return -EAGAIN; return -EAGAIN;
} }
len = svc_addr_len(svc_addr(rqstp)); len = svc_addr_len(svc_addr(rqstp));
if (len < 0) if (len == 0)
return len; return -EAFNOSUPPORT;
rqstp->rq_addrlen = len; rqstp->rq_addrlen = len;
if (skb->tstamp.tv64 == 0) { if (skb->tstamp.tv64 == 0) {
skb->tstamp = ktime_get_real(); skb->tstamp = ktime_get_real();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment