nfs: Fix misparsing of nfsv4 fs_locations attribute
The code incorrectly assumes here that the server name (or ip address) is null-terminated. This can cause referrals to fail in some cases. Also support ipv6 addresses. Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu> Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
This commit is contained in:
parent
f0c929251e
commit
ea31a4437c
@ -153,6 +153,7 @@ extern void nfs4_clear_inode(struct inode *);
|
||||
void nfs_zap_acl_cache(struct inode *inode);
|
||||
|
||||
/* super.c */
|
||||
void nfs_parse_ip_address(char *, size_t, struct sockaddr *, size_t *);
|
||||
extern struct file_system_type nfs_xdev_fs_type;
|
||||
#ifdef CONFIG_NFS_V4
|
||||
extern struct file_system_type nfs4_xdev_fs_type;
|
||||
@ -276,6 +277,7 @@ unsigned int nfs_page_array_len(unsigned int base, size_t len)
|
||||
PAGE_SIZE - 1) >> PAGE_SHIFT;
|
||||
}
|
||||
|
||||
#define IPV6_SCOPE_DELIMITER '%'
|
||||
|
||||
/*
|
||||
* Set the port number in an address. Be agnostic about the address
|
||||
|
@ -93,50 +93,42 @@ static int nfs4_validate_fspath(const struct vfsmount *mnt_parent,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if the string represents a "valid" IPv4 address
|
||||
*/
|
||||
static inline int valid_ipaddr4(const char *buf)
|
||||
{
|
||||
int rc, count, in[4];
|
||||
|
||||
rc = sscanf(buf, "%d.%d.%d.%d", &in[0], &in[1], &in[2], &in[3]);
|
||||
if (rc != 4)
|
||||
return -EINVAL;
|
||||
for (count = 0; count < 4; count++) {
|
||||
if (in[count] > 255)
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct vfsmount *try_location(struct nfs_clone_mount *mountdata,
|
||||
char *page, char *page2,
|
||||
const struct nfs4_fs_location *location)
|
||||
{
|
||||
struct vfsmount *mnt = ERR_PTR(-ENOENT);
|
||||
char *mnt_path;
|
||||
int page2len;
|
||||
unsigned int s;
|
||||
|
||||
mnt_path = nfs4_pathname_string(&location->rootpath, page2, PAGE_SIZE);
|
||||
if (IS_ERR(mnt_path))
|
||||
return mnt;
|
||||
mountdata->mnt_path = mnt_path;
|
||||
page2 += strlen(mnt_path) + 1;
|
||||
page2len = PAGE_SIZE - strlen(mnt_path) - 1;
|
||||
|
||||
for (s = 0; s < location->nservers; s++) {
|
||||
struct sockaddr_in addr = {
|
||||
.sin_family = AF_INET,
|
||||
.sin_port = htons(NFS_PORT),
|
||||
};
|
||||
const struct nfs4_string *buf = &location->servers[s];
|
||||
struct sockaddr_storage addr;
|
||||
|
||||
if (location->servers[s].len <= 0 ||
|
||||
valid_ipaddr4(location->servers[s].data) < 0)
|
||||
if (buf->len <= 0 || buf->len >= PAGE_SIZE)
|
||||
continue;
|
||||
|
||||
mountdata->hostname = location->servers[s].data;
|
||||
addr.sin_addr.s_addr = in_aton(mountdata->hostname),
|
||||
mountdata->addr = (struct sockaddr *)&addr;
|
||||
mountdata->addrlen = sizeof(addr);
|
||||
|
||||
if (memchr(buf->data, IPV6_SCOPE_DELIMITER, buf->len))
|
||||
continue;
|
||||
nfs_parse_ip_address(buf->data, buf->len,
|
||||
mountdata->addr, &mountdata->addrlen);
|
||||
if (mountdata->addr->sa_family == AF_UNSPEC)
|
||||
continue;
|
||||
nfs_set_port(mountdata->addr, NFS_PORT);
|
||||
|
||||
strncpy(page2, buf->data, page2len);
|
||||
page2[page2len] = '\0';
|
||||
mountdata->hostname = page2;
|
||||
|
||||
snprintf(page, PAGE_SIZE, "%s:%s",
|
||||
mountdata->hostname,
|
||||
|
@ -716,8 +716,6 @@ static void nfs_parse_ipv4_address(char *string, size_t str_len,
|
||||
*addr_len = 0;
|
||||
}
|
||||
|
||||
#define IPV6_SCOPE_DELIMITER '%'
|
||||
|
||||
#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,
|
||||
@ -790,7 +788,7 @@ static void nfs_parse_ipv6_address(char *string, size_t str_len,
|
||||
* If there is a problem constructing the new sockaddr, set the address
|
||||
* family to AF_UNSPEC.
|
||||
*/
|
||||
static void nfs_parse_ip_address(char *string, size_t str_len,
|
||||
void nfs_parse_ip_address(char *string, size_t str_len,
|
||||
struct sockaddr *sap, size_t *addr_len)
|
||||
{
|
||||
unsigned int i, colons;
|
||||
|
Loading…
Reference in New Issue
Block a user