Skip to content

Commit

Permalink
NFSv4.0: Remove cl_ipaddr from non-UCS client ID
Browse files Browse the repository at this point in the history
It is possible for two distinct clients to have the same cl_ipaddr:

 - if the client admin disables callback with clientaddr=0.0.0.0 on
   more than one client

 - if two clients behind separate NATs use the same private subnet
   number

 - if the client admin specifies the same address via clientaddr=
   mount option (pointing the server at the same NAT box, for
   example)

Because of the way the Linux NFSv4.0 client constructs its client
ID string by default, such clients could interfere with each others'
lease state when mounting the same server:

	scnprintf(str, len, "Linux NFSv4.0 %s/%s %s",
		clp->cl_ipaddr,
		rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_ADDR),
		rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_PROTO));

cl_ipaddr is set to the value of the clientaddr= mount option. Two
clients whose addresses are 192.168.3.77 that mount the same server
(whose public IP address is, say, 3.4.5.6) would both generate the
same client ID string when sending a SETCLIENTID:

  Linux NFSv4.0 192.168.3.77/3.4.5.6 tcp

and thus the server would not be able to distinguish the clients'
leases. If both clients are using AUTH_SYS when sending SETCLIENTID
then the server could possibly permit the two clients to interfere
with or purge each others' leases.

To better ensure that Linux's NFSv4.0 client ID strings are distinct
in these cases, remove cl_ipaddr from the client ID string and
replace it with something more likely to be unique. Note that the
replacement looks a lot like the uniform client ID string.

Signed-off-by: Chuck Lever <[email protected]>
Signed-off-by: Trond Myklebust <[email protected]>
  • Loading branch information
chucklever authored and Trond Myklebust committed Jun 6, 2018
1 parent 977294c commit 848a4eb
Showing 1 changed file with 20 additions and 6 deletions.
26 changes: 20 additions & 6 deletions fs/nfs/nfs4proc.c
Original file line number Diff line number Diff line change
Expand Up @@ -5618,13 +5618,16 @@ nfs4_init_nonuniform_client_string(struct nfs_client *clp)
return 0;

rcu_read_lock();
len = 14 + strlen(clp->cl_ipaddr) + 1 +
len = 14 +
strlen(clp->cl_rpcclient->cl_nodename) +
1 +
strlen(rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_ADDR)) +
1 +
strlen(rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_PROTO)) +
1;
rcu_read_unlock();

if (nfs4_client_id_uniquifier[0] != '\0')
len += strlen(nfs4_client_id_uniquifier) + 1;
if (len > NFS4_OPAQUE_LIMIT + 1)
return -EINVAL;

Expand All @@ -5638,10 +5641,21 @@ nfs4_init_nonuniform_client_string(struct nfs_client *clp)
return -ENOMEM;

rcu_read_lock();
scnprintf(str, len, "Linux NFSv4.0 %s/%s %s",
clp->cl_ipaddr,
rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_ADDR),
rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_PROTO));
if (nfs4_client_id_uniquifier[0] != '\0')
scnprintf(str, len, "Linux NFSv4.0 %s/%s/%s %s",
clp->cl_rpcclient->cl_nodename,
nfs4_client_id_uniquifier,
rpc_peeraddr2str(clp->cl_rpcclient,
RPC_DISPLAY_ADDR),
rpc_peeraddr2str(clp->cl_rpcclient,
RPC_DISPLAY_PROTO));
else
scnprintf(str, len, "Linux NFSv4.0 %s/%s %s",
clp->cl_rpcclient->cl_nodename,
rpc_peeraddr2str(clp->cl_rpcclient,
RPC_DISPLAY_ADDR),
rpc_peeraddr2str(clp->cl_rpcclient,
RPC_DISPLAY_PROTO));
rcu_read_unlock();

clp->cl_owner_id = str;
Expand Down

0 comments on commit 848a4eb

Please sign in to comment.