xref: /dragonfly/contrib/dhcpcd/src/privsep-bpf.c (revision 556932ec)
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 static void
57 ps_bpf_recvbpf(void *arg, unsigned short events)
58 {
59 	struct ps_process *psp = arg;
60 	struct bpf *bpf = psp->psp_bpf;
61 	uint8_t buf[FRAMELEN_MAX];
62 	ssize_t len;
63 	struct ps_msghdr psm = {
64 		.ps_id = psp->psp_id,
65 		.ps_cmd = psp->psp_id.psi_cmd,
66 	};
67 
68 	if (events != ELE_READ)
69 		logerrx("%s: unexpected event 0x%04x", __func__, events);
70 
71 	bpf->bpf_flags &= ~BPF_EOF;
72 	/* A BPF read can read more than one filtered packet at time.
73 	 * This mechanism allows us to read each packet from the buffer. */
74 	while (!(bpf->bpf_flags & BPF_EOF)) {
75 		len = bpf_read(bpf, buf, sizeof(buf));
76 		if (len == -1) {
77 			int error = errno;
78 
79 			if (errno != ENETDOWN)
80 				logerr("%s: %s", psp->psp_ifname, __func__);
81 			if (error != ENXIO)
82 				break;
83 			/* If the interface has departed, close the BPF
84 			 * socket. This stops log spam if RTM_IFANNOUNCE is
85 			 * delayed in announcing the departing interface. */
86 			eloop_event_delete(psp->psp_ctx->eloop, bpf->bpf_fd);
87 			bpf_close(bpf);
88 			psp->psp_bpf = NULL;
89 			break;
90 		}
91 		if (len == 0)
92 			break;
93 		psm.ps_flags = bpf->bpf_flags;
94 		len = ps_sendpsmdata(psp->psp_ctx, psp->psp_ctx->ps_data_fd,
95 		    &psm, buf, (size_t)len);
96 		if (len == -1)
97 			logerr(__func__);
98 		if (len == -1 || len == 0)
99 			break;
100 	}
101 }
102 
103 static ssize_t
104 ps_bpf_recvmsgcb(void *arg, struct ps_msghdr *psm, struct msghdr *msg)
105 {
106 	struct ps_process *psp = arg;
107 	struct iovec *iov = msg->msg_iov;
108 
109 #ifdef PRIVSEP_DEBUG
110 	logerrx("%s: IN cmd %x, psp %p", __func__, psm->ps_cmd, psp);
111 #endif
112 
113 	switch(psm->ps_cmd) {
114 #ifdef ARP
115 	case PS_BPF_ARP:	/* FALLTHROUGH */
116 #endif
117 	case PS_BPF_BOOTP:
118 		break;
119 	default:
120 		/* IPC failure, we should not be processing any commands
121 		 * at this point!/ */
122 		errno = EINVAL;
123 		return -1;
124 	}
125 
126 	/* We might have had an earlier ENXIO error. */
127 	if (psp->psp_bpf == NULL) {
128 		errno = ENXIO;
129 		return -1;
130 	}
131 
132 	return bpf_send(psp->psp_bpf, psp->psp_proto,
133 	    iov->iov_base, iov->iov_len);
134 }
135 
136 static void
137 ps_bpf_recvmsg(void *arg, unsigned short events)
138 {
139 	struct ps_process *psp = arg;
140 
141 	if (ps_recvpsmsg(psp->psp_ctx, psp->psp_fd, events,
142 	    ps_bpf_recvmsgcb, arg) == -1)
143 		logerr(__func__);
144 }
145 
146 static int
147 ps_bpf_start_bpf(struct ps_process *psp)
148 {
149 	struct dhcpcd_ctx *ctx = psp->psp_ctx;
150 	char *addr;
151 	struct in_addr *ia = &psp->psp_id.psi_addr.psa_in_addr;
152 
153 	if (ia->s_addr == INADDR_ANY) {
154 		ia = NULL;
155 		addr = NULL;
156 	} else
157 		addr = inet_ntoa(*ia);
158 	setproctitle("[BPF %s] %s%s%s", psp->psp_protostr, psp->psp_ifname,
159 	    addr != NULL ? " " : "", addr != NULL ? addr : "");
160 	ps_freeprocesses(ctx, psp);
161 
162 	psp->psp_bpf = bpf_open(&psp->psp_ifp, psp->psp_filter, ia);
163 	if (psp->psp_bpf == NULL)
164 		logerr("%s: bpf_open",__func__);
165 #ifdef PRIVSEP_RIGHTS
166 	else if (ps_rights_limit_fd(psp->psp_bpf->bpf_fd) == -1)
167 		logerr("%s: ps_rights_limit_fd", __func__);
168 #endif
169 	else if (eloop_event_add(ctx->eloop, psp->psp_bpf->bpf_fd, ELE_READ,
170 	    ps_bpf_recvbpf, psp) == -1)
171 		logerr("%s: eloop_event_add", __func__);
172 	else {
173 		psp->psp_work_fd = psp->psp_bpf->bpf_fd;
174 		return 0;
175 	}
176 
177 	eloop_exit(ctx->eloop, EXIT_FAILURE);
178 	return -1;
179 }
180 
181 ssize_t
182 ps_bpf_cmd(struct dhcpcd_ctx *ctx, struct ps_msghdr *psm, struct msghdr *msg)
183 {
184 	uint16_t cmd;
185 	struct ps_process *psp;
186 	pid_t start;
187 	struct iovec *iov = msg->msg_iov;
188 	struct interface *ifp;
189 	struct in_addr *ia = &psm->ps_id.psi_addr.psa_in_addr;
190 	const char *addr;
191 
192 	cmd = (uint16_t)(psm->ps_cmd & ~(PS_START | PS_STOP));
193 	psp = ps_findprocess(ctx, &psm->ps_id);
194 
195 #ifdef PRIVSEP_DEBUG
196 	logerrx("%s: IN cmd %x, psp %p", __func__, psm->ps_cmd, psp);
197 #endif
198 
199 	switch (cmd) {
200 #ifdef ARP
201 	case PS_BPF_ARP:	/* FALLTHROUGH */
202 #endif
203 	case PS_BPF_BOOTP:
204 		break;
205 	default:
206 		logerrx("%s: unknown command %x", __func__, psm->ps_cmd);
207 		errno = ENOTSUP;
208 		return -1;
209 	}
210 
211 	if (!(psm->ps_cmd & PS_START)) {
212 		errno = EINVAL;
213 		return -1;
214 	}
215 
216 	if (psp != NULL)
217 		return 1;
218 
219 	psp = ps_newprocess(ctx, &psm->ps_id);
220 	if (psp == NULL)
221 		return -1;
222 
223 	ifp = &psp->psp_ifp;
224 	assert(msg->msg_iovlen == 1);
225 	assert(iov->iov_len == sizeof(*ifp));
226 	memcpy(ifp, iov->iov_base, sizeof(*ifp));
227 	ifp->ctx = psp->psp_ctx;
228 	ifp->options = NULL;
229 	memset(ifp->if_data, 0, sizeof(ifp->if_data));
230 
231 	memcpy(psp->psp_ifname, ifp->name, sizeof(psp->psp_ifname));
232 
233 	switch (cmd) {
234 #ifdef ARP
235 	case PS_BPF_ARP:
236 		psp->psp_proto = ETHERTYPE_ARP;
237 		psp->psp_protostr = "ARP";
238 		psp->psp_filter = bpf_arp;
239 		break;
240 #endif
241 	case PS_BPF_BOOTP:
242 		psp->psp_proto = ETHERTYPE_IP;
243 		psp->psp_protostr = "BOOTP";
244 		psp->psp_filter = bpf_bootp;
245 		break;
246 	}
247 
248 	if (ia->s_addr == INADDR_ANY)
249 		addr = NULL;
250 	else
251 		addr = inet_ntoa(*ia);
252 	snprintf(psp->psp_name, sizeof(psp->psp_name), "BPF %s%s%s",
253 	    psp->psp_protostr,
254 	    addr != NULL ? " " : "", addr != NULL ? addr : "");
255 
256 	start = ps_startprocess(psp, ps_bpf_recvmsg, NULL,
257 	    ps_bpf_start_bpf, NULL, PSF_DROPPRIVS);
258 	switch (start) {
259 	case -1:
260 		ps_freeprocess(psp);
261 		return -1;
262 	case 0:
263 		ps_entersandbox("stdio", NULL);
264 		break;
265 	default:
266 		logdebugx("%s: spawned %s on PID %d",
267 		    psp->psp_ifname, psp->psp_name, psp->psp_pid);
268 		break;
269 	}
270 	return start;
271 }
272 
273 ssize_t
274 ps_bpf_dispatch(struct dhcpcd_ctx *ctx,
275     struct ps_msghdr *psm, struct msghdr *msg)
276 {
277 	struct iovec *iov = msg->msg_iov;
278 	struct interface *ifp;
279 	uint8_t *bpf;
280 	size_t bpf_len;
281 
282 	switch (psm->ps_cmd) {
283 #ifdef ARP
284 	case PS_BPF_ARP:
285 #endif
286 	case PS_BPF_BOOTP:
287 		break;
288 	default:
289 		errno = ENOTSUP;
290 		return -1;
291 	}
292 
293 	ifp = if_findindex(ctx->ifaces, psm->ps_id.psi_ifindex);
294 	/* interface may have departed .... */
295 	if (ifp == NULL)
296 		return -1;
297 
298 	bpf = iov->iov_base;
299 	bpf_len = iov->iov_len;
300 
301 	switch (psm->ps_cmd) {
302 #ifdef ARP
303 	case PS_BPF_ARP:
304 		arp_packet(ifp, bpf, bpf_len, (unsigned int)psm->ps_flags);
305 		break;
306 #endif
307 	case PS_BPF_BOOTP:
308 		dhcp_packet(ifp, bpf, bpf_len, (unsigned int)psm->ps_flags);
309 		break;
310 	}
311 
312 	return 1;
313 }
314 
315 static ssize_t
316 ps_bpf_send(const struct interface *ifp, const struct in_addr *ia,
317     uint16_t cmd, const void *data, size_t len)
318 {
319 	struct dhcpcd_ctx *ctx = ifp->ctx;
320 	struct ps_msghdr psm = {
321 		.ps_cmd = cmd,
322 		.ps_id = {
323 			.psi_ifindex = ifp->index,
324 			.psi_cmd = (uint8_t)(cmd & ~(PS_START | PS_STOP)),
325 		},
326 	};
327 
328 	if (ia != NULL)
329 		psm.ps_id.psi_addr.psa_in_addr = *ia;
330 
331 	return ps_sendpsmdata(ctx, PS_ROOT_FD(ctx), &psm, data, len);
332 }
333 
334 #ifdef ARP
335 ssize_t
336 ps_bpf_openarp(const struct interface *ifp, const struct in_addr *ia)
337 {
338 
339 	assert(ia != NULL);
340 	return ps_bpf_send(ifp, ia, PS_BPF_ARP | PS_START,
341 	    ifp, sizeof(*ifp));
342 }
343 
344 ssize_t
345 ps_bpf_closearp(const struct interface *ifp, const struct in_addr *ia)
346 {
347 
348 	return ps_bpf_send(ifp, ia, PS_BPF_ARP | PS_STOP, NULL, 0);
349 }
350 
351 ssize_t
352 ps_bpf_sendarp(const struct interface *ifp, const struct in_addr *ia,
353     const void *data, size_t len)
354 {
355 
356 	assert(ia != NULL);
357 	return ps_bpf_send(ifp, ia, PS_BPF_ARP, data, len);
358 }
359 #endif
360 
361 ssize_t
362 ps_bpf_openbootp(const struct interface *ifp)
363 {
364 
365 	return ps_bpf_send(ifp, NULL, PS_BPF_BOOTP | PS_START,
366 	    ifp, sizeof(*ifp));
367 }
368 
369 ssize_t
370 ps_bpf_closebootp(const struct interface *ifp)
371 {
372 
373 	return ps_bpf_send(ifp, NULL, PS_BPF_BOOTP | PS_STOP, NULL, 0);
374 }
375 
376 ssize_t
377 ps_bpf_sendbootp(const struct interface *ifp, const void *data, size_t len)
378 {
379 
380 	return ps_bpf_send(ifp, NULL, PS_BPF_BOOTP, data, len);
381 }
382