|
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> |
|
64 | 66 |
|
65 | 67 | #define RPCDBG_FACILITY RPCDBG_SVCXPRT |
66 | 68 |
|
| 69 | +/* To-do: to avoid tying up an nfsd thread while waiting for a |
| 70 | + * handshake request, the request could instead be deferred. |
| 71 | + */ |
| 72 | +enum { |
| 73 | + SVC_HANDSHAKE_TO = 5U * HZ |
| 74 | +}; |
67 | 75 |
|
68 | 76 | static struct svc_sock *svc_setup_socket(struct svc_serv *, struct socket *, |
69 | 77 | int flags); |
@@ -359,6 +367,8 @@ static void svc_data_ready(struct sock *sk) |
359 | 367 | rmb(); |
360 | 368 | svsk->sk_odata(sk); |
361 | 369 | trace_svcsock_data_ready(&svsk->sk_xprt, 0); |
| 370 | + if (test_bit(XPT_HANDSHAKE, &svsk->sk_xprt.xpt_flags)) |
| 371 | + return; |
362 | 372 | if (!test_and_set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags)) |
363 | 373 | svc_xprt_enqueue(&svsk->sk_xprt); |
364 | 374 | } |
@@ -396,6 +406,88 @@ static void svc_tcp_kill_temp_xprt(struct svc_xprt *xprt) |
396 | 406 | sock_no_linger(svsk->sk_sock->sk); |
397 | 407 | } |
398 | 408 |
|
| 409 | +/** |
| 410 | + * svc_tcp_handshake_done - Handshake completion handler |
| 411 | + * @data: address of xprt to wake |
| 412 | + * @status: status of handshake |
| 413 | + * @peerid: serial number of key containing the remote peer's identity |
| 414 | + * |
| 415 | + * If a security policy is specified as an export option, we don't |
| 416 | + * have a specific export here to check. So we set a "TLS session |
| 417 | + * is present" flag on the xprt and let an upper layer enforce local |
| 418 | + * security policy. |
| 419 | + */ |
| 420 | +static void svc_tcp_handshake_done(void *data, int status, key_serial_t peerid) |
| 421 | +{ |
| 422 | + struct svc_xprt *xprt = data; |
| 423 | + struct svc_sock *svsk = container_of(xprt, struct svc_sock, sk_xprt); |
| 424 | + |
| 425 | + if (!status) { |
| 426 | + if (peerid != TLS_NO_PEERID) |
| 427 | + set_bit(XPT_PEER_AUTH, &xprt->xpt_flags); |
| 428 | + set_bit(XPT_TLS_SESSION, &xprt->xpt_flags); |
| 429 | + } |
| 430 | + clear_bit(XPT_HANDSHAKE, &xprt->xpt_flags); |
| 431 | + complete_all(&svsk->sk_handshake_done); |
| 432 | +} |
| 433 | + |
| 434 | +/** |
| 435 | + * svc_tcp_handshake - Perform a transport-layer security handshake |
| 436 | + * @xprt: connected transport endpoint |
| 437 | + * |
| 438 | + */ |
| 439 | +static void svc_tcp_handshake(struct svc_xprt *xprt) |
| 440 | +{ |
| 441 | + struct svc_sock *svsk = container_of(xprt, struct svc_sock, sk_xprt); |
| 442 | + struct sock *sk = svsk->sk_sock->sk; |
| 443 | + struct tls_handshake_args args = { |
| 444 | + .ta_sock = svsk->sk_sock, |
| 445 | + .ta_done = svc_tcp_handshake_done, |
| 446 | + .ta_data = xprt, |
| 447 | + }; |
| 448 | + int ret; |
| 449 | + |
| 450 | + trace_svc_tls_upcall(xprt); |
| 451 | + |
| 452 | + clear_bit(XPT_TLS_SESSION, &xprt->xpt_flags); |
| 453 | + init_completion(&svsk->sk_handshake_done); |
| 454 | + |
| 455 | + ret = tls_server_hello_x509(&args, GFP_KERNEL); |
| 456 | + if (ret) { |
| 457 | + trace_svc_tls_not_started(xprt); |
| 458 | + goto out_failed; |
| 459 | + } |
| 460 | + |
| 461 | + ret = wait_for_completion_interruptible_timeout(&svsk->sk_handshake_done, |
| 462 | + SVC_HANDSHAKE_TO); |
| 463 | + if (ret <= 0) { |
| 464 | + if (tls_handshake_cancel(sk)) { |
| 465 | + trace_svc_tls_timed_out(xprt); |
| 466 | + goto out_close; |
| 467 | + } |
| 468 | + } |
| 469 | + |
| 470 | + if (!test_bit(XPT_TLS_SESSION, &xprt->xpt_flags)) { |
| 471 | + trace_svc_tls_unavailable(xprt); |
| 472 | + goto out_close; |
| 473 | + } |
| 474 | + |
| 475 | + /* Mark the transport ready in case the remote sent RPC |
| 476 | + * traffic before the kernel received the handshake |
| 477 | + * completion downcall. |
| 478 | + */ |
| 479 | + set_bit(XPT_DATA, &xprt->xpt_flags); |
| 480 | + svc_xprt_enqueue(xprt); |
| 481 | + return; |
| 482 | + |
| 483 | +out_close: |
| 484 | + set_bit(XPT_CLOSE, &xprt->xpt_flags); |
| 485 | +out_failed: |
| 486 | + clear_bit(XPT_HANDSHAKE, &xprt->xpt_flags); |
| 487 | + set_bit(XPT_DATA, &xprt->xpt_flags); |
| 488 | + svc_xprt_enqueue(xprt); |
| 489 | +} |
| 490 | + |
399 | 491 | /* |
400 | 492 | * See net/ipv6/ip_sockglue.c : ip_cmsg_recv_pktinfo |
401 | 493 | */ |
@@ -1257,6 +1349,7 @@ static const struct svc_xprt_ops svc_tcp_ops = { |
1257 | 1349 | .xpo_has_wspace = svc_tcp_has_wspace, |
1258 | 1350 | .xpo_accept = svc_tcp_accept, |
1259 | 1351 | .xpo_kill_temp_xprt = svc_tcp_kill_temp_xprt, |
| 1352 | + .xpo_handshake = svc_tcp_handshake, |
1260 | 1353 | }; |
1261 | 1354 |
|
1262 | 1355 | static struct svc_xprt_class svc_tcp_class = { |
@@ -1580,10 +1673,12 @@ static void svc_tcp_sock_detach(struct svc_xprt *xprt) |
1580 | 1673 | static void svc_sock_free(struct svc_xprt *xprt) |
1581 | 1674 | { |
1582 | 1675 | struct svc_sock *svsk = container_of(xprt, struct svc_sock, sk_xprt); |
| 1676 | + struct socket *sock = svsk->sk_sock; |
1583 | 1677 |
|
1584 | | - if (svsk->sk_sock->file) |
1585 | | - sockfd_put(svsk->sk_sock); |
| 1678 | + tls_handshake_cancel(sock->sk); |
| 1679 | + if (sock->file) |
| 1680 | + sockfd_put(sock); |
1586 | 1681 | else |
1587 | | - sock_release(svsk->sk_sock); |
| 1682 | + sock_release(sock); |
1588 | 1683 | kfree(svsk); |
1589 | 1684 | } |
0 commit comments