Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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 <chuck.lever@oracle.com>
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>

authored by

Chuck Lever and committed by
Trond Myklebust
c8407f2e 6c0a8c5f

+102 -15
+3 -3
fs/nfs/client.c
··· 463 463 464 464 switch (proto) { 465 465 case XPRT_TRANSPORT_TCP: 466 + case XPRT_TRANSPORT_TCP_TLS: 466 467 case XPRT_TRANSPORT_RDMA: 467 468 if (retrans == NFS_UNSPEC_RETRANS) 468 469 to->to_retries = NFS_DEF_TCP_RETRANS; ··· 516 515 .version = clp->rpc_ops->version, 517 516 .authflavor = flavor, 518 517 .cred = cl_init->cred, 518 + .xprtsec = cl_init->xprtsec, 519 519 }; 520 520 521 521 if (test_bit(NFS_CS_DISCRTRY, &clp->cl_flags)) ··· 682 680 .cred = server->cred, 683 681 .nconnect = ctx->nfs_server.nconnect, 684 682 .init_flags = (1UL << NFS_CS_REUSEPORT), 685 - .xprtsec = { 686 - .policy = RPC_XPRTSEC_NONE, 687 - }, 683 + .xprtsec = ctx->xprtsec, 688 684 }; 689 685 struct nfs_client *clp; 690 686 int error;
+62
fs/nfs/fs_context.c
··· 18 18 #include <linux/nfs_fs.h> 19 19 #include <linux/nfs_mount.h> 20 20 #include <linux/nfs4_mount.h> 21 + 22 + #include <net/handshake.h> 23 + 21 24 #include "nfs.h" 22 25 #include "internal.h" 23 26 ··· 91 88 Opt_vers, 92 89 Opt_wsize, 93 90 Opt_write, 91 + Opt_xprtsec, 94 92 }; 95 93 96 94 enum { ··· 198 194 fsparam_string("vers", Opt_vers), 199 195 fsparam_enum ("write", Opt_write, nfs_param_enums_write), 200 196 fsparam_u32 ("wsize", Opt_wsize), 197 + fsparam_string("xprtsec", Opt_xprtsec), 201 198 {} 202 199 }; 203 200 ··· 272 267 {} 273 268 }; 274 269 270 + enum { 271 + Opt_xprtsec_none, 272 + Opt_xprtsec_tls, 273 + Opt_xprtsec_mtls, 274 + nr__Opt_xprtsec 275 + }; 276 + 277 + static const struct constant_table nfs_xprtsec_policies[] = { 278 + { "none", Opt_xprtsec_none }, 279 + { "tls", Opt_xprtsec_tls }, 280 + { "mtls", Opt_xprtsec_mtls }, 281 + {} 282 + }; 283 + 275 284 /* 276 285 * Sanity-check a server address provided by the mount command. 277 286 * ··· 339 320 default: 340 321 ctx->nfs_server.protocol = XPRT_TRANSPORT_TCP; 341 322 } 323 + 324 + if (ctx->xprtsec.policy != RPC_XPRTSEC_NONE) 325 + switch (ctx->nfs_server.protocol) { 326 + case XPRT_TRANSPORT_TCP: 327 + ctx->nfs_server.protocol = XPRT_TRANSPORT_TCP_TLS; 328 + break; 329 + default: 330 + goto out_invalid_xprtsec_policy; 331 + } 332 + 342 333 return 0; 343 334 out_invalid_transport_udp: 344 335 return nfs_invalf(fc, "NFS: Unsupported transport protocol udp"); 336 + out_invalid_xprtsec_policy: 337 + return nfs_invalf(fc, "NFS: Transport does not support xprtsec"); 345 338 } 346 339 347 340 /* ··· 458 427 return ret; 459 428 } 460 429 430 + return 0; 431 + } 432 + 433 + static int nfs_parse_xprtsec_policy(struct fs_context *fc, 434 + struct fs_parameter *param) 435 + { 436 + struct nfs_fs_context *ctx = nfs_fc2context(fc); 437 + 438 + trace_nfs_mount_assign(param->key, param->string); 439 + 440 + switch (lookup_constant(nfs_xprtsec_policies, param->string, -1)) { 441 + case Opt_xprtsec_none: 442 + ctx->xprtsec.policy = RPC_XPRTSEC_NONE; 443 + break; 444 + case Opt_xprtsec_tls: 445 + ctx->xprtsec.policy = RPC_XPRTSEC_TLS_ANON; 446 + break; 447 + case Opt_xprtsec_mtls: 448 + ctx->xprtsec.policy = RPC_XPRTSEC_TLS_X509; 449 + break; 450 + default: 451 + return nfs_invalf(fc, "NFS: Unrecognized transport security policy"); 452 + } 461 453 return 0; 462 454 } 463 455 ··· 747 693 break; 748 694 case Opt_sec: 749 695 ret = nfs_parse_security_flavors(fc, param); 696 + if (ret < 0) 697 + return ret; 698 + break; 699 + case Opt_xprtsec: 700 + ret = nfs_parse_xprtsec_policy(fc, param); 750 701 if (ret < 0) 751 702 return ret; 752 703 break; ··· 1633 1574 ctx->selected_flavor = RPC_AUTH_MAXFLAVOR; 1634 1575 ctx->minorversion = 0; 1635 1576 ctx->need_mount = true; 1577 + ctx->xprtsec.policy = RPC_XPRTSEC_NONE; 1578 + ctx->xprtsec.cert_serial = TLS_NO_CERT; 1579 + ctx->xprtsec.privkey_serial = TLS_NO_PRIVKEY; 1636 1580 1637 1581 fc->s_iflags |= SB_I_STABLE_WRITES; 1638 1582 }
+1
fs/nfs/internal.h
··· 102 102 unsigned int bsize; 103 103 struct nfs_auth_info auth_info; 104 104 rpc_authflavor_t selected_flavor; 105 + struct xprtsec_parms xprtsec; 105 106 char *client_address; 106 107 unsigned int version; 107 108 unsigned int minorversion;
+6 -2
fs/nfs/nfs3client.c
··· 103 103 return ERR_PTR(-EINVAL); 104 104 cl_init.hostname = buf; 105 105 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 + } 108 112 109 113 if (mds_srv->flags & NFS_MOUNT_NORESVPORT) 110 114 __set_bit(NFS_CS_NORESVPORT, &cl_init.init_flags);
+18 -10
fs/nfs/nfs4client.c
··· 918 918 __set_bit(NFS_CS_REUSEPORT, &cl_init.init_flags); 919 919 else 920 920 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: 922 924 cl_init.nconnect = nconnect; 925 + } 923 926 924 927 if (server->flags & NFS_MOUNT_NORESVPORT) 925 928 __set_bit(NFS_CS_NORESVPORT, &cl_init.init_flags); ··· 991 988 return ERR_PTR(-EINVAL); 992 989 cl_init.hostname = buf; 993 990 994 - if (mds_clp->cl_nconnect > 1 && ds_proto == XPRT_TRANSPORT_TCP) { 995 - cl_init.nconnect = mds_clp->cl_nconnect; 996 - cl_init.max_connect = NFS_MAX_TRANSPORTS; 991 + switch (ds_proto) { 992 + case XPRT_TRANSPORT_TCP: 993 + case XPRT_TRANSPORT_TCP_TLS: 994 + if (mds_clp->cl_nconnect > 1) { 995 + cl_init.nconnect = mds_clp->cl_nconnect; 996 + cl_init.max_connect = NFS_MAX_TRANSPORTS; 997 + } 997 998 } 998 999 999 1000 if (mds_srv->flags & NFS_MOUNT_NORESVPORT) ··· 1137 1130 static int nfs4_init_server(struct nfs_server *server, struct fs_context *fc) 1138 1131 { 1139 1132 struct nfs_fs_context *ctx = nfs_fc2context(fc); 1140 - struct xprtsec_parms xprtsec = { 1141 - .policy = RPC_XPRTSEC_NONE, 1142 - }; 1143 1133 struct rpc_timeout timeparms; 1144 1134 int error; 1145 1135 ··· 1168 1164 ctx->nfs_server.nconnect, 1169 1165 ctx->nfs_server.max_connect, 1170 1166 fc->net_ns, 1171 - &xprtsec); 1167 + &ctx->xprtsec); 1172 1168 if (error < 0) 1173 1169 return error; 1174 1170 ··· 1230 1226 struct nfs_fs_context *ctx = nfs_fc2context(fc); 1231 1227 struct nfs_client *parent_client; 1232 1228 struct nfs_server *server, *parent_server; 1229 + int proto, error; 1233 1230 bool auth_probe; 1234 - int error; 1235 1231 1236 1232 server = nfs_alloc_server(); 1237 1233 if (!server) ··· 1264 1260 goto init_server; 1265 1261 #endif /* IS_ENABLED(CONFIG_SUNRPC_XPRT_RDMA) */ 1266 1262 1263 + proto = XPRT_TRANSPORT_TCP; 1264 + if (parent_client->cl_xprtsec.policy != RPC_XPRTSEC_NONE) 1265 + proto = XPRT_TRANSPORT_TCP_TLS; 1267 1266 rpc_set_port(&ctx->nfs_server.address, NFS_PORT); 1268 1267 error = nfs4_set_client(server, 1269 1268 ctx->nfs_server.hostname, 1270 1269 &ctx->nfs_server._address, 1271 1270 ctx->nfs_server.addrlen, 1272 1271 parent_client->cl_ipaddr, 1273 - XPRT_TRANSPORT_TCP, 1272 + proto, 1274 1273 parent_server->client->cl_timeout, 1275 1274 parent_client->cl_mvops->minor_version, 1276 1275 parent_client->cl_nconnect, ··· 1330 1323 .dstaddr = (struct sockaddr *)sap, 1331 1324 .addrlen = salen, 1332 1325 .servername = hostname, 1326 + /* cel: bleh. We might need to pass TLS parameters here */ 1333 1327 }; 1334 1328 char buf[INET6_ADDRSTRLEN + 1]; 1335 1329 struct sockaddr_storage address;
+12
fs/nfs/super.c
··· 59 59 #include <linux/uaccess.h> 60 60 #include <linux/nfs_ssc.h> 61 61 62 + #include <uapi/linux/tls.h> 63 + 62 64 #include "nfs4_fs.h" 63 65 #include "callback.h" 64 66 #include "delegation.h" ··· 493 491 seq_printf(m, ",timeo=%lu", 10U * nfss->client->cl_timeout->to_initval / HZ); 494 492 seq_printf(m, ",retrans=%u", nfss->client->cl_timeout->to_retries); 495 493 seq_printf(m, ",sec=%s", nfs_pseudoflavour_to_name(nfss->client->cl_auth->au_flavor)); 494 + switch (clp->cl_xprtsec.policy) { 495 + case RPC_XPRTSEC_TLS_ANON: 496 + seq_puts(m, ",xprtsec=tls"); 497 + break; 498 + case RPC_XPRTSEC_TLS_X509: 499 + seq_puts(m, ",xprtsec=mtls"); 500 + break; 501 + default: 502 + break; 503 + } 496 504 497 505 if (version != 4) 498 506 nfs_show_mountd_options(m, nfss, showdefaults);