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

Merge branch 'another-crack-at-a-handshake-upcall-mechanism'

Chuck Lever says:

====================
Another crack at a handshake upcall mechanism

Here is v10 of a series to add generic support for transport layer
security handshake on behalf of kernel socket consumers (user space
consumers use a security library directly, of course). A summary of
the purpose of these patches is archived here:

https://lore.kernel.org/netdev/1DE06BB1-6BA9-4DB4-B2AA-07DE532963D6@oracle.com/

The first patch in the series applies to the top-level .gitignore
file to address the build warnings reported a few days ago. I intend
to submit that separately. I'd like you to consider taking the rest
of this series for v6.4.

The full patch set to support SunRPC with TLSv1.3 is available in
the topic-rpc-with-tls-upcall branch here, based on net-next/main:

https://git.kernel.org/pub/scm/linux/kernel/git/cel/linux.git

This patch set includes support for in-transit confidentiality and
peer authentication for both the Linux NFS client and server.

A user space handshake agent for TLSv1.3 to go along with the kernel
patches is available in the "main" branch here:

https://github.com/oracle/ktls-utils
====================

Link: https://lore.kernel.org/r/168174169259.9520.1911007910797225963.stgit@91.116.238.104.host.secureserver.net
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

+2467
+1
.gitignore
··· 105 105 !.gitignore 106 106 !.mailmap 107 107 !.rustfmt.toml 108 + !.kunitconfig 108 109 109 110 # 110 111 # Generated include files
+124
Documentation/netlink/specs/handshake.yaml
··· 1 + # SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) 2 + # 3 + # Author: Chuck Lever <chuck.lever@oracle.com> 4 + # 5 + # Copyright (c) 2023, Oracle and/or its affiliates. 6 + # 7 + 8 + name: handshake 9 + 10 + protocol: genetlink 11 + 12 + doc: Netlink protocol to request a transport layer security handshake. 13 + 14 + definitions: 15 + - 16 + type: enum 17 + name: handler-class 18 + value-start: 0 19 + entries: [ none, tlshd, max ] 20 + - 21 + type: enum 22 + name: msg-type 23 + value-start: 0 24 + entries: [ unspec, clienthello, serverhello ] 25 + - 26 + type: enum 27 + name: auth 28 + value-start: 0 29 + entries: [ unspec, unauth, psk, x509 ] 30 + 31 + attribute-sets: 32 + - 33 + name: x509 34 + attributes: 35 + - 36 + name: cert 37 + type: u32 38 + - 39 + name: privkey 40 + type: u32 41 + - 42 + name: accept 43 + attributes: 44 + - 45 + name: sockfd 46 + type: u32 47 + - 48 + name: handler-class 49 + type: u32 50 + enum: handler-class 51 + - 52 + name: message-type 53 + type: u32 54 + enum: msg-type 55 + - 56 + name: timeout 57 + type: u32 58 + - 59 + name: auth-mode 60 + type: u32 61 + enum: auth 62 + - 63 + name: peer-identity 64 + type: u32 65 + multi-attr: true 66 + - 67 + name: certificate 68 + type: nest 69 + nested-attributes: x509 70 + multi-attr: true 71 + - 72 + name: done 73 + attributes: 74 + - 75 + name: status 76 + type: u32 77 + - 78 + name: sockfd 79 + type: u32 80 + - 81 + name: remote-auth 82 + type: u32 83 + multi-attr: true 84 + 85 + operations: 86 + list: 87 + - 88 + name: ready 89 + doc: Notify handlers that a new handshake request is waiting 90 + notify: accept 91 + - 92 + name: accept 93 + doc: Handler retrieves next queued handshake request 94 + attribute-set: accept 95 + flags: [ admin-perm ] 96 + do: 97 + request: 98 + attributes: 99 + - handler-class 100 + reply: 101 + attributes: 102 + - sockfd 103 + - message-type 104 + - timeout 105 + - auth-mode 106 + - peer-identity 107 + - certificate 108 + - 109 + name: done 110 + doc: Handler reports handshake completion 111 + attribute-set: done 112 + do: 113 + request: 114 + attributes: 115 + - status 116 + - sockfd 117 + - remote-auth 118 + 119 + mcast-groups: 120 + list: 121 + - 122 + name: none 123 + - 124 + name: tlshd
+1
Documentation/networking/index.rst
··· 36 36 scaling 37 37 tls 38 38 tls-offload 39 + tls-handshake 39 40 nfc 40 41 6lowpan 41 42 6pack
+217
Documentation/networking/tls-handshake.rst
··· 1 + .. SPDX-License-Identifier: GPL-2.0 2 + 3 + ======================= 4 + In-Kernel TLS Handshake 5 + ======================= 6 + 7 + Overview 8 + ======== 9 + 10 + Transport Layer Security (TLS) is a Upper Layer Protocol (ULP) that runs 11 + over TCP. TLS provides end-to-end data integrity and confidentiality in 12 + addition to peer authentication. 13 + 14 + The kernel's kTLS implementation handles the TLS record subprotocol, but 15 + does not handle the TLS handshake subprotocol which is used to establish 16 + a TLS session. Kernel consumers can use the API described here to 17 + request TLS session establishment. 18 + 19 + There are several possible ways to provide a handshake service in the 20 + kernel. The API described here is designed to hide the details of those 21 + implementations so that in-kernel TLS consumers do not need to be 22 + aware of how the handshake gets done. 23 + 24 + 25 + User handshake agent 26 + ==================== 27 + 28 + As of this writing, there is no TLS handshake implementation in the 29 + Linux kernel. To provide a handshake service, a handshake agent 30 + (typically in user space) is started in each network namespace where a 31 + kernel consumer might require a TLS handshake. Handshake agents listen 32 + for events sent from the kernel that indicate a handshake request is 33 + waiting. 34 + 35 + An open socket is passed to a handshake agent via a netlink operation, 36 + which creates a socket descriptor in the agent's file descriptor table. 37 + If the handshake completes successfully, the handshake agent promotes 38 + the socket to use the TLS ULP and sets the session information using the 39 + SOL_TLS socket options. The handshake agent returns the socket to the 40 + kernel via a second netlink operation. 41 + 42 + 43 + Kernel Handshake API 44 + ==================== 45 + 46 + A kernel TLS consumer initiates a client-side TLS handshake on an open 47 + socket by invoking one of the tls_client_hello() functions. First, it 48 + fills in a structure that contains the parameters of the request: 49 + 50 + .. code-block:: c 51 + 52 + struct tls_handshake_args { 53 + struct socket *ta_sock; 54 + tls_done_func_t ta_done; 55 + void *ta_data; 56 + unsigned int ta_timeout_ms; 57 + key_serial_t ta_keyring; 58 + key_serial_t ta_my_cert; 59 + key_serial_t ta_my_privkey; 60 + unsigned int ta_num_peerids; 61 + key_serial_t ta_my_peerids[5]; 62 + }; 63 + 64 + The @ta_sock field references an open and connected socket. The consumer 65 + must hold a reference on the socket to prevent it from being destroyed 66 + while the handshake is in progress. The consumer must also have 67 + instantiated a struct file in sock->file. 68 + 69 + 70 + @ta_done contains a callback function that is invoked when the handshake 71 + has completed. Further explanation of this function is in the "Handshake 72 + Completion" sesction below. 73 + 74 + The consumer can fill in the @ta_timeout_ms field to force the servicing 75 + handshake agent to exit after a number of milliseconds. This enables the 76 + socket to be fully closed once both the kernel and the handshake agent 77 + have closed their endpoints. 78 + 79 + Authentication material such as x.509 certificates, private certificate 80 + keys, and pre-shared keys are provided to the handshake agent in keys 81 + that are instantiated by the consumer before making the handshake 82 + request. The consumer can provide a private keyring that is linked into 83 + the handshake agent's process keyring in the @ta_keyring field to prevent 84 + access of those keys by other subsystems. 85 + 86 + To request an x.509-authenticated TLS session, the consumer fills in 87 + the @ta_my_cert and @ta_my_privkey fields with the serial numbers of 88 + keys containing an x.509 certificate and the private key for that 89 + certificate. Then, it invokes this function: 90 + 91 + .. code-block:: c 92 + 93 + ret = tls_client_hello_x509(args, gfp_flags); 94 + 95 + The function returns zero when the handshake request is under way. A 96 + zero return guarantees the callback function @ta_done will be invoked 97 + for this socket. The function returns a negative errno if the handshake 98 + could not be started. A negative errno guarantees the callback function 99 + @ta_done will not be invoked on this socket. 100 + 101 + 102 + To initiate a client-side TLS handshake with a pre-shared key, use: 103 + 104 + .. code-block:: c 105 + 106 + ret = tls_client_hello_psk(args, gfp_flags); 107 + 108 + However, in this case, the consumer fills in the @ta_my_peerids array 109 + with serial numbers of keys containing the peer identities it wishes 110 + to offer, and the @ta_num_peerids field with the number of array 111 + entries it has filled in. The other fields are filled in as above. 112 + 113 + 114 + To initiate an anonymous client-side TLS handshake use: 115 + 116 + .. code-block:: c 117 + 118 + ret = tls_client_hello_anon(args, gfp_flags); 119 + 120 + The handshake agent presents no peer identity information to the remote 121 + during this type of handshake. Only server authentication (ie the client 122 + verifies the server's identity) is performed during the handshake. Thus 123 + the established session uses encryption only. 124 + 125 + 126 + Consumers that are in-kernel servers use: 127 + 128 + .. code-block:: c 129 + 130 + ret = tls_server_hello_x509(args, gfp_flags); 131 + 132 + or 133 + 134 + .. code-block:: c 135 + 136 + ret = tls_server_hello_psk(args, gfp_flags); 137 + 138 + The argument structure is filled in as above. 139 + 140 + 141 + If the consumer needs to cancel the handshake request, say, due to a ^C 142 + or other exigent event, the consumer can invoke: 143 + 144 + .. code-block:: c 145 + 146 + bool tls_handshake_cancel(sock); 147 + 148 + This function returns true if the handshake request associated with 149 + @sock has been canceled. The consumer's handshake completion callback 150 + will not be invoked. If this function returns false, then the consumer's 151 + completion callback has already been invoked. 152 + 153 + 154 + Handshake Completion 155 + ==================== 156 + 157 + When the handshake agent has completed processing, it notifies the 158 + kernel that the socket may be used by the consumer again. At this point, 159 + the consumer's handshake completion callback, provided in the @ta_done 160 + field in the tls_handshake_args structure, is invoked. 161 + 162 + The synopsis of this function is: 163 + 164 + .. code-block:: c 165 + 166 + typedef void (*tls_done_func_t)(void *data, int status, 167 + key_serial_t peerid); 168 + 169 + The consumer provides a cookie in the @ta_data field of the 170 + tls_handshake_args structure that is returned in the @data parameter of 171 + this callback. The consumer uses the cookie to match the callback to the 172 + thread waiting for the handshake to complete. 173 + 174 + The success status of the handshake is returned via the @status 175 + parameter: 176 + 177 + +------------+----------------------------------------------+ 178 + | status | meaning | 179 + +============+==============================================+ 180 + | 0 | TLS session established successfully | 181 + +------------+----------------------------------------------+ 182 + | -EACCESS | Remote peer rejected the handshake or | 183 + | | authentication failed | 184 + +------------+----------------------------------------------+ 185 + | -ENOMEM | Temporary resource allocation failure | 186 + +------------+----------------------------------------------+ 187 + | -EINVAL | Consumer provided an invalid argument | 188 + +------------+----------------------------------------------+ 189 + | -ENOKEY | Missing authentication material | 190 + +------------+----------------------------------------------+ 191 + | -EIO | An unexpected fault occurred | 192 + +------------+----------------------------------------------+ 193 + 194 + The @peerid parameter contains the serial number of a key containing the 195 + remote peer's identity or the value TLS_NO_PEERID if the session is not 196 + authenticated. 197 + 198 + A best practice is to close and destroy the socket immediately if the 199 + handshake failed. 200 + 201 + 202 + Other considerations 203 + -------------------- 204 + 205 + While a handshake is under way, the kernel consumer must alter the 206 + socket's sk_data_ready callback function to ignore all incoming data. 207 + Once the handshake completion callback function has been invoked, normal 208 + receive operation can be resumed. 209 + 210 + Once a TLS session is established, the consumer must provide a buffer 211 + for and then examine the control message (CMSG) that is part of every 212 + subsequent sock_recvmsg(). Each control message indicates whether the 213 + received message data is TLS record data or session metadata. 214 + 215 + See tls.rst for details on how a kTLS consumer recognizes incoming 216 + (decrypted) application data, alerts, and handshake packets once the 217 + socket has been promoted to use the TLS ULP.
+11
MAINTAINERS
··· 8947 8947 T: git git://linuxtv.org/anttip/media_tree.git 8948 8948 F: drivers/media/usb/hackrf/ 8949 8949 8950 + HANDSHAKE UPCALL FOR TRANSPORT LAYER SECURITY 8951 + M: Chuck Lever <chuck.lever@oracle.com> 8952 + L: kernel-tls-handshake@lists.linux.dev 8953 + L: netdev@vger.kernel.org 8954 + S: Maintained 8955 + F: Documentation/netlink/specs/handshake.yaml 8956 + F: Documentation/networking/tls-handshake.rst 8957 + F: include/net/handshake.h 8958 + F: include/trace/events/handshake.h 8959 + F: net/handshake/ 8960 + 8950 8961 HANTRO VPU CODEC DRIVER 8951 8962 M: Ezequiel Garcia <ezequiel@vanguardiasur.com.ar> 8952 8963 M: Philipp Zabel <p.zabel@pengutronix.de>
+43
include/net/handshake.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-only */ 2 + /* 3 + * Generic netlink HANDSHAKE service. 4 + * 5 + * Author: Chuck Lever <chuck.lever@oracle.com> 6 + * 7 + * Copyright (c) 2023, Oracle and/or its affiliates. 8 + */ 9 + 10 + #ifndef _NET_HANDSHAKE_H 11 + #define _NET_HANDSHAKE_H 12 + 13 + enum { 14 + TLS_NO_KEYRING = 0, 15 + TLS_NO_PEERID = 0, 16 + TLS_NO_CERT = 0, 17 + TLS_NO_PRIVKEY = 0, 18 + }; 19 + 20 + typedef void (*tls_done_func_t)(void *data, int status, 21 + key_serial_t peerid); 22 + 23 + struct tls_handshake_args { 24 + struct socket *ta_sock; 25 + tls_done_func_t ta_done; 26 + void *ta_data; 27 + unsigned int ta_timeout_ms; 28 + key_serial_t ta_keyring; 29 + key_serial_t ta_my_cert; 30 + key_serial_t ta_my_privkey; 31 + unsigned int ta_num_peerids; 32 + key_serial_t ta_my_peerids[5]; 33 + }; 34 + 35 + int tls_client_hello_anon(const struct tls_handshake_args *args, gfp_t flags); 36 + int tls_client_hello_x509(const struct tls_handshake_args *args, gfp_t flags); 37 + int tls_client_hello_psk(const struct tls_handshake_args *args, gfp_t flags); 38 + int tls_server_hello_x509(const struct tls_handshake_args *args, gfp_t flags); 39 + int tls_server_hello_psk(const struct tls_handshake_args *args, gfp_t flags); 40 + 41 + bool tls_handshake_cancel(struct sock *sk); 42 + 43 + #endif /* _NET_HANDSHAKE_H */
+159
include/trace/events/handshake.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + #undef TRACE_SYSTEM 3 + #define TRACE_SYSTEM handshake 4 + 5 + #if !defined(_TRACE_HANDSHAKE_H) || defined(TRACE_HEADER_MULTI_READ) 6 + #define _TRACE_HANDSHAKE_H 7 + 8 + #include <linux/net.h> 9 + #include <linux/tracepoint.h> 10 + 11 + DECLARE_EVENT_CLASS(handshake_event_class, 12 + TP_PROTO( 13 + const struct net *net, 14 + const struct handshake_req *req, 15 + const struct sock *sk 16 + ), 17 + TP_ARGS(net, req, sk), 18 + TP_STRUCT__entry( 19 + __field(const void *, req) 20 + __field(const void *, sk) 21 + __field(unsigned int, netns_ino) 22 + ), 23 + TP_fast_assign( 24 + __entry->req = req; 25 + __entry->sk = sk; 26 + __entry->netns_ino = net->ns.inum; 27 + ), 28 + TP_printk("req=%p sk=%p", 29 + __entry->req, __entry->sk 30 + ) 31 + ); 32 + #define DEFINE_HANDSHAKE_EVENT(name) \ 33 + DEFINE_EVENT(handshake_event_class, name, \ 34 + TP_PROTO( \ 35 + const struct net *net, \ 36 + const struct handshake_req *req, \ 37 + const struct sock *sk \ 38 + ), \ 39 + TP_ARGS(net, req, sk)) 40 + 41 + DECLARE_EVENT_CLASS(handshake_fd_class, 42 + TP_PROTO( 43 + const struct net *net, 44 + const struct handshake_req *req, 45 + const struct sock *sk, 46 + int fd 47 + ), 48 + TP_ARGS(net, req, sk, fd), 49 + TP_STRUCT__entry( 50 + __field(const void *, req) 51 + __field(const void *, sk) 52 + __field(int, fd) 53 + __field(unsigned int, netns_ino) 54 + ), 55 + TP_fast_assign( 56 + __entry->req = req; 57 + __entry->sk = req->hr_sk; 58 + __entry->fd = fd; 59 + __entry->netns_ino = net->ns.inum; 60 + ), 61 + TP_printk("req=%p sk=%p fd=%d", 62 + __entry->req, __entry->sk, __entry->fd 63 + ) 64 + ); 65 + #define DEFINE_HANDSHAKE_FD_EVENT(name) \ 66 + DEFINE_EVENT(handshake_fd_class, name, \ 67 + TP_PROTO( \ 68 + const struct net *net, \ 69 + const struct handshake_req *req, \ 70 + const struct sock *sk, \ 71 + int fd \ 72 + ), \ 73 + TP_ARGS(net, req, sk, fd)) 74 + 75 + DECLARE_EVENT_CLASS(handshake_error_class, 76 + TP_PROTO( 77 + const struct net *net, 78 + const struct handshake_req *req, 79 + const struct sock *sk, 80 + int err 81 + ), 82 + TP_ARGS(net, req, sk, err), 83 + TP_STRUCT__entry( 84 + __field(const void *, req) 85 + __field(const void *, sk) 86 + __field(int, err) 87 + __field(unsigned int, netns_ino) 88 + ), 89 + TP_fast_assign( 90 + __entry->req = req; 91 + __entry->sk = sk; 92 + __entry->err = err; 93 + __entry->netns_ino = net->ns.inum; 94 + ), 95 + TP_printk("req=%p sk=%p err=%d", 96 + __entry->req, __entry->sk, __entry->err 97 + ) 98 + ); 99 + #define DEFINE_HANDSHAKE_ERROR(name) \ 100 + DEFINE_EVENT(handshake_error_class, name, \ 101 + TP_PROTO( \ 102 + const struct net *net, \ 103 + const struct handshake_req *req, \ 104 + const struct sock *sk, \ 105 + int err \ 106 + ), \ 107 + TP_ARGS(net, req, sk, err)) 108 + 109 + 110 + /* 111 + * Request lifetime events 112 + */ 113 + 114 + DEFINE_HANDSHAKE_EVENT(handshake_submit); 115 + DEFINE_HANDSHAKE_ERROR(handshake_submit_err); 116 + DEFINE_HANDSHAKE_EVENT(handshake_cancel); 117 + DEFINE_HANDSHAKE_EVENT(handshake_cancel_none); 118 + DEFINE_HANDSHAKE_EVENT(handshake_cancel_busy); 119 + DEFINE_HANDSHAKE_EVENT(handshake_destruct); 120 + 121 + 122 + TRACE_EVENT(handshake_complete, 123 + TP_PROTO( 124 + const struct net *net, 125 + const struct handshake_req *req, 126 + const struct sock *sk, 127 + int status 128 + ), 129 + TP_ARGS(net, req, sk, status), 130 + TP_STRUCT__entry( 131 + __field(const void *, req) 132 + __field(const void *, sk) 133 + __field(int, status) 134 + __field(unsigned int, netns_ino) 135 + ), 136 + TP_fast_assign( 137 + __entry->req = req; 138 + __entry->sk = sk; 139 + __entry->status = status; 140 + __entry->netns_ino = net->ns.inum; 141 + ), 142 + TP_printk("req=%p sk=%p status=%d", 143 + __entry->req, __entry->sk, __entry->status 144 + ) 145 + ); 146 + 147 + /* 148 + * Netlink events 149 + */ 150 + 151 + DEFINE_HANDSHAKE_ERROR(handshake_notify_err); 152 + DEFINE_HANDSHAKE_FD_EVENT(handshake_cmd_accept); 153 + DEFINE_HANDSHAKE_ERROR(handshake_cmd_accept_err); 154 + DEFINE_HANDSHAKE_FD_EVENT(handshake_cmd_done); 155 + DEFINE_HANDSHAKE_ERROR(handshake_cmd_done_err); 156 + 157 + #endif /* _TRACE_HANDSHAKE_H */ 158 + 159 + #include <trace/define_trace.h>
+73
include/uapi/linux/handshake.h
··· 1 + /* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ 2 + /* Do not edit directly, auto-generated from: */ 3 + /* Documentation/netlink/specs/handshake.yaml */ 4 + /* YNL-GEN uapi header */ 5 + 6 + #ifndef _UAPI_LINUX_HANDSHAKE_H 7 + #define _UAPI_LINUX_HANDSHAKE_H 8 + 9 + #define HANDSHAKE_FAMILY_NAME "handshake" 10 + #define HANDSHAKE_FAMILY_VERSION 1 11 + 12 + enum handshake_handler_class { 13 + HANDSHAKE_HANDLER_CLASS_NONE, 14 + HANDSHAKE_HANDLER_CLASS_TLSHD, 15 + HANDSHAKE_HANDLER_CLASS_MAX, 16 + }; 17 + 18 + enum handshake_msg_type { 19 + HANDSHAKE_MSG_TYPE_UNSPEC, 20 + HANDSHAKE_MSG_TYPE_CLIENTHELLO, 21 + HANDSHAKE_MSG_TYPE_SERVERHELLO, 22 + }; 23 + 24 + enum handshake_auth { 25 + HANDSHAKE_AUTH_UNSPEC, 26 + HANDSHAKE_AUTH_UNAUTH, 27 + HANDSHAKE_AUTH_PSK, 28 + HANDSHAKE_AUTH_X509, 29 + }; 30 + 31 + enum { 32 + HANDSHAKE_A_X509_CERT = 1, 33 + HANDSHAKE_A_X509_PRIVKEY, 34 + 35 + __HANDSHAKE_A_X509_MAX, 36 + HANDSHAKE_A_X509_MAX = (__HANDSHAKE_A_X509_MAX - 1) 37 + }; 38 + 39 + enum { 40 + HANDSHAKE_A_ACCEPT_SOCKFD = 1, 41 + HANDSHAKE_A_ACCEPT_HANDLER_CLASS, 42 + HANDSHAKE_A_ACCEPT_MESSAGE_TYPE, 43 + HANDSHAKE_A_ACCEPT_TIMEOUT, 44 + HANDSHAKE_A_ACCEPT_AUTH_MODE, 45 + HANDSHAKE_A_ACCEPT_PEER_IDENTITY, 46 + HANDSHAKE_A_ACCEPT_CERTIFICATE, 47 + 48 + __HANDSHAKE_A_ACCEPT_MAX, 49 + HANDSHAKE_A_ACCEPT_MAX = (__HANDSHAKE_A_ACCEPT_MAX - 1) 50 + }; 51 + 52 + enum { 53 + HANDSHAKE_A_DONE_STATUS = 1, 54 + HANDSHAKE_A_DONE_SOCKFD, 55 + HANDSHAKE_A_DONE_REMOTE_AUTH, 56 + 57 + __HANDSHAKE_A_DONE_MAX, 58 + HANDSHAKE_A_DONE_MAX = (__HANDSHAKE_A_DONE_MAX - 1) 59 + }; 60 + 61 + enum { 62 + HANDSHAKE_CMD_READY = 1, 63 + HANDSHAKE_CMD_ACCEPT, 64 + HANDSHAKE_CMD_DONE, 65 + 66 + __HANDSHAKE_CMD_MAX, 67 + HANDSHAKE_CMD_MAX = (__HANDSHAKE_CMD_MAX - 1) 68 + }; 69 + 70 + #define HANDSHAKE_MCGRP_NONE "none" 71 + #define HANDSHAKE_MCGRP_TLSHD "tlshd" 72 + 73 + #endif /* _UAPI_LINUX_HANDSHAKE_H */
+20
net/Kconfig
··· 68 68 source "net/smc/Kconfig" 69 69 source "net/xdp/Kconfig" 70 70 71 + config NET_HANDSHAKE 72 + bool 73 + depends on SUNRPC || NVME_TARGET_TCP || NVME_TCP 74 + default y 75 + 76 + config NET_HANDSHAKE_KUNIT_TEST 77 + tristate "KUnit tests for the handshake upcall mechanism" if !KUNIT_ALL_TESTS 78 + default KUNIT_ALL_TESTS 79 + depends on KUNIT 80 + help 81 + This builds the KUnit tests for the handshake upcall mechanism. 82 + 83 + KUnit tests run during boot and output the results to the debug 84 + log in TAP format (https://testanything.org/). Only useful for 85 + kernel devs running KUnit test harness and are not for inclusion 86 + into a production build. 87 + 88 + For more information on KUnit and unit tests in general, refer 89 + to the KUnit documentation in Documentation/dev-tools/kunit/. 90 + 71 91 config INET 72 92 bool "TCP/IP networking" 73 93 help
+1
net/Makefile
··· 79 79 obj-$(CONFIG_XDP_SOCKETS) += xdp/ 80 80 obj-$(CONFIG_MPTCP) += mptcp/ 81 81 obj-$(CONFIG_MCTP) += mctp/ 82 + obj-$(CONFIG_NET_HANDSHAKE) += handshake/
+11
net/handshake/.kunitconfig
··· 1 + CONFIG_KUNIT=y 2 + CONFIG_UBSAN=y 3 + CONFIG_STACKTRACE=y 4 + CONFIG_NET=y 5 + CONFIG_NETWORK_FILESYSTEMS=y 6 + CONFIG_INET=y 7 + CONFIG_MULTIUSER=y 8 + CONFIG_NFS_FS=y 9 + CONFIG_SUNRPC=y 10 + CONFIG_NET_HANDSHAKE=y 11 + CONFIG_NET_HANDSHAKE_KUNIT_TEST=y
+13
net/handshake/Makefile
··· 1 + # SPDX-License-Identifier: GPL-2.0-only 2 + # 3 + # Makefile for the Generic HANDSHAKE service 4 + # 5 + # Author: Chuck Lever <chuck.lever@oracle.com> 6 + # 7 + # Copyright (c) 2023, Oracle and/or its affiliates. 8 + # 9 + 10 + obj-y += handshake.o 11 + handshake-y := genl.o netlink.o request.o tlshd.o trace.o 12 + 13 + obj-$(CONFIG_NET_HANDSHAKE_KUNIT_TEST) += handshake-test.o
+58
net/handshake/genl.c
··· 1 + // SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) 2 + /* Do not edit directly, auto-generated from: */ 3 + /* Documentation/netlink/specs/handshake.yaml */ 4 + /* YNL-GEN kernel source */ 5 + 6 + #include <net/netlink.h> 7 + #include <net/genetlink.h> 8 + 9 + #include "genl.h" 10 + 11 + #include <linux/handshake.h> 12 + 13 + /* HANDSHAKE_CMD_ACCEPT - do */ 14 + static const struct nla_policy handshake_accept_nl_policy[HANDSHAKE_A_ACCEPT_HANDLER_CLASS + 1] = { 15 + [HANDSHAKE_A_ACCEPT_HANDLER_CLASS] = NLA_POLICY_MAX(NLA_U32, 2), 16 + }; 17 + 18 + /* HANDSHAKE_CMD_DONE - do */ 19 + static const struct nla_policy handshake_done_nl_policy[HANDSHAKE_A_DONE_REMOTE_AUTH + 1] = { 20 + [HANDSHAKE_A_DONE_STATUS] = { .type = NLA_U32, }, 21 + [HANDSHAKE_A_DONE_SOCKFD] = { .type = NLA_U32, }, 22 + [HANDSHAKE_A_DONE_REMOTE_AUTH] = { .type = NLA_U32, }, 23 + }; 24 + 25 + /* Ops table for handshake */ 26 + static const struct genl_split_ops handshake_nl_ops[] = { 27 + { 28 + .cmd = HANDSHAKE_CMD_ACCEPT, 29 + .doit = handshake_nl_accept_doit, 30 + .policy = handshake_accept_nl_policy, 31 + .maxattr = HANDSHAKE_A_ACCEPT_HANDLER_CLASS, 32 + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, 33 + }, 34 + { 35 + .cmd = HANDSHAKE_CMD_DONE, 36 + .doit = handshake_nl_done_doit, 37 + .policy = handshake_done_nl_policy, 38 + .maxattr = HANDSHAKE_A_DONE_REMOTE_AUTH, 39 + .flags = GENL_CMD_CAP_DO, 40 + }, 41 + }; 42 + 43 + static const struct genl_multicast_group handshake_nl_mcgrps[] = { 44 + [HANDSHAKE_NLGRP_NONE] = { "none", }, 45 + [HANDSHAKE_NLGRP_TLSHD] = { "tlshd", }, 46 + }; 47 + 48 + struct genl_family handshake_nl_family __ro_after_init = { 49 + .name = HANDSHAKE_FAMILY_NAME, 50 + .version = HANDSHAKE_FAMILY_VERSION, 51 + .netnsok = true, 52 + .parallel_ops = true, 53 + .module = THIS_MODULE, 54 + .split_ops = handshake_nl_ops, 55 + .n_split_ops = ARRAY_SIZE(handshake_nl_ops), 56 + .mcgrps = handshake_nl_mcgrps, 57 + .n_mcgrps = ARRAY_SIZE(handshake_nl_mcgrps), 58 + };
+24
net/handshake/genl.h
··· 1 + /* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ 2 + /* Do not edit directly, auto-generated from: */ 3 + /* Documentation/netlink/specs/handshake.yaml */ 4 + /* YNL-GEN kernel header */ 5 + 6 + #ifndef _LINUX_HANDSHAKE_GEN_H 7 + #define _LINUX_HANDSHAKE_GEN_H 8 + 9 + #include <net/netlink.h> 10 + #include <net/genetlink.h> 11 + 12 + #include <linux/handshake.h> 13 + 14 + int handshake_nl_accept_doit(struct sk_buff *skb, struct genl_info *info); 15 + int handshake_nl_done_doit(struct sk_buff *skb, struct genl_info *info); 16 + 17 + enum { 18 + HANDSHAKE_NLGRP_NONE, 19 + HANDSHAKE_NLGRP_TLSHD, 20 + }; 21 + 22 + extern struct genl_family handshake_nl_family; 23 + 24 + #endif /* _LINUX_HANDSHAKE_GEN_H */
+523
net/handshake/handshake-test.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Copyright (c) 2023 Oracle and/or its affiliates. 4 + * 5 + * KUnit test of the handshake upcall mechanism. 6 + */ 7 + 8 + #include <kunit/test.h> 9 + #include <kunit/visibility.h> 10 + 11 + #include <linux/kernel.h> 12 + 13 + #include <net/sock.h> 14 + #include <net/genetlink.h> 15 + #include <net/netns/generic.h> 16 + 17 + #include <uapi/linux/handshake.h> 18 + #include "handshake.h" 19 + 20 + MODULE_IMPORT_NS(EXPORTED_FOR_KUNIT_TESTING); 21 + 22 + static int test_accept_func(struct handshake_req *req, struct genl_info *info, 23 + int fd) 24 + { 25 + return 0; 26 + } 27 + 28 + static void test_done_func(struct handshake_req *req, unsigned int status, 29 + struct genl_info *info) 30 + { 31 + } 32 + 33 + struct handshake_req_alloc_test_param { 34 + const char *desc; 35 + struct handshake_proto *proto; 36 + gfp_t gfp; 37 + bool expect_success; 38 + }; 39 + 40 + static struct handshake_proto handshake_req_alloc_proto_2 = { 41 + .hp_handler_class = HANDSHAKE_HANDLER_CLASS_NONE, 42 + }; 43 + 44 + static struct handshake_proto handshake_req_alloc_proto_3 = { 45 + .hp_handler_class = HANDSHAKE_HANDLER_CLASS_MAX, 46 + }; 47 + 48 + static struct handshake_proto handshake_req_alloc_proto_4 = { 49 + .hp_handler_class = HANDSHAKE_HANDLER_CLASS_TLSHD, 50 + }; 51 + 52 + static struct handshake_proto handshake_req_alloc_proto_5 = { 53 + .hp_handler_class = HANDSHAKE_HANDLER_CLASS_TLSHD, 54 + .hp_accept = test_accept_func, 55 + }; 56 + 57 + static struct handshake_proto handshake_req_alloc_proto_6 = { 58 + .hp_handler_class = HANDSHAKE_HANDLER_CLASS_TLSHD, 59 + .hp_privsize = UINT_MAX, 60 + .hp_accept = test_accept_func, 61 + .hp_done = test_done_func, 62 + }; 63 + 64 + static struct handshake_proto handshake_req_alloc_proto_good = { 65 + .hp_handler_class = HANDSHAKE_HANDLER_CLASS_TLSHD, 66 + .hp_accept = test_accept_func, 67 + .hp_done = test_done_func, 68 + }; 69 + 70 + static const 71 + struct handshake_req_alloc_test_param handshake_req_alloc_params[] = { 72 + { 73 + .desc = "handshake_req_alloc NULL proto", 74 + .proto = NULL, 75 + .gfp = GFP_KERNEL, 76 + .expect_success = false, 77 + }, 78 + { 79 + .desc = "handshake_req_alloc CLASS_NONE", 80 + .proto = &handshake_req_alloc_proto_2, 81 + .gfp = GFP_KERNEL, 82 + .expect_success = false, 83 + }, 84 + { 85 + .desc = "handshake_req_alloc CLASS_MAX", 86 + .proto = &handshake_req_alloc_proto_3, 87 + .gfp = GFP_KERNEL, 88 + .expect_success = false, 89 + }, 90 + { 91 + .desc = "handshake_req_alloc no callbacks", 92 + .proto = &handshake_req_alloc_proto_4, 93 + .gfp = GFP_KERNEL, 94 + .expect_success = false, 95 + }, 96 + { 97 + .desc = "handshake_req_alloc no done callback", 98 + .proto = &handshake_req_alloc_proto_5, 99 + .gfp = GFP_KERNEL, 100 + .expect_success = false, 101 + }, 102 + { 103 + .desc = "handshake_req_alloc excessive privsize", 104 + .proto = &handshake_req_alloc_proto_6, 105 + .gfp = GFP_KERNEL, 106 + .expect_success = false, 107 + }, 108 + { 109 + .desc = "handshake_req_alloc all good", 110 + .proto = &handshake_req_alloc_proto_good, 111 + .gfp = GFP_KERNEL, 112 + .expect_success = true, 113 + }, 114 + }; 115 + 116 + static void 117 + handshake_req_alloc_get_desc(const struct handshake_req_alloc_test_param *param, 118 + char *desc) 119 + { 120 + strscpy(desc, param->desc, KUNIT_PARAM_DESC_SIZE); 121 + } 122 + 123 + /* Creates the function handshake_req_alloc_gen_params */ 124 + KUNIT_ARRAY_PARAM(handshake_req_alloc, handshake_req_alloc_params, 125 + handshake_req_alloc_get_desc); 126 + 127 + static void handshake_req_alloc_case(struct kunit *test) 128 + { 129 + const struct handshake_req_alloc_test_param *param = test->param_value; 130 + struct handshake_req *result; 131 + 132 + /* Arrange */ 133 + 134 + /* Act */ 135 + result = handshake_req_alloc(param->proto, param->gfp); 136 + 137 + /* Assert */ 138 + if (param->expect_success) 139 + KUNIT_EXPECT_NOT_NULL(test, result); 140 + else 141 + KUNIT_EXPECT_NULL(test, result); 142 + 143 + kfree(result); 144 + } 145 + 146 + static void handshake_req_submit_test1(struct kunit *test) 147 + { 148 + struct socket *sock; 149 + int err, result; 150 + 151 + /* Arrange */ 152 + err = __sock_create(&init_net, PF_INET, SOCK_STREAM, IPPROTO_TCP, 153 + &sock, 1); 154 + KUNIT_ASSERT_EQ(test, err, 0); 155 + 156 + /* Act */ 157 + result = handshake_req_submit(sock, NULL, GFP_KERNEL); 158 + 159 + /* Assert */ 160 + KUNIT_EXPECT_EQ(test, result, -EINVAL); 161 + 162 + sock_release(sock); 163 + } 164 + 165 + static void handshake_req_submit_test2(struct kunit *test) 166 + { 167 + struct handshake_req *req; 168 + int result; 169 + 170 + /* Arrange */ 171 + req = handshake_req_alloc(&handshake_req_alloc_proto_good, GFP_KERNEL); 172 + KUNIT_ASSERT_NOT_NULL(test, req); 173 + 174 + /* Act */ 175 + result = handshake_req_submit(NULL, req, GFP_KERNEL); 176 + 177 + /* Assert */ 178 + KUNIT_EXPECT_EQ(test, result, -EINVAL); 179 + 180 + /* handshake_req_submit() destroys @req on error */ 181 + } 182 + 183 + static void handshake_req_submit_test3(struct kunit *test) 184 + { 185 + struct handshake_req *req; 186 + struct socket *sock; 187 + int err, result; 188 + 189 + /* Arrange */ 190 + req = handshake_req_alloc(&handshake_req_alloc_proto_good, GFP_KERNEL); 191 + KUNIT_ASSERT_NOT_NULL(test, req); 192 + 193 + err = __sock_create(&init_net, PF_INET, SOCK_STREAM, IPPROTO_TCP, 194 + &sock, 1); 195 + KUNIT_ASSERT_EQ(test, err, 0); 196 + sock->file = NULL; 197 + 198 + /* Act */ 199 + result = handshake_req_submit(sock, req, GFP_KERNEL); 200 + 201 + /* Assert */ 202 + KUNIT_EXPECT_EQ(test, result, -EINVAL); 203 + 204 + /* handshake_req_submit() destroys @req on error */ 205 + sock_release(sock); 206 + } 207 + 208 + static void handshake_req_submit_test4(struct kunit *test) 209 + { 210 + struct handshake_req *req, *result; 211 + struct socket *sock; 212 + int err; 213 + 214 + /* Arrange */ 215 + req = handshake_req_alloc(&handshake_req_alloc_proto_good, GFP_KERNEL); 216 + KUNIT_ASSERT_NOT_NULL(test, req); 217 + 218 + err = __sock_create(&init_net, PF_INET, SOCK_STREAM, IPPROTO_TCP, 219 + &sock, 1); 220 + KUNIT_ASSERT_EQ(test, err, 0); 221 + sock->file = sock_alloc_file(sock, O_NONBLOCK, NULL); 222 + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, sock->file); 223 + KUNIT_ASSERT_NOT_NULL(test, sock->sk); 224 + 225 + err = handshake_req_submit(sock, req, GFP_KERNEL); 226 + KUNIT_ASSERT_EQ(test, err, 0); 227 + 228 + /* Act */ 229 + result = handshake_req_hash_lookup(sock->sk); 230 + 231 + /* Assert */ 232 + KUNIT_EXPECT_NOT_NULL(test, result); 233 + KUNIT_EXPECT_PTR_EQ(test, req, result); 234 + 235 + handshake_req_cancel(sock->sk); 236 + sock_release(sock); 237 + } 238 + 239 + static void handshake_req_submit_test5(struct kunit *test) 240 + { 241 + struct handshake_req *req; 242 + struct handshake_net *hn; 243 + struct socket *sock; 244 + struct net *net; 245 + int saved, err; 246 + 247 + /* Arrange */ 248 + req = handshake_req_alloc(&handshake_req_alloc_proto_good, GFP_KERNEL); 249 + KUNIT_ASSERT_NOT_NULL(test, req); 250 + 251 + err = __sock_create(&init_net, PF_INET, SOCK_STREAM, IPPROTO_TCP, 252 + &sock, 1); 253 + KUNIT_ASSERT_EQ(test, err, 0); 254 + sock->file = sock_alloc_file(sock, O_NONBLOCK, NULL); 255 + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, sock->file); 256 + KUNIT_ASSERT_NOT_NULL(test, sock->sk); 257 + 258 + net = sock_net(sock->sk); 259 + hn = handshake_pernet(net); 260 + KUNIT_ASSERT_NOT_NULL(test, hn); 261 + 262 + saved = hn->hn_pending; 263 + hn->hn_pending = hn->hn_pending_max + 1; 264 + 265 + /* Act */ 266 + err = handshake_req_submit(sock, req, GFP_KERNEL); 267 + 268 + /* Assert */ 269 + KUNIT_EXPECT_EQ(test, err, -EAGAIN); 270 + 271 + sock_release(sock); 272 + hn->hn_pending = saved; 273 + } 274 + 275 + static void handshake_req_submit_test6(struct kunit *test) 276 + { 277 + struct handshake_req *req1, *req2; 278 + struct socket *sock; 279 + int err; 280 + 281 + /* Arrange */ 282 + req1 = handshake_req_alloc(&handshake_req_alloc_proto_good, GFP_KERNEL); 283 + KUNIT_ASSERT_NOT_NULL(test, req1); 284 + req2 = handshake_req_alloc(&handshake_req_alloc_proto_good, GFP_KERNEL); 285 + KUNIT_ASSERT_NOT_NULL(test, req2); 286 + 287 + err = __sock_create(&init_net, PF_INET, SOCK_STREAM, IPPROTO_TCP, 288 + &sock, 1); 289 + KUNIT_ASSERT_EQ(test, err, 0); 290 + sock->file = sock_alloc_file(sock, O_NONBLOCK, NULL); 291 + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, sock->file); 292 + KUNIT_ASSERT_NOT_NULL(test, sock->sk); 293 + 294 + /* Act */ 295 + err = handshake_req_submit(sock, req1, GFP_KERNEL); 296 + KUNIT_ASSERT_EQ(test, err, 0); 297 + err = handshake_req_submit(sock, req2, GFP_KERNEL); 298 + 299 + /* Assert */ 300 + KUNIT_EXPECT_EQ(test, err, -EBUSY); 301 + 302 + handshake_req_cancel(sock->sk); 303 + sock_release(sock); 304 + } 305 + 306 + static void handshake_req_cancel_test1(struct kunit *test) 307 + { 308 + struct handshake_req *req; 309 + struct socket *sock; 310 + bool result; 311 + int err; 312 + 313 + /* Arrange */ 314 + req = handshake_req_alloc(&handshake_req_alloc_proto_good, GFP_KERNEL); 315 + KUNIT_ASSERT_NOT_NULL(test, req); 316 + 317 + err = __sock_create(&init_net, PF_INET, SOCK_STREAM, IPPROTO_TCP, 318 + &sock, 1); 319 + KUNIT_ASSERT_EQ(test, err, 0); 320 + 321 + sock->file = sock_alloc_file(sock, O_NONBLOCK, NULL); 322 + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, sock->file); 323 + 324 + err = handshake_req_submit(sock, req, GFP_KERNEL); 325 + KUNIT_ASSERT_EQ(test, err, 0); 326 + 327 + /* NB: handshake_req hasn't been accepted */ 328 + 329 + /* Act */ 330 + result = handshake_req_cancel(sock->sk); 331 + 332 + /* Assert */ 333 + KUNIT_EXPECT_TRUE(test, result); 334 + 335 + sock_release(sock); 336 + } 337 + 338 + static void handshake_req_cancel_test2(struct kunit *test) 339 + { 340 + struct handshake_req *req, *next; 341 + struct handshake_net *hn; 342 + struct socket *sock; 343 + struct net *net; 344 + bool result; 345 + int err; 346 + 347 + /* Arrange */ 348 + req = handshake_req_alloc(&handshake_req_alloc_proto_good, GFP_KERNEL); 349 + KUNIT_ASSERT_NOT_NULL(test, req); 350 + 351 + err = __sock_create(&init_net, PF_INET, SOCK_STREAM, IPPROTO_TCP, 352 + &sock, 1); 353 + KUNIT_ASSERT_EQ(test, err, 0); 354 + 355 + sock->file = sock_alloc_file(sock, O_NONBLOCK, NULL); 356 + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, sock->file); 357 + 358 + err = handshake_req_submit(sock, req, GFP_KERNEL); 359 + KUNIT_ASSERT_EQ(test, err, 0); 360 + 361 + net = sock_net(sock->sk); 362 + hn = handshake_pernet(net); 363 + KUNIT_ASSERT_NOT_NULL(test, hn); 364 + 365 + /* Pretend to accept this request */ 366 + next = handshake_req_next(hn, HANDSHAKE_HANDLER_CLASS_TLSHD); 367 + KUNIT_ASSERT_PTR_EQ(test, req, next); 368 + 369 + /* Act */ 370 + result = handshake_req_cancel(sock->sk); 371 + 372 + /* Assert */ 373 + KUNIT_EXPECT_TRUE(test, result); 374 + 375 + sock_release(sock); 376 + } 377 + 378 + static void handshake_req_cancel_test3(struct kunit *test) 379 + { 380 + struct handshake_req *req, *next; 381 + struct handshake_net *hn; 382 + struct socket *sock; 383 + struct net *net; 384 + bool result; 385 + int err; 386 + 387 + /* Arrange */ 388 + req = handshake_req_alloc(&handshake_req_alloc_proto_good, GFP_KERNEL); 389 + KUNIT_ASSERT_NOT_NULL(test, req); 390 + 391 + err = __sock_create(&init_net, PF_INET, SOCK_STREAM, IPPROTO_TCP, 392 + &sock, 1); 393 + KUNIT_ASSERT_EQ(test, err, 0); 394 + 395 + sock->file = sock_alloc_file(sock, O_NONBLOCK, NULL); 396 + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, sock->file); 397 + 398 + err = handshake_req_submit(sock, req, GFP_KERNEL); 399 + KUNIT_ASSERT_EQ(test, err, 0); 400 + 401 + net = sock_net(sock->sk); 402 + hn = handshake_pernet(net); 403 + KUNIT_ASSERT_NOT_NULL(test, hn); 404 + 405 + /* Pretend to accept this request */ 406 + next = handshake_req_next(hn, HANDSHAKE_HANDLER_CLASS_TLSHD); 407 + KUNIT_ASSERT_PTR_EQ(test, req, next); 408 + 409 + /* Pretend to complete this request */ 410 + handshake_complete(next, -ETIMEDOUT, NULL); 411 + 412 + /* Act */ 413 + result = handshake_req_cancel(sock->sk); 414 + 415 + /* Assert */ 416 + KUNIT_EXPECT_FALSE(test, result); 417 + 418 + sock_release(sock); 419 + } 420 + 421 + static struct handshake_req *handshake_req_destroy_test; 422 + 423 + static void test_destroy_func(struct handshake_req *req) 424 + { 425 + handshake_req_destroy_test = req; 426 + } 427 + 428 + static struct handshake_proto handshake_req_alloc_proto_destroy = { 429 + .hp_handler_class = HANDSHAKE_HANDLER_CLASS_TLSHD, 430 + .hp_accept = test_accept_func, 431 + .hp_done = test_done_func, 432 + .hp_destroy = test_destroy_func, 433 + }; 434 + 435 + static void handshake_req_destroy_test1(struct kunit *test) 436 + { 437 + struct handshake_req *req; 438 + struct socket *sock; 439 + int err; 440 + 441 + /* Arrange */ 442 + handshake_req_destroy_test = NULL; 443 + 444 + req = handshake_req_alloc(&handshake_req_alloc_proto_destroy, GFP_KERNEL); 445 + KUNIT_ASSERT_NOT_NULL(test, req); 446 + 447 + err = __sock_create(&init_net, PF_INET, SOCK_STREAM, IPPROTO_TCP, 448 + &sock, 1); 449 + KUNIT_ASSERT_EQ(test, err, 0); 450 + 451 + sock->file = sock_alloc_file(sock, O_NONBLOCK, NULL); 452 + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, sock->file); 453 + 454 + err = handshake_req_submit(sock, req, GFP_KERNEL); 455 + KUNIT_ASSERT_EQ(test, err, 0); 456 + 457 + handshake_req_cancel(sock->sk); 458 + 459 + /* Act */ 460 + sock_release(sock); 461 + 462 + /* Assert */ 463 + KUNIT_EXPECT_PTR_EQ(test, handshake_req_destroy_test, req); 464 + } 465 + 466 + static struct kunit_case handshake_api_test_cases[] = { 467 + { 468 + .name = "req_alloc API fuzzing", 469 + .run_case = handshake_req_alloc_case, 470 + .generate_params = handshake_req_alloc_gen_params, 471 + }, 472 + { 473 + .name = "req_submit NULL req arg", 474 + .run_case = handshake_req_submit_test1, 475 + }, 476 + { 477 + .name = "req_submit NULL sock arg", 478 + .run_case = handshake_req_submit_test2, 479 + }, 480 + { 481 + .name = "req_submit NULL sock->file", 482 + .run_case = handshake_req_submit_test3, 483 + }, 484 + { 485 + .name = "req_lookup works", 486 + .run_case = handshake_req_submit_test4, 487 + }, 488 + { 489 + .name = "req_submit max pending", 490 + .run_case = handshake_req_submit_test5, 491 + }, 492 + { 493 + .name = "req_submit multiple", 494 + .run_case = handshake_req_submit_test6, 495 + }, 496 + { 497 + .name = "req_cancel before accept", 498 + .run_case = handshake_req_cancel_test1, 499 + }, 500 + { 501 + .name = "req_cancel after accept", 502 + .run_case = handshake_req_cancel_test2, 503 + }, 504 + { 505 + .name = "req_cancel after done", 506 + .run_case = handshake_req_cancel_test3, 507 + }, 508 + { 509 + .name = "req_destroy works", 510 + .run_case = handshake_req_destroy_test1, 511 + }, 512 + {} 513 + }; 514 + 515 + static struct kunit_suite handshake_api_suite = { 516 + .name = "Handshake API tests", 517 + .test_cases = handshake_api_test_cases, 518 + }; 519 + 520 + kunit_test_suites(&handshake_api_suite); 521 + 522 + MODULE_DESCRIPTION("Test handshake upcall API functions"); 523 + MODULE_LICENSE("GPL");
+87
net/handshake/handshake.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-only */ 2 + /* 3 + * Generic netlink handshake service 4 + * 5 + * Author: Chuck Lever <chuck.lever@oracle.com> 6 + * 7 + * Copyright (c) 2023, Oracle and/or its affiliates. 8 + */ 9 + 10 + #ifndef _INTERNAL_HANDSHAKE_H 11 + #define _INTERNAL_HANDSHAKE_H 12 + 13 + /* Per-net namespace context */ 14 + struct handshake_net { 15 + spinlock_t hn_lock; /* protects next 3 fields */ 16 + int hn_pending; 17 + int hn_pending_max; 18 + struct list_head hn_requests; 19 + 20 + unsigned long hn_flags; 21 + }; 22 + 23 + enum hn_flags_bits { 24 + HANDSHAKE_F_NET_DRAINING, 25 + }; 26 + 27 + struct handshake_proto; 28 + 29 + /* One handshake request */ 30 + struct handshake_req { 31 + struct list_head hr_list; 32 + struct rhash_head hr_rhash; 33 + unsigned long hr_flags; 34 + const struct handshake_proto *hr_proto; 35 + struct sock *hr_sk; 36 + void (*hr_odestruct)(struct sock *sk); 37 + 38 + /* Always the last field */ 39 + char hr_priv[]; 40 + }; 41 + 42 + enum hr_flags_bits { 43 + HANDSHAKE_F_REQ_COMPLETED, 44 + }; 45 + 46 + /* Invariants for all handshake requests for one transport layer 47 + * security protocol 48 + */ 49 + struct handshake_proto { 50 + int hp_handler_class; 51 + size_t hp_privsize; 52 + unsigned long hp_flags; 53 + 54 + int (*hp_accept)(struct handshake_req *req, 55 + struct genl_info *info, int fd); 56 + void (*hp_done)(struct handshake_req *req, 57 + unsigned int status, 58 + struct genl_info *info); 59 + void (*hp_destroy)(struct handshake_req *req); 60 + }; 61 + 62 + enum hp_flags_bits { 63 + HANDSHAKE_F_PROTO_NOTIFY, 64 + }; 65 + 66 + /* netlink.c */ 67 + int handshake_genl_notify(struct net *net, const struct handshake_proto *proto, 68 + gfp_t flags); 69 + struct nlmsghdr *handshake_genl_put(struct sk_buff *msg, 70 + struct genl_info *info); 71 + struct handshake_net *handshake_pernet(struct net *net); 72 + 73 + /* request.c */ 74 + struct handshake_req *handshake_req_alloc(const struct handshake_proto *proto, 75 + gfp_t flags); 76 + int handshake_req_hash_init(void); 77 + void handshake_req_hash_destroy(void); 78 + void *handshake_req_private(struct handshake_req *req); 79 + struct handshake_req *handshake_req_hash_lookup(struct sock *sk); 80 + struct handshake_req *handshake_req_next(struct handshake_net *hn, int class); 81 + int handshake_req_submit(struct socket *sock, struct handshake_req *req, 82 + gfp_t flags); 83 + void handshake_complete(struct handshake_req *req, unsigned int status, 84 + struct genl_info *info); 85 + bool handshake_req_cancel(struct sock *sk); 86 + 87 + #endif /* _INTERNAL_HANDSHAKE_H */
+319
net/handshake/netlink.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * Generic netlink handshake service 4 + * 5 + * Author: Chuck Lever <chuck.lever@oracle.com> 6 + * 7 + * Copyright (c) 2023, Oracle and/or its affiliates. 8 + */ 9 + 10 + #include <linux/types.h> 11 + #include <linux/socket.h> 12 + #include <linux/kernel.h> 13 + #include <linux/module.h> 14 + #include <linux/skbuff.h> 15 + #include <linux/mm.h> 16 + 17 + #include <net/sock.h> 18 + #include <net/genetlink.h> 19 + #include <net/netns/generic.h> 20 + 21 + #include <kunit/visibility.h> 22 + 23 + #include <uapi/linux/handshake.h> 24 + #include "handshake.h" 25 + #include "genl.h" 26 + 27 + #include <trace/events/handshake.h> 28 + 29 + /** 30 + * handshake_genl_notify - Notify handlers that a request is waiting 31 + * @net: target network namespace 32 + * @proto: handshake protocol 33 + * @flags: memory allocation control flags 34 + * 35 + * Returns zero on success or a negative errno if notification failed. 36 + */ 37 + int handshake_genl_notify(struct net *net, const struct handshake_proto *proto, 38 + gfp_t flags) 39 + { 40 + struct sk_buff *msg; 41 + void *hdr; 42 + 43 + /* Disable notifications during unit testing */ 44 + if (!test_bit(HANDSHAKE_F_PROTO_NOTIFY, &proto->hp_flags)) 45 + return 0; 46 + 47 + if (!genl_has_listeners(&handshake_nl_family, net, 48 + proto->hp_handler_class)) 49 + return -ESRCH; 50 + 51 + msg = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL); 52 + if (!msg) 53 + return -ENOMEM; 54 + 55 + hdr = genlmsg_put(msg, 0, 0, &handshake_nl_family, 0, 56 + HANDSHAKE_CMD_READY); 57 + if (!hdr) 58 + goto out_free; 59 + 60 + if (nla_put_u32(msg, HANDSHAKE_A_ACCEPT_HANDLER_CLASS, 61 + proto->hp_handler_class) < 0) { 62 + genlmsg_cancel(msg, hdr); 63 + goto out_free; 64 + } 65 + 66 + genlmsg_end(msg, hdr); 67 + return genlmsg_multicast_netns(&handshake_nl_family, net, msg, 68 + 0, proto->hp_handler_class, flags); 69 + 70 + out_free: 71 + nlmsg_free(msg); 72 + return -EMSGSIZE; 73 + } 74 + 75 + /** 76 + * handshake_genl_put - Create a generic netlink message header 77 + * @msg: buffer in which to create the header 78 + * @info: generic netlink message context 79 + * 80 + * Returns a ready-to-use header, or NULL. 81 + */ 82 + struct nlmsghdr *handshake_genl_put(struct sk_buff *msg, 83 + struct genl_info *info) 84 + { 85 + return genlmsg_put(msg, info->snd_portid, info->snd_seq, 86 + &handshake_nl_family, 0, info->genlhdr->cmd); 87 + } 88 + EXPORT_SYMBOL(handshake_genl_put); 89 + 90 + /* 91 + * dup() a kernel socket for use as a user space file descriptor 92 + * in the current process. The kernel socket must have an 93 + * instatiated struct file. 94 + * 95 + * Implicit argument: "current()" 96 + */ 97 + static int handshake_dup(struct socket *sock) 98 + { 99 + struct file *file; 100 + int newfd; 101 + 102 + if (!sock->file) 103 + return -EBADF; 104 + 105 + file = get_file(sock->file); 106 + newfd = get_unused_fd_flags(O_CLOEXEC); 107 + if (newfd < 0) { 108 + fput(file); 109 + return newfd; 110 + } 111 + 112 + fd_install(newfd, file); 113 + return newfd; 114 + } 115 + 116 + int handshake_nl_accept_doit(struct sk_buff *skb, struct genl_info *info) 117 + { 118 + struct net *net = sock_net(skb->sk); 119 + struct handshake_net *hn = handshake_pernet(net); 120 + struct handshake_req *req = NULL; 121 + struct socket *sock; 122 + int class, fd, err; 123 + 124 + err = -EOPNOTSUPP; 125 + if (!hn) 126 + goto out_status; 127 + 128 + err = -EINVAL; 129 + if (GENL_REQ_ATTR_CHECK(info, HANDSHAKE_A_ACCEPT_HANDLER_CLASS)) 130 + goto out_status; 131 + class = nla_get_u32(info->attrs[HANDSHAKE_A_ACCEPT_HANDLER_CLASS]); 132 + 133 + err = -EAGAIN; 134 + req = handshake_req_next(hn, class); 135 + if (!req) 136 + goto out_status; 137 + 138 + sock = req->hr_sk->sk_socket; 139 + fd = handshake_dup(sock); 140 + if (fd < 0) { 141 + err = fd; 142 + goto out_complete; 143 + } 144 + err = req->hr_proto->hp_accept(req, info, fd); 145 + if (err) 146 + goto out_complete; 147 + 148 + trace_handshake_cmd_accept(net, req, req->hr_sk, fd); 149 + return 0; 150 + 151 + out_complete: 152 + handshake_complete(req, -EIO, NULL); 153 + fput(sock->file); 154 + out_status: 155 + trace_handshake_cmd_accept_err(net, req, NULL, err); 156 + return err; 157 + } 158 + 159 + int handshake_nl_done_doit(struct sk_buff *skb, struct genl_info *info) 160 + { 161 + struct net *net = sock_net(skb->sk); 162 + struct socket *sock = NULL; 163 + struct handshake_req *req; 164 + int fd, status, err; 165 + 166 + if (GENL_REQ_ATTR_CHECK(info, HANDSHAKE_A_DONE_SOCKFD)) 167 + return -EINVAL; 168 + fd = nla_get_u32(info->attrs[HANDSHAKE_A_DONE_SOCKFD]); 169 + 170 + err = 0; 171 + sock = sockfd_lookup(fd, &err); 172 + if (err) { 173 + err = -EBADF; 174 + goto out_status; 175 + } 176 + 177 + req = handshake_req_hash_lookup(sock->sk); 178 + if (!req) { 179 + err = -EBUSY; 180 + fput(sock->file); 181 + goto out_status; 182 + } 183 + 184 + trace_handshake_cmd_done(net, req, sock->sk, fd); 185 + 186 + status = -EIO; 187 + if (info->attrs[HANDSHAKE_A_DONE_STATUS]) 188 + status = nla_get_u32(info->attrs[HANDSHAKE_A_DONE_STATUS]); 189 + 190 + handshake_complete(req, status, info); 191 + fput(sock->file); 192 + return 0; 193 + 194 + out_status: 195 + trace_handshake_cmd_done_err(net, req, sock->sk, err); 196 + return err; 197 + } 198 + 199 + static unsigned int handshake_net_id; 200 + 201 + static int __net_init handshake_net_init(struct net *net) 202 + { 203 + struct handshake_net *hn = net_generic(net, handshake_net_id); 204 + unsigned long tmp; 205 + struct sysinfo si; 206 + 207 + /* 208 + * Arbitrary limit to prevent handshakes that do not make 209 + * progress from clogging up the system. The cap scales up 210 + * with the amount of physical memory on the system. 211 + */ 212 + si_meminfo(&si); 213 + tmp = si.totalram / (25 * si.mem_unit); 214 + hn->hn_pending_max = clamp(tmp, 3UL, 50UL); 215 + 216 + spin_lock_init(&hn->hn_lock); 217 + hn->hn_pending = 0; 218 + hn->hn_flags = 0; 219 + INIT_LIST_HEAD(&hn->hn_requests); 220 + return 0; 221 + } 222 + 223 + static void __net_exit handshake_net_exit(struct net *net) 224 + { 225 + struct handshake_net *hn = net_generic(net, handshake_net_id); 226 + struct handshake_req *req; 227 + LIST_HEAD(requests); 228 + 229 + /* 230 + * Drain the net's pending list. Requests that have been 231 + * accepted and are in progress will be destroyed when 232 + * the socket is closed. 233 + */ 234 + spin_lock(&hn->hn_lock); 235 + set_bit(HANDSHAKE_F_NET_DRAINING, &hn->hn_flags); 236 + list_splice_init(&requests, &hn->hn_requests); 237 + spin_unlock(&hn->hn_lock); 238 + 239 + while (!list_empty(&requests)) { 240 + req = list_first_entry(&requests, struct handshake_req, hr_list); 241 + list_del(&req->hr_list); 242 + 243 + /* 244 + * Requests on this list have not yet been 245 + * accepted, so they do not have an fd to put. 246 + */ 247 + 248 + handshake_complete(req, -ETIMEDOUT, NULL); 249 + } 250 + } 251 + 252 + static struct pernet_operations __net_initdata handshake_genl_net_ops = { 253 + .init = handshake_net_init, 254 + .exit = handshake_net_exit, 255 + .id = &handshake_net_id, 256 + .size = sizeof(struct handshake_net), 257 + }; 258 + 259 + /** 260 + * handshake_pernet - Get the handshake private per-net structure 261 + * @net: network namespace 262 + * 263 + * Returns a pointer to the net's private per-net structure for the 264 + * handshake module, or NULL if handshake_init() failed. 265 + */ 266 + struct handshake_net *handshake_pernet(struct net *net) 267 + { 268 + return handshake_net_id ? 269 + net_generic(net, handshake_net_id) : NULL; 270 + } 271 + EXPORT_SYMBOL_IF_KUNIT(handshake_pernet); 272 + 273 + static int __init handshake_init(void) 274 + { 275 + int ret; 276 + 277 + ret = handshake_req_hash_init(); 278 + if (ret) { 279 + pr_warn("handshake: hash initialization failed (%d)\n", ret); 280 + return ret; 281 + } 282 + 283 + ret = genl_register_family(&handshake_nl_family); 284 + if (ret) { 285 + pr_warn("handshake: netlink registration failed (%d)\n", ret); 286 + handshake_req_hash_destroy(); 287 + return ret; 288 + } 289 + 290 + /* 291 + * ORDER: register_pernet_subsys must be done last. 292 + * 293 + * If initialization does not make it past pernet_subsys 294 + * registration, then handshake_net_id will remain 0. That 295 + * shunts the handshake consumer API to return ENOTSUPP 296 + * to prevent it from dereferencing something that hasn't 297 + * been allocated. 298 + */ 299 + ret = register_pernet_subsys(&handshake_genl_net_ops); 300 + if (ret) { 301 + pr_warn("handshake: pernet registration failed (%d)\n", ret); 302 + genl_unregister_family(&handshake_nl_family); 303 + handshake_req_hash_destroy(); 304 + } 305 + 306 + return ret; 307 + } 308 + 309 + static void __exit handshake_exit(void) 310 + { 311 + unregister_pernet_subsys(&handshake_genl_net_ops); 312 + handshake_net_id = 0; 313 + 314 + handshake_req_hash_destroy(); 315 + genl_unregister_family(&handshake_nl_family); 316 + } 317 + 318 + module_init(handshake_init); 319 + module_exit(handshake_exit);
+344
net/handshake/request.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * Handshake request lifetime events 4 + * 5 + * Author: Chuck Lever <chuck.lever@oracle.com> 6 + * 7 + * Copyright (c) 2023, Oracle and/or its affiliates. 8 + */ 9 + 10 + #include <linux/types.h> 11 + #include <linux/socket.h> 12 + #include <linux/kernel.h> 13 + #include <linux/module.h> 14 + #include <linux/skbuff.h> 15 + #include <linux/inet.h> 16 + #include <linux/fdtable.h> 17 + #include <linux/rhashtable.h> 18 + 19 + #include <net/sock.h> 20 + #include <net/genetlink.h> 21 + #include <net/netns/generic.h> 22 + 23 + #include <kunit/visibility.h> 24 + 25 + #include <uapi/linux/handshake.h> 26 + #include "handshake.h" 27 + 28 + #include <trace/events/handshake.h> 29 + 30 + /* 31 + * We need both a handshake_req -> sock mapping, and a sock -> 32 + * handshake_req mapping. Both are one-to-one. 33 + * 34 + * To avoid adding another pointer field to struct sock, net/handshake 35 + * maintains a hash table, indexed by the memory address of @sock, to 36 + * find the struct handshake_req outstanding for that socket. The 37 + * reverse direction uses a simple pointer field in the handshake_req 38 + * struct. 39 + */ 40 + 41 + static struct rhashtable handshake_rhashtbl ____cacheline_aligned_in_smp; 42 + 43 + static const struct rhashtable_params handshake_rhash_params = { 44 + .key_len = sizeof_field(struct handshake_req, hr_sk), 45 + .key_offset = offsetof(struct handshake_req, hr_sk), 46 + .head_offset = offsetof(struct handshake_req, hr_rhash), 47 + .automatic_shrinking = true, 48 + }; 49 + 50 + int handshake_req_hash_init(void) 51 + { 52 + return rhashtable_init(&handshake_rhashtbl, &handshake_rhash_params); 53 + } 54 + 55 + void handshake_req_hash_destroy(void) 56 + { 57 + rhashtable_destroy(&handshake_rhashtbl); 58 + } 59 + 60 + struct handshake_req *handshake_req_hash_lookup(struct sock *sk) 61 + { 62 + return rhashtable_lookup_fast(&handshake_rhashtbl, &sk, 63 + handshake_rhash_params); 64 + } 65 + EXPORT_SYMBOL_IF_KUNIT(handshake_req_hash_lookup); 66 + 67 + static bool handshake_req_hash_add(struct handshake_req *req) 68 + { 69 + int ret; 70 + 71 + ret = rhashtable_lookup_insert_fast(&handshake_rhashtbl, 72 + &req->hr_rhash, 73 + handshake_rhash_params); 74 + return ret == 0; 75 + } 76 + 77 + static void handshake_req_destroy(struct handshake_req *req) 78 + { 79 + if (req->hr_proto->hp_destroy) 80 + req->hr_proto->hp_destroy(req); 81 + rhashtable_remove_fast(&handshake_rhashtbl, &req->hr_rhash, 82 + handshake_rhash_params); 83 + kfree(req); 84 + } 85 + 86 + static void handshake_sk_destruct(struct sock *sk) 87 + { 88 + void (*sk_destruct)(struct sock *sk); 89 + struct handshake_req *req; 90 + 91 + req = handshake_req_hash_lookup(sk); 92 + if (!req) 93 + return; 94 + 95 + trace_handshake_destruct(sock_net(sk), req, sk); 96 + sk_destruct = req->hr_odestruct; 97 + handshake_req_destroy(req); 98 + if (sk_destruct) 99 + sk_destruct(sk); 100 + } 101 + 102 + /** 103 + * handshake_req_alloc - Allocate a handshake request 104 + * @proto: security protocol 105 + * @flags: memory allocation flags 106 + * 107 + * Returns an initialized handshake_req or NULL. 108 + */ 109 + struct handshake_req *handshake_req_alloc(const struct handshake_proto *proto, 110 + gfp_t flags) 111 + { 112 + struct handshake_req *req; 113 + 114 + if (!proto) 115 + return NULL; 116 + if (proto->hp_handler_class <= HANDSHAKE_HANDLER_CLASS_NONE) 117 + return NULL; 118 + if (proto->hp_handler_class >= HANDSHAKE_HANDLER_CLASS_MAX) 119 + return NULL; 120 + if (!proto->hp_accept || !proto->hp_done) 121 + return NULL; 122 + 123 + req = kzalloc(struct_size(req, hr_priv, proto->hp_privsize), flags); 124 + if (!req) 125 + return NULL; 126 + 127 + INIT_LIST_HEAD(&req->hr_list); 128 + req->hr_proto = proto; 129 + return req; 130 + } 131 + EXPORT_SYMBOL(handshake_req_alloc); 132 + 133 + /** 134 + * handshake_req_private - Get per-handshake private data 135 + * @req: handshake arguments 136 + * 137 + */ 138 + void *handshake_req_private(struct handshake_req *req) 139 + { 140 + return (void *)&req->hr_priv; 141 + } 142 + EXPORT_SYMBOL(handshake_req_private); 143 + 144 + static bool __add_pending_locked(struct handshake_net *hn, 145 + struct handshake_req *req) 146 + { 147 + if (WARN_ON_ONCE(!list_empty(&req->hr_list))) 148 + return false; 149 + hn->hn_pending++; 150 + list_add_tail(&req->hr_list, &hn->hn_requests); 151 + return true; 152 + } 153 + 154 + static void __remove_pending_locked(struct handshake_net *hn, 155 + struct handshake_req *req) 156 + { 157 + hn->hn_pending--; 158 + list_del_init(&req->hr_list); 159 + } 160 + 161 + /* 162 + * Returns %true if the request was found on @net's pending list, 163 + * otherwise %false. 164 + * 165 + * If @req was on a pending list, it has not yet been accepted. 166 + */ 167 + static bool remove_pending(struct handshake_net *hn, struct handshake_req *req) 168 + { 169 + bool ret = false; 170 + 171 + spin_lock(&hn->hn_lock); 172 + if (!list_empty(&req->hr_list)) { 173 + __remove_pending_locked(hn, req); 174 + ret = true; 175 + } 176 + spin_unlock(&hn->hn_lock); 177 + 178 + return ret; 179 + } 180 + 181 + struct handshake_req *handshake_req_next(struct handshake_net *hn, int class) 182 + { 183 + struct handshake_req *req, *pos; 184 + 185 + req = NULL; 186 + spin_lock(&hn->hn_lock); 187 + list_for_each_entry(pos, &hn->hn_requests, hr_list) { 188 + if (pos->hr_proto->hp_handler_class != class) 189 + continue; 190 + __remove_pending_locked(hn, pos); 191 + req = pos; 192 + break; 193 + } 194 + spin_unlock(&hn->hn_lock); 195 + 196 + return req; 197 + } 198 + EXPORT_SYMBOL_IF_KUNIT(handshake_req_next); 199 + 200 + /** 201 + * handshake_req_submit - Submit a handshake request 202 + * @sock: open socket on which to perform the handshake 203 + * @req: handshake arguments 204 + * @flags: memory allocation flags 205 + * 206 + * Return values: 207 + * %0: Request queued 208 + * %-EINVAL: Invalid argument 209 + * %-EBUSY: A handshake is already under way for this socket 210 + * %-ESRCH: No handshake agent is available 211 + * %-EAGAIN: Too many pending handshake requests 212 + * %-ENOMEM: Failed to allocate memory 213 + * %-EMSGSIZE: Failed to construct notification message 214 + * %-EOPNOTSUPP: Handshake module not initialized 215 + * 216 + * A zero return value from handshake_req_submit() means that 217 + * exactly one subsequent completion callback is guaranteed. 218 + * 219 + * A negative return value from handshake_req_submit() means that 220 + * no completion callback will be done and that @req has been 221 + * destroyed. 222 + */ 223 + int handshake_req_submit(struct socket *sock, struct handshake_req *req, 224 + gfp_t flags) 225 + { 226 + struct handshake_net *hn; 227 + struct net *net; 228 + int ret; 229 + 230 + if (!sock || !req || !sock->file) { 231 + kfree(req); 232 + return -EINVAL; 233 + } 234 + 235 + req->hr_sk = sock->sk; 236 + if (!req->hr_sk) { 237 + kfree(req); 238 + return -EINVAL; 239 + } 240 + req->hr_odestruct = req->hr_sk->sk_destruct; 241 + req->hr_sk->sk_destruct = handshake_sk_destruct; 242 + 243 + ret = -EOPNOTSUPP; 244 + net = sock_net(req->hr_sk); 245 + hn = handshake_pernet(net); 246 + if (!hn) 247 + goto out_err; 248 + 249 + ret = -EAGAIN; 250 + if (READ_ONCE(hn->hn_pending) >= hn->hn_pending_max) 251 + goto out_err; 252 + 253 + spin_lock(&hn->hn_lock); 254 + ret = -EOPNOTSUPP; 255 + if (test_bit(HANDSHAKE_F_NET_DRAINING, &hn->hn_flags)) 256 + goto out_unlock; 257 + ret = -EBUSY; 258 + if (!handshake_req_hash_add(req)) 259 + goto out_unlock; 260 + if (!__add_pending_locked(hn, req)) 261 + goto out_unlock; 262 + spin_unlock(&hn->hn_lock); 263 + 264 + ret = handshake_genl_notify(net, req->hr_proto, flags); 265 + if (ret) { 266 + trace_handshake_notify_err(net, req, req->hr_sk, ret); 267 + if (remove_pending(hn, req)) 268 + goto out_err; 269 + } 270 + 271 + /* Prevent socket release while a handshake request is pending */ 272 + sock_hold(req->hr_sk); 273 + 274 + trace_handshake_submit(net, req, req->hr_sk); 275 + return 0; 276 + 277 + out_unlock: 278 + spin_unlock(&hn->hn_lock); 279 + out_err: 280 + trace_handshake_submit_err(net, req, req->hr_sk, ret); 281 + handshake_req_destroy(req); 282 + return ret; 283 + } 284 + EXPORT_SYMBOL(handshake_req_submit); 285 + 286 + void handshake_complete(struct handshake_req *req, unsigned int status, 287 + struct genl_info *info) 288 + { 289 + struct sock *sk = req->hr_sk; 290 + struct net *net = sock_net(sk); 291 + 292 + if (!test_and_set_bit(HANDSHAKE_F_REQ_COMPLETED, &req->hr_flags)) { 293 + trace_handshake_complete(net, req, sk, status); 294 + req->hr_proto->hp_done(req, status, info); 295 + 296 + /* Handshake request is no longer pending */ 297 + sock_put(sk); 298 + } 299 + } 300 + EXPORT_SYMBOL_IF_KUNIT(handshake_complete); 301 + 302 + /** 303 + * handshake_req_cancel - Cancel an in-progress handshake 304 + * @sk: socket on which there is an ongoing handshake 305 + * 306 + * Request cancellation races with request completion. To determine 307 + * who won, callers examine the return value from this function. 308 + * 309 + * Return values: 310 + * %true - Uncompleted handshake request was canceled 311 + * %false - Handshake request already completed or not found 312 + */ 313 + bool handshake_req_cancel(struct sock *sk) 314 + { 315 + struct handshake_req *req; 316 + struct handshake_net *hn; 317 + struct net *net; 318 + 319 + net = sock_net(sk); 320 + req = handshake_req_hash_lookup(sk); 321 + if (!req) { 322 + trace_handshake_cancel_none(net, req, sk); 323 + return false; 324 + } 325 + 326 + hn = handshake_pernet(net); 327 + if (hn && remove_pending(hn, req)) { 328 + /* Request hadn't been accepted */ 329 + goto out_true; 330 + } 331 + if (test_and_set_bit(HANDSHAKE_F_REQ_COMPLETED, &req->hr_flags)) { 332 + /* Request already completed */ 333 + trace_handshake_cancel_busy(net, req, sk); 334 + return false; 335 + } 336 + 337 + out_true: 338 + trace_handshake_cancel(net, req, sk); 339 + 340 + /* Handshake request is no longer pending */ 341 + sock_put(sk); 342 + return true; 343 + } 344 + EXPORT_SYMBOL(handshake_req_cancel);
+418
net/handshake/tlshd.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * Establish a TLS session for a kernel socket consumer 4 + * using the tlshd user space handler. 5 + * 6 + * Author: Chuck Lever <chuck.lever@oracle.com> 7 + * 8 + * Copyright (c) 2021-2023, Oracle and/or its affiliates. 9 + */ 10 + 11 + #include <linux/types.h> 12 + #include <linux/socket.h> 13 + #include <linux/kernel.h> 14 + #include <linux/module.h> 15 + #include <linux/slab.h> 16 + #include <linux/key.h> 17 + 18 + #include <net/sock.h> 19 + #include <net/handshake.h> 20 + #include <net/genetlink.h> 21 + 22 + #include <uapi/linux/keyctl.h> 23 + #include <uapi/linux/handshake.h> 24 + #include "handshake.h" 25 + 26 + struct tls_handshake_req { 27 + void (*th_consumer_done)(void *data, int status, 28 + key_serial_t peerid); 29 + void *th_consumer_data; 30 + 31 + int th_type; 32 + unsigned int th_timeout_ms; 33 + int th_auth_mode; 34 + key_serial_t th_keyring; 35 + key_serial_t th_certificate; 36 + key_serial_t th_privkey; 37 + 38 + unsigned int th_num_peerids; 39 + key_serial_t th_peerid[5]; 40 + }; 41 + 42 + static struct tls_handshake_req * 43 + tls_handshake_req_init(struct handshake_req *req, 44 + const struct tls_handshake_args *args) 45 + { 46 + struct tls_handshake_req *treq = handshake_req_private(req); 47 + 48 + treq->th_timeout_ms = args->ta_timeout_ms; 49 + treq->th_consumer_done = args->ta_done; 50 + treq->th_consumer_data = args->ta_data; 51 + treq->th_keyring = args->ta_keyring; 52 + treq->th_num_peerids = 0; 53 + treq->th_certificate = TLS_NO_CERT; 54 + treq->th_privkey = TLS_NO_PRIVKEY; 55 + return treq; 56 + } 57 + 58 + static void tls_handshake_remote_peerids(struct tls_handshake_req *treq, 59 + struct genl_info *info) 60 + { 61 + struct nlattr *head = nlmsg_attrdata(info->nlhdr, GENL_HDRLEN); 62 + int rem, len = nlmsg_attrlen(info->nlhdr, GENL_HDRLEN); 63 + struct nlattr *nla; 64 + unsigned int i; 65 + 66 + i = 0; 67 + nla_for_each_attr(nla, head, len, rem) { 68 + if (nla_type(nla) == HANDSHAKE_A_DONE_REMOTE_AUTH) 69 + i++; 70 + } 71 + if (!i) 72 + return; 73 + treq->th_num_peerids = min_t(unsigned int, i, 74 + ARRAY_SIZE(treq->th_peerid)); 75 + 76 + i = 0; 77 + nla_for_each_attr(nla, head, len, rem) { 78 + if (nla_type(nla) == HANDSHAKE_A_DONE_REMOTE_AUTH) 79 + treq->th_peerid[i++] = nla_get_u32(nla); 80 + if (i >= treq->th_num_peerids) 81 + break; 82 + } 83 + } 84 + 85 + /** 86 + * tls_handshake_done - callback to handle a CMD_DONE request 87 + * @req: socket on which the handshake was performed 88 + * @status: session status code 89 + * @info: full results of session establishment 90 + * 91 + */ 92 + static void tls_handshake_done(struct handshake_req *req, 93 + unsigned int status, struct genl_info *info) 94 + { 95 + struct tls_handshake_req *treq = handshake_req_private(req); 96 + 97 + treq->th_peerid[0] = TLS_NO_PEERID; 98 + if (info) 99 + tls_handshake_remote_peerids(treq, info); 100 + 101 + treq->th_consumer_done(treq->th_consumer_data, -status, 102 + treq->th_peerid[0]); 103 + } 104 + 105 + #if IS_ENABLED(CONFIG_KEYS) 106 + static int tls_handshake_private_keyring(struct tls_handshake_req *treq) 107 + { 108 + key_ref_t process_keyring_ref, keyring_ref; 109 + int ret; 110 + 111 + if (treq->th_keyring == TLS_NO_KEYRING) 112 + return 0; 113 + 114 + process_keyring_ref = lookup_user_key(KEY_SPEC_PROCESS_KEYRING, 115 + KEY_LOOKUP_CREATE, 116 + KEY_NEED_WRITE); 117 + if (IS_ERR(process_keyring_ref)) { 118 + ret = PTR_ERR(process_keyring_ref); 119 + goto out; 120 + } 121 + 122 + keyring_ref = lookup_user_key(treq->th_keyring, KEY_LOOKUP_CREATE, 123 + KEY_NEED_LINK); 124 + if (IS_ERR(keyring_ref)) { 125 + ret = PTR_ERR(keyring_ref); 126 + goto out_put_key; 127 + } 128 + 129 + ret = key_link(key_ref_to_ptr(process_keyring_ref), 130 + key_ref_to_ptr(keyring_ref)); 131 + 132 + key_ref_put(keyring_ref); 133 + out_put_key: 134 + key_ref_put(process_keyring_ref); 135 + out: 136 + return ret; 137 + } 138 + #else 139 + static int tls_handshake_private_keyring(struct tls_handshake_req *treq) 140 + { 141 + return 0; 142 + } 143 + #endif 144 + 145 + static int tls_handshake_put_peer_identity(struct sk_buff *msg, 146 + struct tls_handshake_req *treq) 147 + { 148 + unsigned int i; 149 + 150 + for (i = 0; i < treq->th_num_peerids; i++) 151 + if (nla_put_u32(msg, HANDSHAKE_A_ACCEPT_PEER_IDENTITY, 152 + treq->th_peerid[i]) < 0) 153 + return -EMSGSIZE; 154 + return 0; 155 + } 156 + 157 + static int tls_handshake_put_certificate(struct sk_buff *msg, 158 + struct tls_handshake_req *treq) 159 + { 160 + struct nlattr *entry_attr; 161 + 162 + if (treq->th_certificate == TLS_NO_CERT && 163 + treq->th_privkey == TLS_NO_PRIVKEY) 164 + return 0; 165 + 166 + entry_attr = nla_nest_start(msg, HANDSHAKE_A_ACCEPT_CERTIFICATE); 167 + if (!entry_attr) 168 + return -EMSGSIZE; 169 + 170 + if (nla_put_u32(msg, HANDSHAKE_A_X509_CERT, 171 + treq->th_certificate) || 172 + nla_put_u32(msg, HANDSHAKE_A_X509_PRIVKEY, 173 + treq->th_privkey)) { 174 + nla_nest_cancel(msg, entry_attr); 175 + return -EMSGSIZE; 176 + } 177 + 178 + nla_nest_end(msg, entry_attr); 179 + return 0; 180 + } 181 + 182 + /** 183 + * tls_handshake_accept - callback to construct a CMD_ACCEPT response 184 + * @req: handshake parameters to return 185 + * @info: generic netlink message context 186 + * @fd: file descriptor to be returned 187 + * 188 + * Returns zero on success, or a negative errno on failure. 189 + */ 190 + static int tls_handshake_accept(struct handshake_req *req, 191 + struct genl_info *info, int fd) 192 + { 193 + struct tls_handshake_req *treq = handshake_req_private(req); 194 + struct nlmsghdr *hdr; 195 + struct sk_buff *msg; 196 + int ret; 197 + 198 + ret = tls_handshake_private_keyring(treq); 199 + if (ret < 0) 200 + goto out; 201 + 202 + ret = -ENOMEM; 203 + msg = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL); 204 + if (!msg) 205 + goto out; 206 + hdr = handshake_genl_put(msg, info); 207 + if (!hdr) 208 + goto out_cancel; 209 + 210 + ret = -EMSGSIZE; 211 + ret = nla_put_u32(msg, HANDSHAKE_A_ACCEPT_SOCKFD, fd); 212 + if (ret < 0) 213 + goto out_cancel; 214 + ret = nla_put_u32(msg, HANDSHAKE_A_ACCEPT_MESSAGE_TYPE, treq->th_type); 215 + if (ret < 0) 216 + goto out_cancel; 217 + if (treq->th_timeout_ms) { 218 + ret = nla_put_u32(msg, HANDSHAKE_A_ACCEPT_TIMEOUT, treq->th_timeout_ms); 219 + if (ret < 0) 220 + goto out_cancel; 221 + } 222 + 223 + ret = nla_put_u32(msg, HANDSHAKE_A_ACCEPT_AUTH_MODE, 224 + treq->th_auth_mode); 225 + if (ret < 0) 226 + goto out_cancel; 227 + switch (treq->th_auth_mode) { 228 + case HANDSHAKE_AUTH_PSK: 229 + ret = tls_handshake_put_peer_identity(msg, treq); 230 + if (ret < 0) 231 + goto out_cancel; 232 + break; 233 + case HANDSHAKE_AUTH_X509: 234 + ret = tls_handshake_put_certificate(msg, treq); 235 + if (ret < 0) 236 + goto out_cancel; 237 + break; 238 + } 239 + 240 + genlmsg_end(msg, hdr); 241 + return genlmsg_reply(msg, info); 242 + 243 + out_cancel: 244 + genlmsg_cancel(msg, hdr); 245 + out: 246 + return ret; 247 + } 248 + 249 + static const struct handshake_proto tls_handshake_proto = { 250 + .hp_handler_class = HANDSHAKE_HANDLER_CLASS_TLSHD, 251 + .hp_privsize = sizeof(struct tls_handshake_req), 252 + .hp_flags = BIT(HANDSHAKE_F_PROTO_NOTIFY), 253 + 254 + .hp_accept = tls_handshake_accept, 255 + .hp_done = tls_handshake_done, 256 + }; 257 + 258 + /** 259 + * tls_client_hello_anon - request an anonymous TLS handshake on a socket 260 + * @args: socket and handshake parameters for this request 261 + * @flags: memory allocation control flags 262 + * 263 + * Return values: 264 + * %0: Handshake request enqueue; ->done will be called when complete 265 + * %-ESRCH: No user agent is available 266 + * %-ENOMEM: Memory allocation failed 267 + */ 268 + int tls_client_hello_anon(const struct tls_handshake_args *args, gfp_t flags) 269 + { 270 + struct tls_handshake_req *treq; 271 + struct handshake_req *req; 272 + 273 + req = handshake_req_alloc(&tls_handshake_proto, flags); 274 + if (!req) 275 + return -ENOMEM; 276 + treq = tls_handshake_req_init(req, args); 277 + treq->th_type = HANDSHAKE_MSG_TYPE_CLIENTHELLO; 278 + treq->th_auth_mode = HANDSHAKE_AUTH_UNAUTH; 279 + 280 + return handshake_req_submit(args->ta_sock, req, flags); 281 + } 282 + EXPORT_SYMBOL(tls_client_hello_anon); 283 + 284 + /** 285 + * tls_client_hello_x509 - request an x.509-based TLS handshake on a socket 286 + * @args: socket and handshake parameters for this request 287 + * @flags: memory allocation control flags 288 + * 289 + * Return values: 290 + * %0: Handshake request enqueue; ->done will be called when complete 291 + * %-ESRCH: No user agent is available 292 + * %-ENOMEM: Memory allocation failed 293 + */ 294 + int tls_client_hello_x509(const struct tls_handshake_args *args, gfp_t flags) 295 + { 296 + struct tls_handshake_req *treq; 297 + struct handshake_req *req; 298 + 299 + req = handshake_req_alloc(&tls_handshake_proto, flags); 300 + if (!req) 301 + return -ENOMEM; 302 + treq = tls_handshake_req_init(req, args); 303 + treq->th_type = HANDSHAKE_MSG_TYPE_CLIENTHELLO; 304 + treq->th_auth_mode = HANDSHAKE_AUTH_X509; 305 + treq->th_certificate = args->ta_my_cert; 306 + treq->th_privkey = args->ta_my_privkey; 307 + 308 + return handshake_req_submit(args->ta_sock, req, flags); 309 + } 310 + EXPORT_SYMBOL(tls_client_hello_x509); 311 + 312 + /** 313 + * tls_client_hello_psk - request a PSK-based TLS handshake on a socket 314 + * @args: socket and handshake parameters for this request 315 + * @flags: memory allocation control flags 316 + * 317 + * Return values: 318 + * %0: Handshake request enqueue; ->done will be called when complete 319 + * %-EINVAL: Wrong number of local peer IDs 320 + * %-ESRCH: No user agent is available 321 + * %-ENOMEM: Memory allocation failed 322 + */ 323 + int tls_client_hello_psk(const struct tls_handshake_args *args, gfp_t flags) 324 + { 325 + struct tls_handshake_req *treq; 326 + struct handshake_req *req; 327 + unsigned int i; 328 + 329 + if (!args->ta_num_peerids || 330 + args->ta_num_peerids > ARRAY_SIZE(treq->th_peerid)) 331 + return -EINVAL; 332 + 333 + req = handshake_req_alloc(&tls_handshake_proto, flags); 334 + if (!req) 335 + return -ENOMEM; 336 + treq = tls_handshake_req_init(req, args); 337 + treq->th_type = HANDSHAKE_MSG_TYPE_CLIENTHELLO; 338 + treq->th_auth_mode = HANDSHAKE_AUTH_PSK; 339 + treq->th_num_peerids = args->ta_num_peerids; 340 + for (i = 0; i < args->ta_num_peerids; i++) 341 + treq->th_peerid[i] = args->ta_my_peerids[i]; 342 + 343 + return handshake_req_submit(args->ta_sock, req, flags); 344 + } 345 + EXPORT_SYMBOL(tls_client_hello_psk); 346 + 347 + /** 348 + * tls_server_hello_x509 - request a server TLS handshake on a socket 349 + * @args: socket and handshake parameters for this request 350 + * @flags: memory allocation control flags 351 + * 352 + * Return values: 353 + * %0: Handshake request enqueue; ->done will be called when complete 354 + * %-ESRCH: No user agent is available 355 + * %-ENOMEM: Memory allocation failed 356 + */ 357 + int tls_server_hello_x509(const struct tls_handshake_args *args, gfp_t flags) 358 + { 359 + struct tls_handshake_req *treq; 360 + struct handshake_req *req; 361 + 362 + req = handshake_req_alloc(&tls_handshake_proto, flags); 363 + if (!req) 364 + return -ENOMEM; 365 + treq = tls_handshake_req_init(req, args); 366 + treq->th_type = HANDSHAKE_MSG_TYPE_SERVERHELLO; 367 + treq->th_auth_mode = HANDSHAKE_AUTH_X509; 368 + treq->th_certificate = args->ta_my_cert; 369 + treq->th_privkey = args->ta_my_privkey; 370 + 371 + return handshake_req_submit(args->ta_sock, req, flags); 372 + } 373 + EXPORT_SYMBOL(tls_server_hello_x509); 374 + 375 + /** 376 + * tls_server_hello_psk - request a server TLS handshake on a socket 377 + * @args: socket and handshake parameters for this request 378 + * @flags: memory allocation control flags 379 + * 380 + * Return values: 381 + * %0: Handshake request enqueue; ->done will be called when complete 382 + * %-ESRCH: No user agent is available 383 + * %-ENOMEM: Memory allocation failed 384 + */ 385 + int tls_server_hello_psk(const struct tls_handshake_args *args, gfp_t flags) 386 + { 387 + struct tls_handshake_req *treq; 388 + struct handshake_req *req; 389 + 390 + req = handshake_req_alloc(&tls_handshake_proto, flags); 391 + if (!req) 392 + return -ENOMEM; 393 + treq = tls_handshake_req_init(req, args); 394 + treq->th_type = HANDSHAKE_MSG_TYPE_SERVERHELLO; 395 + treq->th_auth_mode = HANDSHAKE_AUTH_PSK; 396 + treq->th_num_peerids = 1; 397 + treq->th_peerid[0] = args->ta_my_peerids[0]; 398 + 399 + return handshake_req_submit(args->ta_sock, req, flags); 400 + } 401 + EXPORT_SYMBOL(tls_server_hello_psk); 402 + 403 + /** 404 + * tls_handshake_cancel - cancel a pending handshake 405 + * @sk: socket on which there is an ongoing handshake 406 + * 407 + * Request cancellation races with request completion. To determine 408 + * who won, callers examine the return value from this function. 409 + * 410 + * Return values: 411 + * %true - Uncompleted handshake request was canceled 412 + * %false - Handshake request already completed or not found 413 + */ 414 + bool tls_handshake_cancel(struct sock *sk) 415 + { 416 + return handshake_req_cancel(sk); 417 + } 418 + EXPORT_SYMBOL(tls_handshake_cancel);
+20
net/handshake/trace.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Trace points for transport security layer handshakes. 4 + * 5 + * Author: Chuck Lever <chuck.lever@oracle.com> 6 + * 7 + * Copyright (c) 2023, Oracle and/or its affiliates. 8 + */ 9 + 10 + #include <linux/types.h> 11 + 12 + #include <net/sock.h> 13 + #include <net/netlink.h> 14 + #include <net/genetlink.h> 15 + 16 + #include "handshake.h" 17 + 18 + #define CREATE_TRACE_POINTS 19 + 20 + #include <trace/events/handshake.h>