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