Skip to content

Commit 74fd487

Browse files
jtlaytonchucklever
authored andcommitted
nfsd: new Kconfig option for legacy client tracking
We've had a number of attempts at different NFSv4 client tracking methods over the years, but now nfsdcld has emerged as the clear winner since the others (recoverydir and the usermodehelper upcall) are problematic. As a case in point, the recoverydir backend uses MD5 hashes to encode long form clientid strings, which means that nfsd repeatedly gets dinged on FIPS audits, since MD5 isn't considered secure. Its use of MD5 is not cryptographically significant, so there is no danger there, but allowing us to compile that out allows us to sidestep the issue entirely. As a prelude to eventually removing support for these client tracking methods, add a new Kconfig option that enables them. Mark it deprecated and make it default to N. Acked-by: NeilBrown <neilb@suse.de> Signed-off-by: Jeff Layton <jlayton@kernel.org> Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
1 parent 0dd3ee3 commit 74fd487

File tree

3 files changed

+85
-34
lines changed

3 files changed

+85
-34
lines changed

fs/nfsd/Kconfig

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,3 +158,19 @@ config NFSD_V4_SECURITY_LABEL
158158

159159
If you do not wish to enable fine-grained security labels SELinux or
160160
Smack policies on NFSv4 files, say N.
161+
162+
config NFSD_LEGACY_CLIENT_TRACKING
163+
bool "Support legacy NFSv4 client tracking methods (DEPRECATED)"
164+
depends on NFSD_V4
165+
default n
166+
help
167+
The NFSv4 server needs to store a small amount of information on
168+
stable storage in order to handle state recovery after reboot. Most
169+
modern deployments upcall to a userland daemon for this (nfsdcld),
170+
but older NFS servers may store information directly in a
171+
recoverydir, or spawn a process directly using a usermodehelper
172+
upcall.
173+
174+
These legacy client tracking methods have proven to be probelmatic
175+
and will be removed in the future. Say Y here if you need support
176+
for them in the interim.

fs/nfsd/nfs4recover.c

