1/*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 2019 Isilon Systems, LLC.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28/*
29 * netgdb.c
30 * FreeBSD subsystem supporting debugging the FreeBSD kernel over the network.
31 *
32 * There are three pieces necessary to use NetGDB.
33 *
34 * First, a dedicated proxy server must be running to accept connections from
35 * both NetGDB and gdb(1), and pass bidirectional traffic between the two
36 * protocols.
37 *
38 * Second, The NetGDB client is activated much like ordinary 'gdb' and
39 * similarly to 'netdump' in ddb(4).  Like other debugnet(4) clients
40 * (netdump(4)), the network interface on the route to the proxy server must be
41 * online and support debugnet(4).
42 *
43 * Finally, the remote (k)gdb(1) uses 'target remote <proxy>:<port>' to connect
44 * to the proxy server.
45 *
46 * NetGDBv1 speaks the literal GDB remote serial protocol, and uses a 1:1
47 * relationship between GDB packets and plain debugnet packets.  There is no
48 * encryption utilized to keep debugging sessions private, so this is only
49 * appropriate for local segments or trusted networks.
50 */
51
52#include <sys/cdefs.h>
53__FBSDID("$FreeBSD$");
54
55#include "opt_ddb.h"
56#ifndef DDB
57#error "NetGDB cannot be used without DDB at this time"
58#endif
59
60#include <sys/param.h>
61#include <sys/kdb.h>
62#include <sys/sbuf.h>
63#include <sys/socket.h>
64#include <sys/sysctl.h>
65#include <sys/ttydefaults.h>
66
67#include <machine/gdb_machdep.h>
68
69#ifdef DDB
70#include <ddb/ddb.h>
71#include <ddb/db_command.h>
72#include <ddb/db_lex.h>
73#endif
74
75#include <net/debugnet.h>
76#include <net/if.h>
77#include <net/if_var.h>
78#include <net/route.h>
79
80#include <gdb/gdb.h>
81#include <gdb/gdb_int.h>
82#include <gdb/netgdb.h>
83
84FEATURE(netgdb, "NetGDB support");
85SYSCTL_NODE(_debug_gdb, OID_AUTO, netgdb, CTLFLAG_RD | CTLFLAG_MPSAFE, NULL,
86    "NetGDB parameters");
87
88static unsigned netgdb_debug;
89SYSCTL_UINT(_debug_gdb_netgdb, OID_AUTO, debug, CTLFLAG_RWTUN,
90    &netgdb_debug, 0,
91    "Debug message verbosity (0: off; 1: on)");
92
93#define	NETGDB_DEBUG(f, ...) do {						\
94	if (netgdb_debug > 0)							\
95		printf(("%s [%s:%d]: " f), __func__, __FILE__, __LINE__, ##	\
96		    __VA_ARGS__);						\
97} while (false)
98
99static void netgdb_fini(void);
100
101/* Runtime state. */
102static char netgdb_rxbuf[GDB_BUFSZ + 16];	/* Some overhead for framing. */
103static struct sbuf netgdb_rxsb;
104static ssize_t netgdb_rx_off;
105
106static struct debugnet_pcb *netgdb_conn;
107static struct gdb_dbgport *netgdb_prev_dbgport;
108static int *netgdb_prev_kdb_inactive;
109
110/* TODO(CEM) disable ack mode */
111
112/*
113 * Receive non-TX ACK packets on the client port.
114 *
115 * The mbuf chain will have all non-debugnet framing headers removed
116 * (ethernet, inet, udp).  It will start with a debugnet_msg_hdr, of
117 * which the header is guaranteed to be contiguous.  If m_pullup is
118 * used, the supplied in-out mbuf pointer should be updated
119 * appropriately.
120 *
121 * If the handler frees the mbuf chain, it should set the mbuf pointer
122 * to NULL.  Otherwise, the debugnet input framework will free the
123 * chain.
124 */
125static void
126netgdb_rx(struct debugnet_pcb *pcb, struct mbuf **mb)
127{
128	const struct debugnet_msg_hdr *dnh;
129	struct mbuf *m;
130	uint32_t rlen, count;
131	int error;
132
133	m = *mb;
134	dnh = mtod(m, const void *);
135
136	if (ntohl(dnh->mh_type) == DEBUGNET_FINISHED) {
137		sbuf_putc(&netgdb_rxsb, CTRL('C'));
138		return;
139	}
140
141	if (ntohl(dnh->mh_type) != DEBUGNET_DATA) {
142		printf("%s: Got unexpected debugnet message %u\n",
143		    __func__, ntohl(dnh->mh_type));
144		return;
145	}
146
147	rlen = ntohl(dnh->mh_len);
148#define	_SBUF_FREESPACE(s)	((s)->s_size - ((s)->s_len + 1))
149	if (_SBUF_FREESPACE(&netgdb_rxsb) < rlen) {
150		NETGDB_DEBUG("Backpressure: Not ACKing RX of packet that "
151		    "would overflow our buffer (%zd/%zd used).\n",
152		    netgdb_rxsb.s_len, netgdb_rxsb.s_size);
153		return;
154	}
155#undef _SBUF_FREESPACE
156
157	error = debugnet_ack_output(pcb, dnh->mh_seqno);
158	if (error != 0) {
159		printf("%s: Couldn't ACK rx packet %u; %d\n", __func__,
160		    ntohl(dnh->mh_seqno), error);
161		/*
162		 * Sender will re-xmit, and assuming the condition is
163		 * transient, we'll process the packet's contentss later.
164		 */
165		return;
166	}
167
168	m_adj(m, sizeof(*dnh));
169	dnh = NULL;
170
171	/*
172	 * Inlined m_apply -- why isn't there a macro or inline function
173	 * version?
174	 */
175	while (m != NULL && m->m_len == 0)
176		m = m->m_next;
177	while (rlen > 0) {
178		MPASS(m != NULL && m->m_len >= 0);
179		count = min((uint32_t)m->m_len, rlen);
180		(void)sbuf_bcat(&netgdb_rxsb, mtod(m, const void *), count);
181		rlen -= count;
182		m = m->m_next;
183	}
184}
185
186/*
187 * The following routines implement a pseudo GDB debugport (an emulated serial
188 * driver that the MI gdb(4) code does I/O with).
189 */
190
191static int
192netgdb_dbg_getc(void)
193{
194	int c;
195
196	while (true) {
197		/* Pull bytes off any currently cached packet first. */
198		if (netgdb_rx_off < sbuf_len(&netgdb_rxsb)) {
199			c = netgdb_rxsb.s_buf[netgdb_rx_off];
200			netgdb_rx_off++;
201			break;
202		}
203
204		/* Reached EOF?  Reuse buffer. */
205		sbuf_clear(&netgdb_rxsb);
206		netgdb_rx_off = 0;
207
208		/* Check for CTRL-C on console/serial, if any. */
209		if (netgdb_prev_dbgport != NULL) {
210			c = netgdb_prev_dbgport->gdb_getc();
211			if (c == CTRL('C'))
212				break;
213		}
214
215		debugnet_network_poll(netgdb_conn);
216	}
217
218	if (c == CTRL('C')) {
219		netgdb_fini();
220		/* Caller gdb_getc() will print that we got ^C. */
221	}
222	return (c);
223}
224
225static void
226netgdb_dbg_sendpacket(const void *buf, size_t len)
227{
228	struct debugnet_proto_aux aux;
229	int error;
230
231	MPASS(len <= UINT32_MAX);
232
233	/*
234	 * GDB packet boundaries matter.  debugnet_send() fragments a single
235	 * request into many sequential debugnet messages.  Mark full packet
236	 * length and offset for potential reassembly by the proxy.
237	 */
238	aux = (struct debugnet_proto_aux) {
239		.dp_aux2 = len,
240	};
241
242	error = debugnet_send(netgdb_conn, DEBUGNET_DATA, buf, len, &aux);
243	if (error != 0) {
244		printf("%s: Network error: %d; trying to switch back to ddb.\n",
245		    __func__, error);
246		netgdb_fini();
247
248		if (kdb_dbbe_select("ddb") != 0)
249			printf("The ddb backend could not be selected.\n");
250		else {
251			printf("using longjmp, hope it works!\n");
252			kdb_reenter();
253		}
254	}
255
256}
257
258/* Just used for + / - GDB-level ACKs. */
259static void
260netgdb_dbg_putc(int i)
261{
262	char c;
263
264	c = i;
265	netgdb_dbg_sendpacket(&c, 1);
266
267}
268
269static struct gdb_dbgport netgdb_gdb_dbgport = {
270	.gdb_name = "netgdb",
271	.gdb_getc = netgdb_dbg_getc,
272	.gdb_putc = netgdb_dbg_putc,
273	.gdb_term = netgdb_fini,
274	.gdb_sendpacket = netgdb_dbg_sendpacket,
275	.gdb_dbfeatures = GDB_DBGP_FEAT_WANTTERM | GDB_DBGP_FEAT_RELIABLE,
276};
277
278static void
279netgdb_init(void)
280{
281	struct kdb_dbbe *be, **iter;
282
283	/*
284	 * Force enable GDB.  (If no other debugports were registered at boot,
285	 * KDB thinks it doesn't exist.)
286	 */
287	SET_FOREACH(iter, kdb_dbbe_set) {
288		be = *iter;
289		if (strcmp(be->dbbe_name, "gdb") != 0)
290			continue;
291		if (be->dbbe_active == -1) {
292			netgdb_prev_kdb_inactive = &be->dbbe_active;
293			be->dbbe_active = 0;
294		}
295		break;
296	}
297
298	/* Force netgdb debugport. */
299	netgdb_prev_dbgport = gdb_cur;
300	gdb_cur = &netgdb_gdb_dbgport;
301
302	sbuf_new(&netgdb_rxsb, netgdb_rxbuf, sizeof(netgdb_rxbuf),
303	    SBUF_FIXEDLEN);
304	netgdb_rx_off = 0;
305}
306
307static void
308netgdb_fini(void)
309{
310
311	/* TODO: tear down conn gracefully? */
312	if (netgdb_conn != NULL) {
313		debugnet_free(netgdb_conn);
314		netgdb_conn = NULL;
315	}
316
317	sbuf_delete(&netgdb_rxsb);
318
319	gdb_cur = netgdb_prev_dbgport;
320
321	if (netgdb_prev_kdb_inactive != NULL) {
322		*netgdb_prev_kdb_inactive = -1;
323		netgdb_prev_kdb_inactive = NULL;
324	}
325}
326
327#ifdef DDB
328/*
329 * Usage: netgdb -s <server> [-g <gateway -c <localip> -i <interface>]
330 *
331 * Order is not significant.
332 *
333 * Currently, this command does not support configuring encryption or
334 * compression.
335 */
336DB_FUNC(netgdb, db_netgdb_cmd, db_cmd_table, CS_OWN, NULL)
337{
338	struct debugnet_ddb_config params;
339	struct debugnet_conn_params dcp;
340	struct debugnet_pcb *pcb;
341	int error;
342
343	if (!KERNEL_PANICKED()) {
344		/* TODO: This limitation should be removed in future work. */
345		printf("%s: netgdb is currently limited to use only after a "
346		    "panic.  Sorry.\n", __func__);
347		return;
348	}
349
350	error = debugnet_parse_ddb_cmd("netgdb", &params);
351	if (error != 0) {
352		db_printf("Error configuring netgdb: %d\n", error);
353		return;
354	}
355
356	/*
357	 * Must initialize netgdb_rxsb before debugnet_connect(), because we
358	 * might be getting rx handler callbacks from the send->poll path
359	 * during debugnet_connect().
360	 */
361	netgdb_init();
362
363	if (!params.dd_has_client)
364		params.dd_client = INADDR_ANY;
365	if (!params.dd_has_gateway)
366		params.dd_gateway = INADDR_ANY;
367
368	dcp = (struct debugnet_conn_params) {
369		.dc_ifp = params.dd_ifp,
370		.dc_client = params.dd_client,
371		.dc_server = params.dd_server,
372		.dc_gateway = params.dd_gateway,
373		.dc_herald_port = NETGDB_HERALDPORT,
374		.dc_client_port = NETGDB_CLIENTPORT,
375		.dc_herald_aux2 = NETGDB_PROTO_V1,
376		.dc_rx_handler = netgdb_rx,
377	};
378
379	error = debugnet_connect(&dcp, &pcb);
380	if (error != 0) {
381		printf("failed to contact netgdb server: %d\n", error);
382		netgdb_fini();
383		return;
384	}
385
386	netgdb_conn = pcb;
387
388	if (kdb_dbbe_select("gdb") != 0) {
389		db_printf("The remote GDB backend could not be selected.\n");
390		netgdb_fini();
391		return;
392	}
393
394	/*
395	 * Mark that we are done in ddb(4).  Return -> kdb_trap() should
396	 * re-enter with the new backend.
397	 */
398	db_cmd_loop_done = 1;
399	gdb_return_to_ddb = true;
400	db_printf("(detaching GDB will return control to DDB)\n");
401#if 0
402	/* Aspirational, but does not work reliably. */
403	db_printf("(ctrl-c will return control to ddb)\n");
404#endif
405}
406#endif /* DDB */
407