Commit 57df675c60c5cf0748ddba9c7f85afde1530d74d
Committed by
Trond Myklebust
1 parent
78851e1aa4
Exists in
master
and in
7 other branches
NLM: Fix GRANT callback address comparison when IPv6 is enabled
The NFS mount command may pass an AF_INET server address to lockd. If lockd happens to be using a PF_INET6 listener, the nlm_cmp_addr() in nlmclnt_grant() will fail to match requests from that host because they will all have a mapped IPv4 AF_INET6 address. Adopt the same solution used in nfs_sockaddr_match_ipaddr() for NFSv4 callbacks: if either address is AF_INET, map it to an AF_INET6 address before doing the comparison. Signed-off-by: Chuck Lever <chuck.lever@oracle.com> Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Showing 1 changed file with 50 additions and 1 deletions Side-by-side Diff
fs/lockd/clntlock.c
... | ... | @@ -139,7 +139,56 @@ |
139 | 139 | return 0; |
140 | 140 | } |
141 | 141 | |
142 | +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | |
143 | +static const struct in6_addr *nlmclnt_map_v4addr(const struct sockaddr *sap, | |
144 | + struct in6_addr *addr_mapped) | |
145 | +{ | |
146 | + const struct sockaddr_in *sin = (const struct sockaddr_in *)sap; | |
147 | + | |
148 | + switch (sap->sa_family) { | |
149 | + case AF_INET6: | |
150 | + return &((const struct sockaddr_in6 *)sap)->sin6_addr; | |
151 | + case AF_INET: | |
152 | + ipv6_addr_set_v4mapped(sin->sin_addr.s_addr, addr_mapped); | |
153 | + return addr_mapped; | |
154 | + } | |
155 | + | |
156 | + return NULL; | |
157 | +} | |
158 | + | |
142 | 159 | /* |
160 | + * If lockd is using a PF_INET6 listener, all incoming requests appear | |
161 | + * to come from AF_INET6 remotes. The address of AF_INET remotes are | |
162 | + * mapped to AF_INET6 automatically by the network layer. In case the | |
163 | + * user passed an AF_INET server address at mount time, ensure both | |
164 | + * addresses are AF_INET6 before comparing them. | |
165 | + */ | |
166 | +static int nlmclnt_cmp_addr(const struct nlm_host *host, | |
167 | + const struct sockaddr *sap) | |
168 | +{ | |
169 | + const struct in6_addr *addr1; | |
170 | + const struct in6_addr *addr2; | |
171 | + struct in6_addr addr1_mapped; | |
172 | + struct in6_addr addr2_mapped; | |
173 | + | |
174 | + addr1 = nlmclnt_map_v4addr(nlm_addr(host), &addr1_mapped); | |
175 | + if (likely(addr1 != NULL)) { | |
176 | + addr2 = nlmclnt_map_v4addr(sap, &addr2_mapped); | |
177 | + if (likely(addr2 != NULL)) | |
178 | + return ipv6_addr_equal(addr1, addr2); | |
179 | + } | |
180 | + | |
181 | + return 0; | |
182 | +} | |
183 | +#else /* !(CONFIG_IPV6 || CONFIG_IPV6_MODULE) */ | |
184 | +static int nlmclnt_cmp_addr(const struct nlm_host *host, | |
185 | + const struct sockaddr *sap) | |
186 | +{ | |
187 | + return nlm_cmp_addr(nlm_addr(host), sap); | |
188 | +} | |
189 | +#endif /* !(CONFIG_IPV6 || CONFIG_IPV6_MODULE) */ | |
190 | + | |
191 | +/* | |
143 | 192 | * The server lockd has called us back to tell us the lock was granted |
144 | 193 | */ |
145 | 194 | __be32 nlmclnt_grant(const struct sockaddr *addr, const struct nlm_lock *lock) |
... | ... | @@ -166,7 +215,7 @@ |
166 | 215 | */ |
167 | 216 | if (fl_blocked->fl_u.nfs_fl.owner->pid != lock->svid) |
168 | 217 | continue; |
169 | - if (!nlm_cmp_addr(nlm_addr(block->b_host), addr)) | |
218 | + if (!nlmclnt_cmp_addr(block->b_host, addr)) | |
170 | 219 | continue; |
171 | 220 | if (nfs_compare_fh(NFS_FH(fl_blocked->fl_file->f_path.dentry->d_inode) ,fh) != 0) |
172 | 221 | continue; |