Skip to content

Commit c8407f2

Browse files
chuckleverTrond Myklebust
authored andcommitted
NFS: Add an "xprtsec=" NFS mount option
After some discussion, we decided that controlling transport layer security policy should be separate from the setting for the user authentication flavor. To accomplish this, add a new NFS mount option to select a transport layer security policy for RPC operations associated with the mount point. xprtsec=none - Transport layer security is forced off. xprtsec=tls - Establish an encryption-only TLS session. If the initial handshake fails, the mount fails. If TLS is not available on a reconnect, drop the connection and try again. xprtsec=mtls - Both sides authenticate and an encrypted session is created. If the initial handshake fails, the mount fails. If TLS is not available on a reconnect, drop the connection and try again. To support client peer authentication (mtls), the handshake daemon will have configurable default authentication material (certificate or pre-shared key). In the future, mount options can be added that can provide this material on a per-mount basis. Updates to mount.nfs (to support xprtsec=auto) and nfs(5) will be sent under separate cover. Signed-off-by: Chuck Lever <[email protected]> Signed-off-by: Trond Myklebust <[email protected]>
1 parent 6c0a8c5 commit c8407f2

File tree

6 files changed

+102
-15
lines changed

6 files changed

+102
-15
lines changed

fs/nfs/client.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -463,6 +463,7 @@ void nfs_init_timeout_values(struct rpc_timeout *to, int proto,
463463

464464
switch (proto) {
465465
case XPRT_TRANSPORT_TCP:
466+
case XPRT_TRANSPORT_TCP_TLS:
466467
case XPRT_TRANSPORT_RDMA:
467468
if (retrans == NFS_UNSPEC_RETRANS)
468469
to->to_retries = NFS_DEF_TCP_RETRANS;
@@ -515,6 +516,7 @@ int nfs_create_rpc_client(struct nfs_client *clp,
515516
.version = clp->rpc_ops->version,
516517
.authflavor = flavor,
517518
.cred = cl_init->cred,
519+
.xprtsec = cl_init->xprtsec,
518520
};
519521

520522
if (test_bit(NFS_CS_DISCRTRY, &clp->cl_flags))
@@ -680,9 +682,7 @@ static int nfs_init_server(struct nfs_server *server,
680682
.cred = server->cred,
681683
.nconnect = ctx->nfs_server.nconnect,
682684
.init_flags = (1UL << NFS_CS_REUSEPORT),
683-
.xprtsec = {
684-
.policy = RPC_XPRTSEC_NONE,
685-
},
685+
.xprtsec = ctx->xprtsec,
686686
};
687687
struct nfs_client *clp;
688688
int error;

fs/nfs/fs_context.c

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@
1818
#include <linux/nfs_fs.h>
1919
#include <linux/nfs_mount.h>
2020
#include <linux/nfs4_mount.h>
21+
22+
#include <net/handshake.h>
23+
2124
#include "nfs.h"
2225
#include "internal.h"
2326

@@ -88,6 +91,7 @@ enum nfs_param {
8891
Opt_vers,
8992
Opt_wsize,
9093
Opt_write,
94+
Opt_xprtsec,
9195
};
9296

9397
enum {
@@ -194,6 +198,7 @@ static const struct fs_parameter_spec nfs_fs_parameters[] = {
194198
fsparam_string("vers", Opt_vers),
195199
fsparam_enum ("write", Opt_write, nfs_param_enums_write),
196200
fsparam_u32 ("wsize", Opt_wsize),
201+
fsparam_string("xprtsec", Opt_xprtsec),
197202
{}
198203
};
199204

@@ -267,6 +272,20 @@ static const struct constant_table nfs_secflavor_tokens[] = {
267272
{}
268273
};
269274

275+
enum {
276+
Opt_xprtsec_none,
277+
Opt_xprtsec_tls,
278+
Opt_xprtsec_mtls,
279+
nr__Opt_xprtsec
280+
};
281+
282+
static const struct constant_table nfs_xprtsec_policies[] = {
283+
{ "none", Opt_xprtsec_none },
284+
{ "tls", Opt_xprtsec_tls },
285+
{ "mtls", Opt_xprtsec_mtls },
286+
{}
287+
};
288+
270289
/*
271290
* Sanity-check a server address provided by the mount command.
272291
*
@@ -320,9 +339,21 @@ static int nfs_validate_transport_protocol(struct fs_context *fc,
320339
default:
321340
ctx->nfs_server.protocol = XPRT_TRANSPORT_TCP;
322341
}
342+
343+
if (ctx->xprtsec.policy != RPC_XPRTSEC_NONE)
344+
switch (ctx->nfs_server.protocol) {
345+
case XPRT_TRANSPORT_TCP:
346+
ctx->nfs_server.protocol = XPRT_TRANSPORT_TCP_TLS;
347+
break;
348+
default:
349+
goto out_invalid_xprtsec_policy;
350+
}
351+
323352
return 0;
324353
out_invalid_transport_udp:
325354
return nfs_invalf(fc, "NFS: Unsupported transport protocol udp");
355+
out_invalid_xprtsec_policy:
356+
return nfs_invalf(fc, "NFS: Transport does not support xprtsec");
326357
}
327358

328359
/*
@@ -430,6 +461,29 @@ static int nfs_parse_security_flavors(struct fs_context *fc,
430461
return 0;
431462
}
432463

464+
static int nfs_parse_xprtsec_policy(struct fs_context *fc,
465+
struct fs_parameter *param)
466+
{
467+
struct nfs_fs_context *ctx = nfs_fc2context(fc);
468+
469+
trace_nfs_mount_assign(param->key, param->string);
470+
471+
switch (lookup_constant(nfs_xprtsec_policies, param->string, -1)) {
472+
case Opt_xprtsec_none:
473+
ctx->xprtsec.policy = RPC_XPRTSEC_NONE;
474+
break;
475+
case Opt_xprtsec_tls:
476+
ctx->xprtsec.policy = RPC_XPRTSEC_TLS_ANON;
477+
break;
478+
case Opt_xprtsec_mtls:
479+
ctx->xprtsec.policy = RPC_XPRTSEC_TLS_X509;
480+
break;
481+
default:
482+
return nfs_invalf(fc, "NFS: Unrecognized transport security policy");
483+
}
484+
return 0;
485+
}
486+
433487
static int nfs_parse_version_string(struct fs_context *fc,
434488
const char *string)
435489
{
@@ -696,6 +750,11 @@ static int nfs_fs_context_parse_param(struct fs_context *fc,
696750
if (ret < 0)
697751
return ret;
698752
break;
753+
case Opt_xprtsec:
754+
ret = nfs_parse_xprtsec_policy(fc, param);
755+
if (ret < 0)
756+
return ret;
757+
break;
699758

700759
case Opt_proto:
701760
if (!param->string)
@@ -1574,6 +1633,9 @@ static int nfs_init_fs_context(struct fs_context *fc)
15741633
ctx->selected_flavor = RPC_AUTH_MAXFLAVOR;
15751634
ctx->minorversion = 0;
15761635
ctx->need_mount = true;
1636+
ctx->xprtsec.policy = RPC_XPRTSEC_NONE;
1637+
ctx->xprtsec.cert_serial = TLS_NO_CERT;
1638+
ctx->xprtsec.privkey_serial = TLS_NO_PRIVKEY;
15771639

15781640
fc->s_iflags |= SB_I_STABLE_WRITES;
15791641
}

fs/nfs/internal.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ struct nfs_fs_context {
102102
unsigned int bsize;
103103
struct nfs_auth_info auth_info;
104104
rpc_authflavor_t selected_flavor;
105+
struct xprtsec_parms xprtsec;
105106
char *client_address;
106107
unsigned int version;
107108
unsigned int minorversion;

fs/nfs/nfs3client.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,8 +103,12 @@ struct nfs_client *nfs3_set_ds_client(struct nfs_server *mds_srv,
103103
return ERR_PTR(-EINVAL);
104104
cl_init.hostname = buf;
105105

106-
if (mds_clp->cl_nconnect > 1 && ds_proto == XPRT_TRANSPORT_TCP)
107-
cl_init.nconnect = mds_clp->cl_nconnect;
106+
switch (ds_proto) {
107+
case XPRT_TRANSPORT_TCP:
108+
case XPRT_TRANSPORT_TCP_TLS:
109+
if (mds_clp->cl_nconnect > 1)
110+
cl_init.nconnect = mds_clp->cl_nconnect;
111+
}
108112

109113
if (mds_srv->flags & NFS_MOUNT_NORESVPORT)
110114
__set_bit(NFS_CS_NORESVPORT, &cl_init.init_flags);

fs/nfs/nfs4client.c

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -918,8 +918,11 @@ static int nfs4_set_client(struct nfs_server *server,
918918
__set_bit(NFS_CS_REUSEPORT, &cl_init.init_flags);
919919
else
920920
cl_init.max_connect = max_connect;
921-
if (proto == XPRT_TRANSPORT_TCP)
921+
switch (proto) {
922+
case XPRT_TRANSPORT_TCP:
923+
case XPRT_TRANSPORT_TCP_TLS:
922924
cl_init.nconnect = nconnect;
925+
}
923926

924927
if (server->flags & NFS_MOUNT_NORESVPORT)
925928
__set_bit(NFS_CS_NORESVPORT, &cl_init.init_flags);
@@ -988,9 +991,13 @@ struct nfs_client *nfs4_set_ds_client(struct nfs_server *mds_srv,
988991
return ERR_PTR(-EINVAL);
989992
cl_init.hostname = buf;
990993

991-
if (mds_clp->cl_nconnect > 1 && ds_proto == XPRT_TRANSPORT_TCP) {
992-
cl_init.nconnect = mds_clp->cl_nconnect;
993-
cl_init.max_connect = NFS_MAX_TRANSPORTS;
994+
switch (ds_proto) {
995+
case XPRT_TRANSPORT_TCP:
996+
case XPRT_TRANSPORT_TCP_TLS:
997+
if (mds_clp->cl_nconnect > 1) {
998+
cl_init.nconnect = mds_clp->cl_nconnect;
999+
cl_init.max_connect = NFS_MAX_TRANSPORTS;
1000+
}
9941001
}
9951002

9961003
if (mds_srv->flags & NFS_MOUNT_NORESVPORT)
@@ -1130,9 +1137,6 @@ static int nfs4_server_common_setup(struct nfs_server *server,
11301137
static int nfs4_init_server(struct nfs_server *server, struct fs_context *fc)
11311138
{
11321139
struct nfs_fs_context *ctx = nfs_fc2context(fc);
1133-
struct xprtsec_parms xprtsec = {
1134-
.policy = RPC_XPRTSEC_NONE,
1135-
};
11361140
struct rpc_timeout timeparms;
11371141
int error;
11381142

@@ -1164,7 +1168,7 @@ static int nfs4_init_server(struct nfs_server *server, struct fs_context *fc)
11641168
ctx->nfs_server.nconnect,
11651169
ctx->nfs_server.max_connect,
11661170
fc->net_ns,
1167-
&xprtsec);
1171+
&ctx->xprtsec);
11681172
if (error < 0)
11691173
return error;
11701174

@@ -1226,8 +1230,8 @@ struct nfs_server *nfs4_create_referral_server(struct fs_context *fc)
12261230
struct nfs_fs_context *ctx = nfs_fc2context(fc);
12271231
struct nfs_client *parent_client;
12281232
struct nfs_server *server, *parent_server;
1233+
int proto, error;
12291234
bool auth_probe;
1230-
int error;
12311235

12321236
server = nfs_alloc_server();
12331237
if (!server)
@@ -1260,13 +1264,16 @@ struct nfs_server *nfs4_create_referral_server(struct fs_context *fc)
12601264
goto init_server;
12611265
#endif /* IS_ENABLED(CONFIG_SUNRPC_XPRT_RDMA) */
12621266

1267+
proto = XPRT_TRANSPORT_TCP;
1268+
if (parent_client->cl_xprtsec.policy != RPC_XPRTSEC_NONE)
1269+
proto = XPRT_TRANSPORT_TCP_TLS;
12631270
rpc_set_port(&ctx->nfs_server.address, NFS_PORT);
12641271
error = nfs4_set_client(server,
12651272
ctx->nfs_server.hostname,
12661273
&ctx->nfs_server._address,
12671274
ctx->nfs_server.addrlen,
12681275
parent_client->cl_ipaddr,
1269-
XPRT_TRANSPORT_TCP,
1276+
proto,
12701277
parent_server->client->cl_timeout,
12711278
parent_client->cl_mvops->minor_version,
12721279
parent_client->cl_nconnect,
@@ -1323,6 +1330,7 @@ int nfs4_update_server(struct nfs_server *server, const char *hostname,
13231330
.dstaddr = (struct sockaddr *)sap,
13241331
.addrlen = salen,
13251332
.servername = hostname,
1333+
/* cel: bleh. We might need to pass TLS parameters here */
13261334
};
13271335
char buf[INET6_ADDRSTRLEN + 1];
13281336
struct sockaddr_storage address;

fs/nfs/super.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@
5959
#include <linux/uaccess.h>
6060
#include <linux/nfs_ssc.h>
6161

62+
#include <uapi/linux/tls.h>
63+
6264
#include "nfs4_fs.h"
6365
#include "callback.h"
6466
#include "delegation.h"
@@ -491,6 +493,16 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss,
491493
seq_printf(m, ",timeo=%lu", 10U * nfss->client->cl_timeout->to_initval / HZ);
492494
seq_printf(m, ",retrans=%u", nfss->client->cl_timeout->to_retries);
493495
seq_printf(m, ",sec=%s", nfs_pseudoflavour_to_name(nfss->client->cl_auth->au_flavor));
496+
switch (clp->cl_xprtsec.policy) {
497+
case RPC_XPRTSEC_TLS_ANON:
498+
seq_puts(m, ",xprtsec=tls");
499+
break;
500+
case RPC_XPRTSEC_TLS_X509:
501+
seq_puts(m, ",xprtsec=mtls");
502+
break;
503+
default:
504+
break;
505+
}
494506

495507
if (version != 4)
496508
nfs_show_mountd_options(m, nfss, showdefaults);

0 commit comments

Comments
 (0)