diff options
author | J. Bruce Fields <bfields@citi.umich.edu> | 2008-08-20 16:10:23 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2008-10-07 18:17:47 -0400 |
commit | ea31a4437c59219bf3ea946d58984b01a45a289c (patch) | |
tree | d386f91c39461c7505e614f0b281f0e7e9b99298 /fs/nfs/nfs4namespace.c | |
parent | f0c929251e01a7a86b6254c775cb6b65c6457f10 (diff) |
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>
Diffstat (limited to 'fs/nfs/nfs4namespace.c')
-rw-r--r-- | fs/nfs/nfs4namespace.c | 44 |
1 files changed, 18 insertions, 26 deletions
diff --git a/fs/nfs/nfs4namespace.c b/fs/nfs/nfs4namespace.c index 6bcc5696f911..30befc39b3c6 100644 --- a/fs/nfs/nfs4namespace.c +++ b/fs/nfs/nfs4namespace.c | |||
@@ -93,50 +93,42 @@ static int nfs4_validate_fspath(const struct vfsmount *mnt_parent, | |||
93 | return 0; | 93 | return 0; |
94 | } | 94 | } |
95 | 95 | ||
96 | /* | ||
97 | * Check if the string represents a "valid" IPv4 address | ||
98 | */ | ||
99 | static inline int valid_ipaddr4(const char *buf) | ||
100 | { | ||
101 | int rc, count, in[4]; | ||
102 | |||
103 | rc = sscanf(buf, "%d.%d.%d.%d", &in[0], &in[1], &in[2], &in[3]); | ||
104 | if (rc != 4) | ||
105 | return -EINVAL; | ||
106 | for (count = 0; count < 4; count++) { | ||
107 | if (in[count] > 255) | ||
108 | return -EINVAL; | ||
109 | } | ||
110 | return 0; | ||
111 | } | ||
112 | |||
113 | static struct vfsmount *try_location(struct nfs_clone_mount *mountdata, | 96 | static struct vfsmount *try_location(struct nfs_clone_mount *mountdata, |
114 | char *page, char *page2, | 97 | char *page, char *page2, |
115 | const struct nfs4_fs_location *location) | 98 | const struct nfs4_fs_location *location) |
116 | { | 99 | { |
117 | struct vfsmount *mnt = ERR_PTR(-ENOENT); | 100 | struct vfsmount *mnt = ERR_PTR(-ENOENT); |
118 | char *mnt_path; | 101 | char *mnt_path; |
102 | int page2len; | ||
119 | unsigned int s; | 103 | unsigned int s; |
120 | 104 | ||
121 | mnt_path = nfs4_pathname_string(&location->rootpath, page2, PAGE_SIZE); | 105 | mnt_path = nfs4_pathname_string(&location->rootpath, page2, PAGE_SIZE); |
122 | if (IS_ERR(mnt_path)) | 106 | if (IS_ERR(mnt_path)) |
123 | return mnt; | 107 | return mnt; |
124 | mountdata->mnt_path = mnt_path; | 108 | mountdata->mnt_path = mnt_path; |
109 | page2 += strlen(mnt_path) + 1; | ||
110 | page2len = PAGE_SIZE - strlen(mnt_path) - 1; | ||
125 | 111 | ||
126 | for (s = 0; s < location->nservers; s++) { | 112 | for (s = 0; s < location->nservers; s++) { |
127 | struct sockaddr_in addr = { | 113 | const struct nfs4_string *buf = &location->servers[s]; |
128 | .sin_family = AF_INET, | 114 | struct sockaddr_storage addr; |
129 | .sin_port = htons(NFS_PORT), | ||
130 | }; | ||
131 | 115 | ||
132 | if (location->servers[s].len <= 0 || | 116 | if (buf->len <= 0 || buf->len >= PAGE_SIZE) |
133 | valid_ipaddr4(location->servers[s].data) < 0) | ||
134 | continue; | 117 | continue; |
135 | 118 | ||
136 | mountdata->hostname = location->servers[s].data; | ||
137 | addr.sin_addr.s_addr = in_aton(mountdata->hostname), | ||
138 | mountdata->addr = (struct sockaddr *)&addr; | 119 | mountdata->addr = (struct sockaddr *)&addr; |
139 | mountdata->addrlen = sizeof(addr); | 120 | |
121 | if (memchr(buf->data, IPV6_SCOPE_DELIMITER, buf->len)) | ||
122 | continue; | ||
123 | nfs_parse_ip_address(buf->data, buf->len, | ||
124 | mountdata->addr, &mountdata->addrlen); | ||
125 | if (mountdata->addr->sa_family == AF_UNSPEC) | ||
126 | continue; | ||
127 | nfs_set_port(mountdata->addr, NFS_PORT); | ||
128 | |||
129 | strncpy(page2, buf->data, page2len); | ||
130 | page2[page2len] = '\0'; | ||
131 | mountdata->hostname = page2; | ||
140 | 132 | ||
141 | snprintf(page, PAGE_SIZE, "%s:%s", | 133 | snprintf(page, PAGE_SIZE, "%s:%s", |
142 | mountdata->hostname, | 134 | mountdata->hostname, |