1/* SPDX-License-Identifier: BSD-2-Clause */
2/*
3 * Privilege Separation BPF Initiator
4 * Copyright (c) 2006-2023 Roy Marples <roy@marples.name>
5 * All rights reserved
6
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29#include <sys/socket.h>
30#include <sys/types.h>
31
32/* Need these headers just for if_ether on some OS. */
33#ifndef __NetBSD__
34#include <net/if.h>
35#include <net/if_arp.h>
36#include <netinet/in.h>
37#endif
38#include <netinet/if_ether.h>
39
40#include <assert.h>
41#include <pwd.h>
42#include <errno.h>
43#include <stdlib.h>
44#include <string.h>
45#include <unistd.h>
46
47#include "arp.h"
48#include "bpf.h"
49#include "dhcp.h"
50#include "dhcp6.h"
51#include "eloop.h"
52#include "ipv6nd.h"
53#include "logerr.h"
54#include "privsep.h"
55
56/* We expect to have open 3 SEQPACKET and one RAW fd */
57
58static void
59ps_bpf_recvbpf(void *arg, unsigned short events)
60{
61	struct ps_process *psp = arg;
62	struct bpf *bpf = psp->psp_bpf;
63	uint8_t buf[FRAMELEN_MAX];
64	ssize_t len;
65	struct ps_msghdr psm = {
66		.ps_id = psp->psp_id,
67		.ps_cmd = psp->psp_id.psi_cmd,
68	};
69
70	if (events != ELE_READ)
71		logerrx("%s: unexpected event 0x%04x", __func__, events);
72
73	bpf->bpf_flags &= ~BPF_EOF;
74	/* A BPF read can read more than one filtered packet at time.
75	 * This mechanism allows us to read each packet from the buffer. */
76	while (!(bpf->bpf_flags & BPF_EOF)) {
77		len = bpf_read(bpf, buf, sizeof(buf));
78		if (len == -1) {
79			int error = errno;
80
81			if (errno != ENETDOWN)
82				logerr("%s: %s", psp->psp_ifname, __func__);
83			if (error != ENXIO)
84				break;
85			/* If the interface has departed, close the BPF
86			 * socket. This stops log spam if RTM_IFANNOUNCE is
87			 * delayed in announcing the departing interface. */
88			eloop_event_delete(psp->psp_ctx->eloop, bpf->bpf_fd);
89			bpf_close(bpf);
90			psp->psp_bpf = NULL;
91			break;
92		}
93		if (len == 0)
94			break;
95		psm.ps_flags = bpf->bpf_flags;
96		len = ps_sendpsmdata(psp->psp_ctx, psp->psp_ctx->ps_data_fd,
97		    &psm, buf, (size_t)len);
98		if (len == -1)
99			logerr(__func__);
100		if (len == -1 || len == 0)
101			break;
102	}
103}
104
105static ssize_t
106ps_bpf_recvmsgcb(void *arg, struct ps_msghdr *psm, struct msghdr *msg)
107{
108	struct ps_process *psp = arg;
109	struct iovec *iov = msg->msg_iov;
110
111#ifdef PRIVSEP_DEBUG
112	logerrx("%s: IN cmd %x, psp %p", __func__, psm->ps_cmd, psp);
113#endif
114
115	switch(psm->ps_cmd) {
116#ifdef ARP
117	case PS_BPF_ARP:	/* FALLTHROUGH */
118#endif
119	case PS_BPF_BOOTP:
120		break;
121	default:
122		/* IPC failure, we should not be processing any commands
123		 * at this point!/ */
124		errno = EINVAL;
125		return -1;
126	}
127
128	/* We might have had an earlier ENXIO error. */
129	if (psp->psp_bpf == NULL) {
130		errno = ENXIO;
131		return -1;
132	}
133
134	return bpf_send(psp->psp_bpf, psp->psp_proto,
135	    iov->iov_base, iov->iov_len);
136}
137
138static void
139ps_bpf_recvmsg(void *arg, unsigned short events)
140{
141	struct ps_process *psp = arg;
142
143	if (ps_recvpsmsg(psp->psp_ctx, psp->psp_fd, events,
144	    ps_bpf_recvmsgcb, arg) == -1)
145		logerr(__func__);
146}
147
148static int
149ps_bpf_start_bpf(struct ps_process *psp)
150{
151	struct dhcpcd_ctx *ctx = psp->psp_ctx;
152	char *addr;
153	struct in_addr *ia = &psp->psp_id.psi_addr.psa_in_addr;
154
155	if (ia->s_addr == INADDR_ANY) {
156		ia = NULL;
157		addr = NULL;
158	} else
159		addr = inet_ntoa(*ia);
160	setproctitle("[BPF %s] %s%s%s", psp->psp_protostr, psp->psp_ifname,
161	    addr != NULL ? " " : "", addr != NULL ? addr : "");
162	ps_freeprocesses(ctx, psp);
163
164	psp->psp_bpf = bpf_open(&psp->psp_ifp, psp->psp_filter, ia);
165#ifdef DEBUG_FD
166	logdebugx("pid %d bpf_fd=%d", getpid(), psp->psp_bpf->bpf_fd);
167#endif
168	if (psp->psp_bpf == NULL)
169		logerr("%s: bpf_open",__func__);
170#ifdef PRIVSEP_RIGHTS
171	else if (ps_rights_limit_fd(psp->psp_bpf->bpf_fd) == -1)
172		logerr("%s: ps_rights_limit_fd", __func__);
173#endif
174	else if (eloop_event_add(ctx->eloop, psp->psp_bpf->bpf_fd, ELE_READ,
175	    ps_bpf_recvbpf, psp) == -1)
176		logerr("%s: eloop_event_add", __func__);
177	else {
178		psp->psp_work_fd = psp->psp_bpf->bpf_fd;
179		return 0;
180	}
181
182	eloop_exit(ctx->eloop, EXIT_FAILURE);
183	return -1;
184}
185
186ssize_t
187ps_bpf_cmd(struct dhcpcd_ctx *ctx, struct ps_msghdr *psm, struct msghdr *msg)
188{
189	uint16_t cmd;
190	struct ps_process *psp;
191	pid_t start;
192	struct iovec *iov = msg->msg_iov;
193	struct interface *ifp;
194	struct in_addr *ia = &psm->ps_id.psi_addr.psa_in_addr;
195	const char *addr;
196
197	cmd = (uint16_t)(psm->ps_cmd & ~(PS_START | PS_STOP));
198	psp = ps_findprocess(ctx, &psm->ps_id);
199
200#ifdef PRIVSEP_DEBUG
201	logerrx("%s: IN cmd %x, psp %p", __func__, psm->ps_cmd, psp);
202#endif
203
204	switch (cmd) {
205#ifdef ARP
206	case PS_BPF_ARP:	/* FALLTHROUGH */
207#endif
208	case PS_BPF_BOOTP:
209		break;
210	default:
211		logerrx("%s: unknown command %x", __func__, psm->ps_cmd);
212		errno = ENOTSUP;
213		return -1;
214	}
215
216	if (!(psm->ps_cmd & PS_START)) {
217		errno = EINVAL;
218		return -1;
219	}
220
221	if (psp != NULL)
222		return 1;
223
224	psp = ps_newprocess(ctx, &psm->ps_id);
225	if (psp == NULL)
226		return -1;
227
228	ifp = &psp->psp_ifp;
229	assert(msg->msg_iovlen == 1);
230	assert(iov->iov_len == sizeof(*ifp));
231	memcpy(ifp, iov->iov_base, sizeof(*ifp));
232	ifp->ctx = psp->psp_ctx;
233	ifp->options = NULL;
234	memset(ifp->if_data, 0, sizeof(ifp->if_data));
235
236	memcpy(psp->psp_ifname, ifp->name, sizeof(psp->psp_ifname));
237
238	switch (cmd) {
239#ifdef ARP
240	case PS_BPF_ARP:
241		psp->psp_proto = ETHERTYPE_ARP;
242		psp->psp_protostr = "ARP";
243		psp->psp_filter = bpf_arp;
244		break;
245#endif
246	case PS_BPF_BOOTP:
247		psp->psp_proto = ETHERTYPE_IP;
248		psp->psp_protostr = "BOOTP";
249		psp->psp_filter = bpf_bootp;
250		break;
251	}
252
253	if (ia->s_addr == INADDR_ANY)
254		addr = NULL;
255	else
256		addr = inet_ntoa(*ia);
257	snprintf(psp->psp_name, sizeof(psp->psp_name), "BPF %s%s%s",
258	    psp->psp_protostr,
259	    addr != NULL ? " " : "", addr != NULL ? addr : "");
260
261	start = ps_startprocess(psp, ps_bpf_recvmsg, NULL,
262	    ps_bpf_start_bpf, NULL, PSF_DROPPRIVS);
263	switch (start) {
264	case -1:
265		ps_freeprocess(psp);
266		return -1;
267	case 0:
268		ps_entersandbox("stdio", NULL);
269		break;
270	default:
271		logdebugx("%s: spawned %s on PID %d",
272		    psp->psp_ifname, psp->psp_name, psp->psp_pid);
273		break;
274	}
275	return start;
276}
277
278ssize_t
279ps_bpf_dispatch(struct dhcpcd_ctx *ctx,
280    struct ps_msghdr *psm, struct msghdr *msg)
281{
282	struct iovec *iov = msg->msg_iov;
283	struct interface *ifp;
284	uint8_t *bpf;
285	size_t bpf_len;
286
287	switch (psm->ps_cmd) {
288#ifdef ARP
289	case PS_BPF_ARP:
290#endif
291	case PS_BPF_BOOTP:
292		break;
293	default:
294		errno = ENOTSUP;
295		return -1;
296	}
297
298	ifp = if_findindex(ctx->ifaces, psm->ps_id.psi_ifindex);
299	/* interface may have departed .... */
300	if (ifp == NULL)
301		return -1;
302
303	bpf = iov->iov_base;
304	bpf_len = iov->iov_len;
305
306	switch (psm->ps_cmd) {
307#ifdef ARP
308	case PS_BPF_ARP:
309		arp_packet(ifp, bpf, bpf_len, (unsigned int)psm->ps_flags);
310		break;
311#endif
312	case PS_BPF_BOOTP:
313		dhcp_packet(ifp, bpf, bpf_len, (unsigned int)psm->ps_flags);
314		break;
315	}
316
317	return 1;
318}
319
320static ssize_t
321ps_bpf_send(const struct interface *ifp, const struct in_addr *ia,
322    uint16_t cmd, const void *data, size_t len)
323{
324	struct dhcpcd_ctx *ctx = ifp->ctx;
325	struct ps_msghdr psm = {
326		.ps_cmd = cmd,
327		.ps_id = {
328			.psi_ifindex = ifp->index,
329			.psi_cmd = (uint8_t)(cmd & ~(PS_START | PS_STOP)),
330		},
331	};
332
333	if (ia != NULL)
334		psm.ps_id.psi_addr.psa_in_addr = *ia;
335
336	return ps_sendpsmdata(ctx, PS_ROOT_FD(ctx), &psm, data, len);
337}
338
339#ifdef ARP
340ssize_t
341ps_bpf_openarp(const struct interface *ifp, const struct in_addr *ia)
342{
343
344	assert(ia != NULL);
345	return ps_bpf_send(ifp, ia, PS_BPF_ARP | PS_START,
346	    ifp, sizeof(*ifp));
347}
348
349ssize_t
350ps_bpf_closearp(const struct interface *ifp, const struct in_addr *ia)
351{
352
353	return ps_bpf_send(ifp, ia, PS_BPF_ARP | PS_STOP, NULL, 0);
354}
355
356ssize_t
357ps_bpf_sendarp(const struct interface *ifp, const struct in_addr *ia,
358    const void *data, size_t len)
359{
360
361	assert(ia != NULL);
362	return ps_bpf_send(ifp, ia, PS_BPF_ARP, data, len);
363}
364#endif
365
366ssize_t
367ps_bpf_openbootp(const struct interface *ifp)
368{
369
370	return ps_bpf_send(ifp, NULL, PS_BPF_BOOTP | PS_START,
371	    ifp, sizeof(*ifp));
372}
373
374ssize_t
375ps_bpf_closebootp(const struct interface *ifp)
376{
377
378	return ps_bpf_send(ifp, NULL, PS_BPF_BOOTP | PS_STOP, NULL, 0);
379}
380
381ssize_t
382ps_bpf_sendbootp(const struct interface *ifp, const void *data, size_t len)
383{
384
385	return ps_bpf_send(ifp, NULL, PS_BPF_BOOTP, data, len);
386}
387