Commit 57df675c60c5cf0748ddba9c7f85afde1530d74d

Authored by Chuck Lever
Committed by Trond Myklebust
1 parent 78851e1aa4

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

... ... @@ -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;