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 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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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