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.

SUNRPC: Support TLS handshake in the server-side TCP socket code

This patch adds opportunitistic RPC-with-TLS to the Linux in-kernel
NFS server. If the client requests RPC-with-TLS and the user space
handshake agent is running, the server will set up a TLS session.

There are no policy settings yet. For example, the server cannot
yet require the use of RPC-with-TLS to access its data.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>

+132 -8
+4 -1
include/linux/sunrpc/svc_xprt.h
··· 27 27 void (*xpo_detach)(struct svc_xprt *); 28 28 void (*xpo_free)(struct svc_xprt *); 29 29 void (*xpo_kill_temp_xprt)(struct svc_xprt *); 30 - void (*xpo_start_tls)(struct svc_xprt *); 30 + void (*xpo_handshake)(struct svc_xprt *xprt); 31 31 }; 32 32 33 33 struct svc_xprt_class { ··· 70 70 #define XPT_LOCAL 12 /* connection from loopback interface */ 71 71 #define XPT_KILL_TEMP 13 /* call xpo_kill_temp_xprt before closing */ 72 72 #define XPT_CONG_CTRL 14 /* has congestion control */ 73 + #define XPT_HANDSHAKE 15 /* xprt requests a handshake */ 74 + #define XPT_TLS_SESSION 16 /* transport-layer security established */ 75 + #define XPT_PEER_AUTH 17 /* peer has been authenticated */ 73 76 74 77 struct svc_serv *xpt_server; /* service for transport */ 75 78 atomic_t xpt_reserved; /* space on outq that is rsvd */
+2
include/linux/sunrpc/svcsock.h
··· 38 38 /* Number of queued send requests */ 39 39 atomic_t sk_sendqlen; 40 40 41 + struct completion sk_handshake_done; 42 + 41 43 struct page * sk_pages[RPCSVC_MAXPAGES]; /* received data */ 42 44 }; 43 45
+15 -1
include/trace/events/sunrpc.h
··· 1857 1857 { BIT(XPT_CACHE_AUTH), "CACHE_AUTH" }, \ 1858 1858 { BIT(XPT_LOCAL), "LOCAL" }, \ 1859 1859 { BIT(XPT_KILL_TEMP), "KILL_TEMP" }, \ 1860 - { BIT(XPT_CONG_CTRL), "CONG_CTRL" }) 1860 + { BIT(XPT_CONG_CTRL), "CONG_CTRL" }, \ 1861 + { BIT(XPT_HANDSHAKE), "HANDSHAKE" }, \ 1862 + { BIT(XPT_TLS_SESSION), "TLS_SESSION" }, \ 1863 + { BIT(XPT_PEER_AUTH), "PEER_AUTH" }) 1861 1864 1862 1865 TRACE_EVENT(svc_xprt_create_err, 1863 1866 TP_PROTO( ··· 1992 1989 DEFINE_SVC_XPRT_EVENT(close); 1993 1990 DEFINE_SVC_XPRT_EVENT(detach); 1994 1991 DEFINE_SVC_XPRT_EVENT(free); 1992 + 1993 + #define DEFINE_SVC_TLS_EVENT(name) \ 1994 + DEFINE_EVENT(svc_xprt_event, svc_tls_##name, \ 1995 + TP_PROTO(const struct svc_xprt *xprt), \ 1996 + TP_ARGS(xprt)) 1997 + 1998 + DEFINE_SVC_TLS_EVENT(start); 1999 + DEFINE_SVC_TLS_EVENT(upcall); 2000 + DEFINE_SVC_TLS_EVENT(unavailable); 2001 + DEFINE_SVC_TLS_EVENT(not_started); 2002 + DEFINE_SVC_TLS_EVENT(timed_out); 1995 2003 1996 2004 TRACE_EVENT(svc_xprt_accept, 1997 2005 TP_PROTO(
+4 -1
net/sunrpc/svc_xprt.c
··· 427 427 428 428 if (xpt_flags & BIT(XPT_BUSY)) 429 429 return false; 430 - if (xpt_flags & (BIT(XPT_CONN) | BIT(XPT_CLOSE))) 430 + if (xpt_flags & (BIT(XPT_CONN) | BIT(XPT_CLOSE) | BIT(XPT_HANDSHAKE))) 431 431 return true; 432 432 if (xpt_flags & (BIT(XPT_DATA) | BIT(XPT_DEFERRED))) { 433 433 if (xprt->xpt_ops->xpo_has_wspace(xprt) && ··· 827 827 } else { 828 828 module_put(xprt->xpt_class->xcl_owner); 829 829 } 830 + svc_xprt_received(xprt); 831 + } else if (test_bit(XPT_HANDSHAKE, &xprt->xpt_flags)) { 832 + xprt->xpt_ops->xpo_handshake(xprt); 830 833 svc_xprt_received(xprt); 831 834 } else if (svc_xprt_reserve_slot(rqstp, xprt)) { 832 835 /* XPT_DATA|XPT_DEFERRED case: */
+9 -2
net/sunrpc/svcauth_unix.c
··· 17 17 #include <net/ipv6.h> 18 18 #include <linux/kernel.h> 19 19 #include <linux/user_namespace.h> 20 - #define RPCDBG_FACILITY RPCDBG_AUTH 20 + #include <trace/events/sunrpc.h> 21 21 22 + #define RPCDBG_FACILITY RPCDBG_AUTH 22 23 23 24 #include "netns.h" 24 25 ··· 833 832 { 834 833 struct xdr_stream *xdr = &rqstp->rq_arg_stream; 835 834 struct svc_cred *cred = &rqstp->rq_cred; 835 + struct svc_xprt *xprt = rqstp->rq_xprt; 836 836 u32 flavor, len; 837 837 void *body; 838 838 __be32 *p; ··· 867 865 if (cred->cr_group_info == NULL) 868 866 return SVC_CLOSE; 869 867 870 - if (rqstp->rq_xprt->xpt_ops->xpo_start_tls) { 868 + if (xprt->xpt_ops->xpo_handshake) { 871 869 p = xdr_reserve_space(&rqstp->rq_res_stream, XDR_UNIT * 2 + 8); 872 870 if (!p) 873 871 return SVC_CLOSE; 872 + trace_svc_tls_start(xprt); 874 873 *p++ = rpc_auth_null; 875 874 *p++ = cpu_to_be32(8); 876 875 memcpy(p, "STARTTLS", 8); 876 + 877 + set_bit(XPT_HANDSHAKE, &xprt->xpt_flags); 878 + svc_xprt_enqueue(xprt); 877 879 } else { 880 + trace_svc_tls_unavailable(xprt); 878 881 if (xdr_stream_encode_opaque_auth(&rqstp->rq_res_stream, 879 882 RPC_AUTH_NULL, NULL, 0) < 0) 880 883 return SVC_CLOSE;
+98 -3
net/sunrpc/svcsock.c
··· 44 44 #include <net/tcp.h> 45 45 #include <net/tcp_states.h> 46 46 #include <net/tls.h> 47 + #include <net/handshake.h> 47 48 #include <linux/uaccess.h> 48 49 #include <linux/highmem.h> 49 50 #include <asm/ioctls.h> 51 + #include <linux/key.h> 50 52 51 53 #include <linux/sunrpc/types.h> 52 54 #include <linux/sunrpc/clnt.h> ··· 66 64 67 65 #define RPCDBG_FACILITY RPCDBG_SVCXPRT 68 66 67 + /* To-do: to avoid tying up an nfsd thread while waiting for a 68 + * handshake request, the request could instead be deferred. 69 + */ 70 + enum { 71 + SVC_HANDSHAKE_TO = 5U * HZ 72 + }; 69 73 70 74 static struct svc_sock *svc_setup_socket(struct svc_serv *, struct socket *, 71 75 int flags); ··· 367 359 rmb(); 368 360 svsk->sk_odata(sk); 369 361 trace_svcsock_data_ready(&svsk->sk_xprt, 0); 362 + if (test_bit(XPT_HANDSHAKE, &svsk->sk_xprt.xpt_flags)) 363 + return; 370 364 if (!test_and_set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags)) 371 365 svc_xprt_enqueue(&svsk->sk_xprt); 372 366 } ··· 404 394 struct svc_sock *svsk = container_of(xprt, struct svc_sock, sk_xprt); 405 395 406 396 sock_no_linger(svsk->sk_sock->sk); 397 + } 398 + 399 + /** 400 + * svc_tcp_handshake_done - Handshake completion handler 401 + * @data: address of xprt to wake 402 + * @status: status of handshake 403 + * @peerid: serial number of key containing the remote peer's identity 404 + * 405 + * If a security policy is specified as an export option, we don't 406 + * have a specific export here to check. So we set a "TLS session 407 + * is present" flag on the xprt and let an upper layer enforce local 408 + * security policy. 409 + */ 410 + static void svc_tcp_handshake_done(void *data, int status, key_serial_t peerid) 411 + { 412 + struct svc_xprt *xprt = data; 413 + struct svc_sock *svsk = container_of(xprt, struct svc_sock, sk_xprt); 414 + 415 + if (!status) { 416 + if (peerid != TLS_NO_PEERID) 417 + set_bit(XPT_PEER_AUTH, &xprt->xpt_flags); 418 + set_bit(XPT_TLS_SESSION, &xprt->xpt_flags); 419 + } 420 + clear_bit(XPT_HANDSHAKE, &xprt->xpt_flags); 421 + complete_all(&svsk->sk_handshake_done); 422 + } 423 + 424 + /** 425 + * svc_tcp_handshake - Perform a transport-layer security handshake 426 + * @xprt: connected transport endpoint 427 + * 428 + */ 429 + static void svc_tcp_handshake(struct svc_xprt *xprt) 430 + { 431 + struct svc_sock *svsk = container_of(xprt, struct svc_sock, sk_xprt); 432 + struct sock *sk = svsk->sk_sock->sk; 433 + struct tls_handshake_args args = { 434 + .ta_sock = svsk->sk_sock, 435 + .ta_done = svc_tcp_handshake_done, 436 + .ta_data = xprt, 437 + }; 438 + int ret; 439 + 440 + trace_svc_tls_upcall(xprt); 441 + 442 + clear_bit(XPT_TLS_SESSION, &xprt->xpt_flags); 443 + init_completion(&svsk->sk_handshake_done); 444 + 445 + ret = tls_server_hello_x509(&args, GFP_KERNEL); 446 + if (ret) { 447 + trace_svc_tls_not_started(xprt); 448 + goto out_failed; 449 + } 450 + 451 + ret = wait_for_completion_interruptible_timeout(&svsk->sk_handshake_done, 452 + SVC_HANDSHAKE_TO); 453 + if (ret <= 0) { 454 + if (tls_handshake_cancel(sk)) { 455 + trace_svc_tls_timed_out(xprt); 456 + goto out_close; 457 + } 458 + } 459 + 460 + if (!test_bit(XPT_TLS_SESSION, &xprt->xpt_flags)) { 461 + trace_svc_tls_unavailable(xprt); 462 + goto out_close; 463 + } 464 + 465 + /* Mark the transport ready in case the remote sent RPC 466 + * traffic before the kernel received the handshake 467 + * completion downcall. 468 + */ 469 + set_bit(XPT_DATA, &xprt->xpt_flags); 470 + svc_xprt_enqueue(xprt); 471 + return; 472 + 473 + out_close: 474 + set_bit(XPT_CLOSE, &xprt->xpt_flags); 475 + out_failed: 476 + clear_bit(XPT_HANDSHAKE, &xprt->xpt_flags); 477 + set_bit(XPT_DATA, &xprt->xpt_flags); 478 + svc_xprt_enqueue(xprt); 407 479 } 408 480 409 481 /* ··· 1349 1257 .xpo_has_wspace = svc_tcp_has_wspace, 1350 1258 .xpo_accept = svc_tcp_accept, 1351 1259 .xpo_kill_temp_xprt = svc_tcp_kill_temp_xprt, 1260 + .xpo_handshake = svc_tcp_handshake, 1352 1261 }; 1353 1262 1354 1263 static struct svc_xprt_class svc_tcp_class = { ··· 1673 1580 static void svc_sock_free(struct svc_xprt *xprt) 1674 1581 { 1675 1582 struct svc_sock *svsk = container_of(xprt, struct svc_sock, sk_xprt); 1583 + struct socket *sock = svsk->sk_sock; 1676 1584 1677 - if (svsk->sk_sock->file) 1678 - sockfd_put(svsk->sk_sock); 1585 + tls_handshake_cancel(sock->sk); 1586 + if (sock->file) 1587 + sockfd_put(sock); 1679 1588 else 1680 - sock_release(svsk->sk_sock); 1589 + sock_release(sock); 1681 1590 kfree(svsk); 1682 1591 }