Lines changed: 63 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ struct nfsd4_client_tracking_ops {
6666
static const struct nfsd4_client_tracking_ops nfsd4_cld_tracking_ops;
6767
static const struct nfsd4_client_tracking_ops nfsd4_cld_tracking_ops_v2;
6868

69+
#ifdef CONFIG_NFSD_LEGACY_CLIENT_TRACKING
6970
/* Globals */
7071
static char user_recovery_dirname[PATH_MAX] = "/var/lib/nfs/v4recovery";
7172

@@ -720,6 +721,7 @@ static const struct nfsd4_client_tracking_ops nfsd4_legacy_tracking_ops = {
720721
.version = 1,
721722
.msglen = 0,
722723
};
724+
#endif /* CONFIG_NFSD_LEGACY_CLIENT_TRACKING */
723725

724726
/* Globals */
725727
#define NFSD_PIPE_DIR "nfsd"
@@ -731,8 +733,10 @@ struct cld_net {
731733
spinlock_t cn_lock;
732734
struct list_head cn_list;
733735
unsigned int cn_xid;
734-
bool cn_has_legacy;
735736
struct crypto_shash *cn_tfm;
737+
#ifdef CONFIG_NFSD_LEGACY_CLIENT_TRACKING
738+
bool cn_has_legacy;
739+
#endif
736740
};
737741

738742
struct cld_upcall {
@@ -793,7 +797,6 @@ __cld_pipe_inprogress_downcall(const struct cld_msg_v2 __user *cmsg,
793797
uint8_t cmd, princhashlen;
794798
struct xdr_netobj name, princhash = { .len = 0, .data = NULL };
795799
uint16_t namelen;
796-
struct cld_net *cn = nn->cld_net;
797800

798801
if (get_user(cmd, &cmsg->cm_cmd)) {
799802
dprintk("%s: error when copying cmd from userspace", __func__);
@@ -833,11 +836,15 @@ __cld_pipe_inprogress_downcall(const struct cld_msg_v2 __user *cmsg,
833836
return PTR_ERR(name.data);
834837
name.len = namelen;
835838
}
839+
#ifdef CONFIG_NFSD_LEGACY_CLIENT_TRACKING
836840
if (name.len > 5 && memcmp(name.data, "hash:", 5) == 0) {
841+
struct cld_net *cn = nn->cld_net;
842+
837843
name.len = name.len - 5;
838844
memmove(name.data, name.data + 5, name.len);
839845
cn->cn_has_legacy = true;
840846
}
847+
#endif
841848
if (!nfs4_client_to_reclaim(name, princhash, nn)) {
842849
kfree(name.data);
843850
kfree(princhash.data);
@@ -1010,7 +1017,9 @@ __nfsd4_init_cld_pipe(struct net *net)
10101017
}
10111018

10121019
cn->cn_pipe->dentry = dentry;
1020+
#ifdef CONFIG_NFSD_LEGACY_CLIENT_TRACKING
10131021
cn->cn_has_legacy = false;
1022+
#endif
10141023
nn->cld_net = cn;
10151024
return 0;
10161025

@@ -1282,10 +1291,6 @@ nfsd4_cld_check(struct nfs4_client *clp)
12821291
{
12831292
struct nfs4_client_reclaim *crp;
12841293
struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
1285-
struct cld_net *cn = nn->cld_net;
1286-
int status;
1287-
char dname[HEXDIR_LEN];
1288-
struct xdr_netobj name;
12891294

12901295
/* did we already find that this client is stable? */
12911296
if (test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags))
@@ -1296,7 +1301,12 @@ nfsd4_cld_check(struct nfs4_client *clp)
12961301
if (crp)
12971302
goto found;
12981303

1299-
if (cn->cn_has_legacy) {
1304+
#ifdef CONFIG_NFSD_LEGACY_CLIENT_TRACKING
1305+
if (nn->cld_net->cn_has_legacy) {
1306+
int status;
1307+
char dname[HEXDIR_LEN];
1308+
struct xdr_netobj name;
1309+
13001310
status = nfs4_make_rec_clidname(dname, &clp->cl_name);
13011311
if (status)
13021312
return -ENOENT;
@@ -1314,6 +1324,7 @@ nfsd4_cld_check(struct nfs4_client *clp)
13141324
goto found;
13151325

13161326
}
1327+
#endif
13171328
return -ENOENT;
13181329
found:
13191330
crp->cr_clp = clp;
@@ -1327,8 +1338,6 @@ nfsd4_cld_check_v2(struct nfs4_client *clp)
13271338
struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
13281339
struct cld_net *cn = nn->cld_net;
13291340
int status;
1330-
char dname[HEXDIR_LEN];
1331-
struct xdr_netobj name;
13321341
struct crypto_shash *tfm = cn->cn_tfm;
13331342
struct xdr_netobj cksum;
13341343
char *principal = NULL;
@@ -1342,7 +1351,11 @@ nfsd4_cld_check_v2(struct nfs4_client *clp)
13421351
if (crp)
13431352
goto found;
13441353

1354+
#ifdef CONFIG_NFSD_LEGACY_CLIENT_TRACKING
13451355
if (cn->cn_has_legacy) {
1356+
struct xdr_netobj name;
1357+
char dname[HEXDIR_LEN];
1358+
13461359
status = nfs4_make_rec_clidname(dname, &clp->cl_name);
13471360
if (status)
13481361
return -ENOENT;
@@ -1360,6 +1373,7 @@ nfsd4_cld_check_v2(struct nfs4_client *clp)
13601373
goto found;
13611374

13621375
}
1376+
#endif
13631377
return -ENOENT;
13641378
found:
13651379
if (crp->cr_princhash.len) {
@@ -1663,6 +1677,7 @@ static const struct nfsd4_client_tracking_ops nfsd4_cld_tracking_ops_v2 = {
16631677
.msglen = sizeof(struct cld_msg_v2),
16641678
};
16651679

1680+
#ifdef CONFIG_NFSD_LEGACY_CLIENT_TRACKING
16661681
/* upcall via usermodehelper */
16671682
static char cltrack_prog[PATH_MAX] = "/sbin/nfsdcltrack";
16681683
module_param_string(cltrack_prog, cltrack_prog, sizeof(cltrack_prog),
@@ -2007,28 +2022,10 @@ static const struct nfsd4_client_tracking_ops nfsd4_umh_tracking_ops = {
20072022
.msglen = 0,
20082023
};
20092024

2010-
int
2011-
nfsd4_client_tracking_init(struct net *net)
2025+
static inline int check_for_legacy_methods(int status, struct net *net)
20122026
{
2013-
int status;
2014-
struct path path;
20152027
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
2016-
2017-
/* just run the init if it the method is already decided */
2018-
if (nn->client_tracking_ops)
2019-
goto do_init;
2020-
2021-
/* First, try to use nfsdcld */
2022-
nn->client_tracking_ops = &nfsd4_cld_tracking_ops;
2023-
status = nn->client_tracking_ops->init(net);
2024-
if (!status)
2025-
return status;
2026-
if (status != -ETIMEDOUT) {
2027-
nn->client_tracking_ops = &nfsd4_cld_tracking_ops_v0;
2028-
status = nn->client_tracking_ops->init(net);
2029-
if (!status)
2030-
return status;
2031-
}
2028+
struct path path;
20322029

20332030
/*
20342031
* Next, try the UMH upcall.
@@ -2045,14 +2042,46 @@ nfsd4_client_tracking_init(struct net *net)
20452042
nn->client_tracking_ops = &nfsd4_legacy_tracking_ops;
20462043
status = kern_path(nfs4_recoverydir(), LOOKUP_FOLLOW, &path);
20472044
if (!status) {
2048-
status = d_is_dir(path.dentry);
2045+
status = !d_is_dir(path.dentry);
20492046
path_put(&path);
2050-
if (!status) {
2051-
status = -EINVAL;
2052-
goto out;
2053-
}
2047+
if (status)
2048+
return -ENOTDIR;
2049+
status = nn->client_tracking_ops->init(net);
2050+
}
2051+
return status;
2052+
}
2053+
#else
2054+
static inline int check_for_legacy_methods(int status, struct net *net)
2055+
{
2056+
return status;
2057+
}
2058+
#endif /* CONFIG_LEGACY_NFSD_CLIENT_TRACKING */
2059+
2060+
int
2061+
nfsd4_client_tracking_init(struct net *net)
2062+
{
2063+
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
2064+
int status;
2065+
2066+
/* just run the init if it the method is already decided */
2067+
if (nn->client_tracking_ops)
2068+
goto do_init;
2069+
2070+
/* First, try to use nfsdcld */
2071+
nn->client_tracking_ops = &nfsd4_cld_tracking_ops;
2072+
status = nn->client_tracking_ops->init(net);
2073+
if (!status)
2074+
return status;
2075+
if (status != -ETIMEDOUT) {
2076+
nn->client_tracking_ops = &nfsd4_cld_tracking_ops_v0;
2077+
status = nn->client_tracking_ops->init(net);
2078+
if (!status)
2079+
return status;
20542080
}
20552081

2082+
status = check_for_legacy_methods(status, net);
2083+
if (status)
2084+
goto out;
20562085
do_init:
20572086
status = nn->client_tracking_ops->init(net);
20582087
out:

fs/nfsd/nfsctl.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,9 @@ static ssize_t write_maxconn(struct file *file, char *buf, size_t size);
7676
#ifdef CONFIG_NFSD_V4
7777
static ssize_t write_leasetime(struct file *file, char *buf, size_t size);
7878
static ssize_t write_gracetime(struct file *file, char *buf, size_t size);
79+
#ifdef CONFIG_NFSD_LEGACY_CLIENT_TRACKING
7980
static ssize_t write_recoverydir(struct file *file, char *buf, size_t size);
81+
#endif
8082
static ssize_t write_v4_end_grace(struct file *file, char *buf, size_t size);
8183
#endif
8284

@@ -93,7 +95,9 @@ static ssize_t (*const write_op[])(struct file *, char *, size_t) = {
9395
#ifdef CONFIG_NFSD_V4
9496
[NFSD_Leasetime] = write_leasetime,
9597
[NFSD_Gracetime] = write_gracetime,
98+
#ifdef CONFIG_NFSD_LEGACY_CLIENT_TRACKING
9699
[NFSD_RecoveryDir] = write_recoverydir,
100+
#endif
97101
[NFSD_V4EndGrace] = write_v4_end_grace,
98102
#endif
99103
};
@@ -1021,6 +1025,7 @@ static ssize_t write_gracetime(struct file *file, char *buf, size_t size)
10211025
return nfsd4_write_time(file, buf, size, &nn->nfsd4_grace, nn);
10221026
}
10231027

1028+
#ifdef CONFIG_NFSD_LEGACY_CLIENT_TRACKING
10241029
static ssize_t __write_recoverydir(struct file *file, char *buf, size_t size,
10251030
struct nfsd_net *nn)
10261031
{
@@ -1081,6 +1086,7 @@ static ssize_t write_recoverydir(struct file *file, char *buf, size_t size)
10811086
mutex_unlock(&nfsd_mutex);
10821087
return rv;
10831088
}
1089+
#endif
10841090

10851091
/*
10861092
* write_v4_end_grace - release grace period for nfsd's v4.x lock manager

0 commit comments

Comments
 (0)