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/file.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_flex(*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 * Returns %false when the net namespace is draining; the drain 167 * loop has taken ownership of the pending list. 168 */ 169 static bool remove_pending(struct handshake_net *hn, struct handshake_req *req) 170 { 171 bool ret = false; 172 173 spin_lock_bh(&hn->hn_lock); 174 if (!test_bit(HANDSHAKE_F_NET_DRAINING, &hn->hn_flags) && 175 !list_empty(&req->hr_list)) { 176 __remove_pending_locked(hn, req); 177 ret = true; 178 } 179 spin_unlock_bh(&hn->hn_lock); 180 181 return ret; 182 } 183 184 /** 185 * handshake_req_next - Return the next queued handshake request 186 * @hn: per-net handshake state 187 * @class: handler class to match 188 * 189 * On a non-NULL return, the caller owns an extra reference 190 * on @req->hr_file. FD_PREPARE() consumes it on success; on 191 * the FD_PREPARE() failure path the caller must fput() it. 192 * 193 * Return: pointer to a removed handshake_req, or NULL. 194 */ 195 struct handshake_req *handshake_req_next(struct handshake_net *hn, int class) 196 { 197 struct handshake_req *req, *pos; 198 199 req = NULL; 200 spin_lock_bh(&hn->hn_lock); 201 list_for_each_entry(pos, &hn->hn_requests, hr_list) { 202 if (pos->hr_proto->hp_handler_class != class) 203 continue; 204 __remove_pending_locked(hn, pos); 205 /* Hand off a file reference to the accept side under 206 * hn_lock. A concurrent handshake_req_cancel() can drop 207 * hr_file before accept reaches FD_PREPARE(); this extra 208 * reference keeps the file alive until FD_PREPARE() takes 209 * ownership. 210 */ 211 get_file(pos->hr_file); 212 req = pos; 213 break; 214 } 215 spin_unlock_bh(&hn->hn_lock); 216 217 return req; 218 } 219 EXPORT_SYMBOL_IF_KUNIT(handshake_req_next); 220 221 /** 222 * handshake_req_submit - Submit a handshake request 223 * @sock: open socket on which to perform the handshake 224 * @req: handshake arguments 225 * @flags: memory allocation flags 226 * 227 * Return values: 228 * %0: Request queued 229 * %-EINVAL: Invalid argument 230 * %-EBUSY: A handshake is already under way for this socket 231 * %-ESRCH: No handshake agent is available 232 * %-EAGAIN: Too many pending handshake requests 233 * %-ENOMEM: Failed to allocate memory 234 * %-EMSGSIZE: Failed to construct notification message 235 * %-EOPNOTSUPP: Handshake module not initialized 236 * 237 * A zero return value from handshake_req_submit() means that 238 * exactly one subsequent completion callback is guaranteed. 239 * 240 * A negative return value from handshake_req_submit() guarantees that 241 * no completion callback will occur and that @req is no longer owned by 242 * the caller. If cancellation wins the completion race after the request 243 * has been published, final destruction is deferred until socket teardown. 244 * 245 * The caller must hold a reference on @sock->file for the duration 246 * of this call. Once the request is published to the accept side, a 247 * concurrent completion or cancellation may release the request's pin on 248 * @sock->file; the caller's reference is what keeps @sock->sk valid until 249 * handshake_req_submit() returns. 250 */ 251 int handshake_req_submit(struct socket *sock, struct handshake_req *req, 252 gfp_t flags) 253 { 254 struct handshake_net *hn; 255 struct net *net; 256 int ret; 257 258 if (!sock || !req || !sock->file) { 259 kfree(req); 260 return -EINVAL; 261 } 262 263 req->hr_sk = sock->sk; 264 if (!req->hr_sk) { 265 kfree(req); 266 return -EINVAL; 267 } 268 269 /* 270 * Pin sock->file for the lifetime of the request so the 271 * accept side does not race a consumer that releases the 272 * socket while a handshake is pending. 273 */ 274 req->hr_file = get_file(sock->file); 275 276 req->hr_odestruct = req->hr_sk->sk_destruct; 277 req->hr_sk->sk_destruct = handshake_sk_destruct; 278 279 ret = -EOPNOTSUPP; 280 net = sock_net(req->hr_sk); 281 hn = handshake_pernet(net); 282 if (!hn) 283 goto out_err; 284 285 ret = -EAGAIN; 286 if (READ_ONCE(hn->hn_pending) >= hn->hn_pending_max) 287 goto out_err; 288 289 spin_lock_bh(&hn->hn_lock); 290 ret = -EOPNOTSUPP; 291 if (test_bit(HANDSHAKE_F_NET_DRAINING, &hn->hn_flags)) 292 goto out_unlock; 293 ret = -EBUSY; 294 if (!handshake_req_hash_add(req)) 295 goto out_unlock; 296 if (!__add_pending_locked(hn, req)) 297 goto out_unlock; 298 spin_unlock_bh(&hn->hn_lock); 299 300 ret = handshake_genl_notify(net, req->hr_proto, flags); 301 if (ret) { 302 trace_handshake_notify_err(net, req, req->hr_sk, ret); 303 if (remove_pending(hn, req)) 304 goto out_err; 305 } 306 307 trace_handshake_submit(net, req, req->hr_sk); 308 return 0; 309 310 out_unlock: 311 spin_unlock_bh(&hn->hn_lock); 312 out_err: 313 trace_handshake_submit_err(net, req, req->hr_sk, ret); 314 if (!test_and_set_bit(HANDSHAKE_F_REQ_COMPLETED, &req->hr_flags)) { 315 /* Restore original destructor so socket teardown still runs. */ 316 req->hr_sk->sk_destruct = req->hr_odestruct; 317 fput(req->hr_file); 318 handshake_req_destroy(req); 319 } 320 return ret; 321 } 322 EXPORT_SYMBOL(handshake_req_submit); 323 324 void handshake_complete(struct handshake_req *req, int status, 325 struct genl_info *info) 326 { 327 struct sock *sk = req->hr_sk; 328 struct net *net = sock_net(sk); 329 330 if (!test_and_set_bit(HANDSHAKE_F_REQ_COMPLETED, &req->hr_flags)) { 331 struct file *file = req->hr_file; 332 333 trace_handshake_complete(net, req, sk, status); 334 req->hr_proto->hp_done(req, status, info); 335 336 fput(file); 337 } 338 } 339 EXPORT_SYMBOL_IF_KUNIT(handshake_complete); 340 341 /** 342 * handshake_req_cancel - Cancel an in-progress handshake 343 * @sk: socket on which there is an ongoing handshake 344 * 345 * Request cancellation races with request completion. To determine 346 * who won, callers examine the return value from this function. 347 * 348 * Return values: 349 * %true - Uncompleted handshake request was canceled 350 * %false - Handshake request already completed or not found 351 */ 352 bool handshake_req_cancel(struct sock *sk) 353 { 354 struct handshake_req *req; 355 struct handshake_net *hn; 356 struct net *net; 357 358 net = sock_net(sk); 359 req = handshake_req_hash_lookup(sk); 360 if (!req) { 361 trace_handshake_cancel_none(net, req, sk); 362 return false; 363 } 364 365 hn = handshake_pernet(net); 366 if (hn && remove_pending(hn, req)) { 367 /* Request hadn't been accepted - mark cancelled */ 368 if (test_and_set_bit(HANDSHAKE_F_REQ_COMPLETED, &req->hr_flags)) { 369 trace_handshake_cancel_busy(net, req, sk); 370 return false; 371 } 372 goto out_true; 373 } 374 if (test_and_set_bit(HANDSHAKE_F_REQ_COMPLETED, &req->hr_flags)) { 375 /* Request already completed */ 376 trace_handshake_cancel_busy(net, req, sk); 377 return false; 378 } 379 380 out_true: 381 trace_handshake_cancel(net, req, sk); 382 383 fput(req->hr_file); 384 return true; 385 } 386 EXPORT_SYMBOL(handshake_req_cancel); 387