1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* Out of band message handling (e.g. challenge-response) 3 * 4 * Copyright (C) 2025 Red Hat, Inc. All Rights Reserved. 5 * Written by David Howells (dhowells@redhat.com) 6 */ 7 8 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 9 10 #include <linux/net.h> 11 #include <linux/gfp.h> 12 #include <linux/skbuff.h> 13 #include <linux/export.h> 14 #include <linux/sched/signal.h> 15 #include <net/sock.h> 16 #include <net/af_rxrpc.h> 17 #include "ar-internal.h" 18 19 enum rxrpc_oob_command { 20 RXRPC_OOB_CMD_UNSET, 21 RXRPC_OOB_CMD_RESPOND, 22 } __mode(byte); 23 24 struct rxrpc_oob_params { 25 u64 oob_id; /* ID number of message if reply */ 26 s32 abort_code; 27 enum rxrpc_oob_command command; 28 bool have_oob_id:1; 29 }; 30 31 /* 32 * Post an out-of-band message for attention by the socket or kernel service 33 * associated with a reference call. 34 */ 35 bool rxrpc_notify_socket_oob(struct rxrpc_call *call, struct sk_buff *skb) 36 { 37 struct rxrpc_skb_priv *sp = rxrpc_skb(skb); 38 struct rxrpc_sock *rx; 39 struct sock *sk; 40 bool queued = false; 41 42 rcu_read_lock(); 43 44 rx = rcu_dereference(call->socket); 45 if (rx) { 46 sk = &rx->sk; 47 spin_lock_irq(&rx->recvmsg_lock); 48 49 if (sk->sk_state < RXRPC_CLOSE) { 50 skb->skb_mstamp_ns = rx->oob_id_counter++; 51 rxrpc_get_skb(skb, rxrpc_skb_get_post_oob); 52 skb_queue_tail(&rx->recvmsg_oobq, skb); 53 queued = true; 54 55 trace_rxrpc_notify_socket(call->debug_id, sp->hdr.serial); 56 if (rx->app_ops) 57 rx->app_ops->notify_oob(sk, skb); 58 } 59 60 spin_unlock_irq(&rx->recvmsg_lock); 61 if (queued && !rx->app_ops && !sock_flag(sk, SOCK_DEAD)) 62 sk->sk_data_ready(sk); 63 } 64 65 rcu_read_unlock(); 66 return queued; 67 } 68 69 /* 70 * Locate the OOB message to respond to by its ID. 71 */ 72 static struct sk_buff *rxrpc_find_pending_oob(struct rxrpc_sock *rx, u64 oob_id) 73 { 74 struct rb_node *p; 75 struct sk_buff *skb; 76 77 p = rx->pending_oobq.rb_node; 78 while (p) { 79 skb = rb_entry(p, struct sk_buff, rbnode); 80 81 if (oob_id < skb->skb_mstamp_ns) 82 p = p->rb_left; 83 else if (oob_id > skb->skb_mstamp_ns) 84 p = p->rb_right; 85 else 86 return skb; 87 } 88 89 return NULL; 90 } 91 92 /* 93 * Add an OOB message into the pending-response set. We always assign the next 94 * value from a 64-bit counter to the oob_id, so just assume we're always going 95 * to be on the right-hand edge of the tree and that the counter won't wrap. 96 * The tree is also given a ref to the message. 97 */ 98 void rxrpc_add_pending_oob(struct rxrpc_sock *rx, struct sk_buff *skb) 99 { 100 struct rb_node **pp = &rx->pending_oobq.rb_node, *p = NULL; 101 102 while (*pp) { 103 p = *pp; 104 pp = &(*pp)->rb_right; 105 } 106 107 rb_link_node(&skb->rbnode, p, pp); 108 rb_insert_color(&skb->rbnode, &rx->pending_oobq); 109 } 110 111 /* 112 * Extract control messages from the sendmsg() control buffer. 113 */ 114 static int rxrpc_sendmsg_oob_cmsg(struct msghdr *msg, struct rxrpc_oob_params *p) 115 { 116 struct cmsghdr *cmsg; 117 int len; 118 119 if (msg->msg_controllen == 0) 120 return -EINVAL; 121 122 for_each_cmsghdr(cmsg, msg) { 123 if (!CMSG_OK(msg, cmsg)) 124 return -EINVAL; 125 126 len = cmsg->cmsg_len - sizeof(struct cmsghdr); 127 _debug("CMSG %d, %d, %d", 128 cmsg->cmsg_level, cmsg->cmsg_type, len); 129 130 if (cmsg->cmsg_level != SOL_RXRPC) 131 continue; 132 133 switch (cmsg->cmsg_type) { 134 case RXRPC_OOB_ID: 135 if (len != sizeof(p->oob_id) || p->have_oob_id) 136 return -EINVAL; 137 memcpy(&p->oob_id, CMSG_DATA(cmsg), sizeof(p->oob_id)); 138 p->have_oob_id = true; 139 break; 140 case RXRPC_RESPOND: 141 if (p->command != RXRPC_OOB_CMD_UNSET) 142 return -EINVAL; 143 p->command = RXRPC_OOB_CMD_RESPOND; 144 break; 145 case RXRPC_ABORT: 146 if (len != sizeof(p->abort_code) || p->abort_code) 147 return -EINVAL; 148 memcpy(&p->abort_code, CMSG_DATA(cmsg), sizeof(p->abort_code)); 149 if (p->abort_code == 0) 150 return -EINVAL; 151 break; 152 case RXRPC_RESP_RXGK_APPDATA: 153 if (p->command != RXRPC_OOB_CMD_RESPOND) 154 return -EINVAL; 155 break; 156 default: 157 return -EINVAL; 158 } 159 } 160 161 switch (p->command) { 162 case RXRPC_OOB_CMD_RESPOND: 163 if (!p->have_oob_id) 164 return -EBADSLT; 165 break; 166 default: 167 return -EINVAL; 168 } 169 170 return 0; 171 } 172 173 /* 174 * Allow userspace to respond to an OOB using sendmsg(). 175 */ 176 static int rxrpc_respond_to_oob(struct rxrpc_sock *rx, 177 struct rxrpc_oob_params *p, 178 struct msghdr *msg) 179 { 180 struct rxrpc_connection *conn; 181 struct rxrpc_skb_priv *sp; 182 struct sk_buff *skb; 183 int ret; 184 185 skb = rxrpc_find_pending_oob(rx, p->oob_id); 186 if (skb) 187 rb_erase(&skb->rbnode, &rx->pending_oobq); 188 release_sock(&rx->sk); 189 if (!skb) 190 return -EBADSLT; 191 192 sp = rxrpc_skb(skb); 193 194 switch (p->command) { 195 case RXRPC_OOB_CMD_RESPOND: 196 ret = -EPROTO; 197 if (skb->mark != RXRPC_OOB_CHALLENGE) 198 break; 199 conn = sp->chall.conn; 200 ret = -EOPNOTSUPP; 201 if (!conn->security->sendmsg_respond_to_challenge) 202 break; 203 if (p->abort_code) { 204 rxrpc_abort_conn(conn, NULL, p->abort_code, -ECONNABORTED, 205 rxrpc_abort_response_sendmsg); 206 ret = 0; 207 } else { 208 ret = conn->security->sendmsg_respond_to_challenge(skb, msg); 209 } 210 break; 211 default: 212 ret = -EINVAL; 213 break; 214 } 215 216 switch (skb->mark) { 217 case RXRPC_OOB_CHALLENGE: 218 rxrpc_put_connection(sp->chall.conn, rxrpc_conn_put_oob); 219 break; 220 } 221 rxrpc_free_skb(skb, rxrpc_skb_put_oob); 222 return ret; 223 } 224 225 /* 226 * Send an out-of-band message or respond to a received out-of-band message. 227 * - caller gives us the socket lock 228 * - the socket may be either a client socket or a server socket 229 */ 230 int rxrpc_sendmsg_oob(struct rxrpc_sock *rx, struct msghdr *msg, size_t len) 231 { 232 struct rxrpc_oob_params p = {}; 233 int ret; 234 235 _enter(""); 236 237 ret = rxrpc_sendmsg_oob_cmsg(msg, &p); 238 if (ret < 0) 239 goto error_release_sock; 240 241 if (p.have_oob_id) 242 return rxrpc_respond_to_oob(rx, &p, msg); 243 244 release_sock(&rx->sk); 245 246 switch (p.command) { 247 default: 248 ret = -EINVAL; 249 break; 250 } 251 252 _leave(" = %d", ret); 253 return ret; 254 255 error_release_sock: 256 release_sock(&rx->sk); 257 return ret; 258 } 259 260 /** 261 * rxrpc_kernel_query_oob - Query the parameters of an out-of-band message 262 * @oob: The message to query 263 * @_peer: Where to return the peer record 264 * @_peer_appdata: The application data attached to a peer record 265 * 266 * Extract useful parameters from an out-of-band message. The source peer 267 * parameters are returned through the argument list and the message type is 268 * returned. 269 * 270 * Return: 271 * * %RXRPC_OOB_CHALLENGE - Challenge wanting a response. 272 */ 273 enum rxrpc_oob_type rxrpc_kernel_query_oob(struct sk_buff *oob, 274 struct rxrpc_peer **_peer, 275 unsigned long *_peer_appdata) 276 { 277 struct rxrpc_skb_priv *sp = rxrpc_skb(oob); 278 enum rxrpc_oob_type type = oob->mark; 279 280 switch (type) { 281 case RXRPC_OOB_CHALLENGE: 282 *_peer = sp->chall.conn->peer; 283 *_peer_appdata = sp->chall.conn->peer->app_data; 284 break; 285 default: 286 WARN_ON_ONCE(1); 287 *_peer = NULL; 288 *_peer_appdata = 0; 289 break; 290 } 291 292 return type; 293 } 294 EXPORT_SYMBOL(rxrpc_kernel_query_oob); 295 296 /** 297 * rxrpc_kernel_dequeue_oob - Dequeue and return the front OOB message 298 * @sock: The socket to query 299 * @_type: Where to return the message type 300 * 301 * Dequeue the front OOB message, if there is one, and return it and 302 * its type. 303 * 304 * Return: The sk_buff representing the OOB message or %NULL if the queue was 305 * empty. 306 */ 307 struct sk_buff *rxrpc_kernel_dequeue_oob(struct socket *sock, 308 enum rxrpc_oob_type *_type) 309 { 310 struct rxrpc_sock *rx = rxrpc_sk(sock->sk); 311 struct sk_buff *oob; 312 313 oob = skb_dequeue(&rx->recvmsg_oobq); 314 if (oob) 315 *_type = oob->mark; 316 return oob; 317 } 318 EXPORT_SYMBOL(rxrpc_kernel_dequeue_oob); 319 320 /** 321 * rxrpc_kernel_free_oob - Free an out-of-band message 322 * @oob: The OOB message to free 323 * 324 * Free an OOB message along with any resources it holds. 325 */ 326 void rxrpc_kernel_free_oob(struct sk_buff *oob) 327 { 328 struct rxrpc_skb_priv *sp = rxrpc_skb(oob); 329 330 switch (oob->mark) { 331 case RXRPC_OOB_CHALLENGE: 332 rxrpc_put_connection(sp->chall.conn, rxrpc_conn_put_oob); 333 break; 334 } 335 336 rxrpc_free_skb(oob, rxrpc_skb_put_purge_oob); 337 } 338 EXPORT_SYMBOL(rxrpc_kernel_free_oob); 339 340 /** 341 * rxrpc_kernel_query_challenge - Query the parameters of a challenge 342 * @challenge: The challenge to query 343 * @_peer: Where to return the peer record 344 * @_peer_appdata: The application data attached to a peer record 345 * @_service_id: Where to return the connection service ID 346 * @_security_index: Where to return the connection security index 347 * 348 * Extract useful parameters from a CHALLENGE message. 349 */ 350 void rxrpc_kernel_query_challenge(struct sk_buff *challenge, 351 struct rxrpc_peer **_peer, 352 unsigned long *_peer_appdata, 353 u16 *_service_id, u8 *_security_index) 354 { 355 struct rxrpc_skb_priv *sp = rxrpc_skb(challenge); 356 357 *_peer = sp->chall.conn->peer; 358 *_peer_appdata = sp->chall.conn->peer->app_data; 359 *_service_id = sp->hdr.serviceId; 360 *_security_index = sp->hdr.securityIndex; 361 } 362 EXPORT_SYMBOL(rxrpc_kernel_query_challenge); 363 364 /** 365 * rxrpc_kernel_reject_challenge - Allow a kernel service to reject a challenge 366 * @challenge: The challenge to be rejected 367 * @abort_code: The abort code to stick into the ABORT packet 368 * @error: Local error value 369 * @why: Indication as to why. 370 * 371 * Allow a kernel service to reject a challenge by aborting the connection if 372 * it's still in an abortable state. The error is returned so this function 373 * can be used with a return statement. 374 * 375 * Return: The %error parameter. 376 */ 377 int rxrpc_kernel_reject_challenge(struct sk_buff *challenge, u32 abort_code, 378 int error, enum rxrpc_abort_reason why) 379 { 380 struct rxrpc_skb_priv *sp = rxrpc_skb(challenge); 381 382 _enter("{%x},%d,%d,%u", sp->hdr.serial, abort_code, error, why); 383 384 rxrpc_abort_conn(sp->chall.conn, NULL, abort_code, error, why); 385 return error; 386 } 387 EXPORT_SYMBOL(rxrpc_kernel_reject_challenge); 388