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