Skip to content

Commit

Permalink
NFS: fix nfs_parse_ip_address() corner case
Browse files Browse the repository at this point in the history
Bruce observed that nfs_parse_ip_address() will successfully parse an
IPv6 address that looks like this:

  "::1%"

A scope delimiter is present, but there is no scope ID following it.
This is harmless, as it would simply set the scope ID to zero.  However,
in some cases we would like to flag this as an improperly formed
address.

We are now also careful to reject addresses where garbage follows the
address (up to the length of the string), instead of ignoring the
non-address characters; and where the scope ID is nonsense (not a valid
device name, but also not numeric).  Before, both of these cases would
result in a harmless zero scope ID.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
  • Loading branch information
Chuck Lever authored and Trond Myklebust committed Oct 10, 2008
1 parent 456018d commit 5e2e772
Showing 1 changed file with 23 additions and 11 deletions.
34 changes: 23 additions & 11 deletions fs/nfs/super.c
Original file line number Diff line number Diff line change
Expand Up @@ -717,17 +717,21 @@ static void nfs_parse_ipv4_address(char *string, size_t str_len,
}

#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
static void nfs_parse_ipv6_scope_id(const char *string, const size_t str_len,
const char *delim,
struct sockaddr_in6 *sin6)
static int nfs_parse_ipv6_scope_id(const char *string, const size_t str_len,
const char *delim,
struct sockaddr_in6 *sin6)
{
char *p;
size_t len;

if (!(ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL))
return ;
if ((string + str_len) == delim)
return 1;

if (*delim != IPV6_SCOPE_DELIMITER)
return;
return 0;

if (!(ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL))
return 0;

len = (string + str_len) - delim - 1;
p = kstrndup(delim + 1, len, GFP_KERNEL);
Expand All @@ -740,14 +744,20 @@ static void nfs_parse_ipv6_scope_id(const char *string, const size_t str_len,
scope_id = dev->ifindex;
dev_put(dev);
} else {
/* scope_id is set to zero on error */
strict_strtoul(p, 10, &scope_id);
if (strict_strtoul(p, 10, &scope_id) == 0) {
kfree(p);
return 0;
}
}

kfree(p);

sin6->sin6_scope_id = scope_id;
dfprintk(MOUNT, "NFS: IPv6 scope ID = %lu\n", scope_id);
return 1;
}

return 0;
}

static void nfs_parse_ipv6_address(char *string, size_t str_len,
Expand All @@ -763,9 +773,11 @@ static void nfs_parse_ipv6_address(char *string, size_t str_len,

sin6->sin6_family = AF_INET6;
*addr_len = sizeof(*sin6);
if (in6_pton(string, str_len, addr, IPV6_SCOPE_DELIMITER, &delim)) {
nfs_parse_ipv6_scope_id(string, str_len, delim, sin6);
return;
if (in6_pton(string, str_len, addr,
IPV6_SCOPE_DELIMITER, &delim) != 0) {
if (nfs_parse_ipv6_scope_id(string, str_len,
delim, sin6) != 0)
return;
}
}

Expand Down

0 comments on commit 5e2e772

Please sign in to comment.