1 /* 2 * Privilege Separation BPF Initiator 3 * SPDX-License-Identifier: BSD-2-Clause 4 * Copyright (c) 2006-2025 Roy Marples <roy (at) 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/types.h> 30 #include <sys/socket.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 <errno.h> 42 #include <pwd.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 SOCK_STREAM and one RAW fd */ 57 58 static void 59 ps_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 | ELE_ERROR))) 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 105 static ssize_t 106 ps_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, iov->iov_base, 135 iov->iov_len); 136 } 137 138 static void 139 ps_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, ps_bpf_recvmsgcb, 144 arg) == -1) 145 logerr(__func__); 146 } 147 148 static int 149 ps_bpf_start_bpf(struct ps_process *psp) 150 { 151 struct dhcpcd_ctx *ctx = psp->psp_ctx; 152 struct in_addr *ia = &psp->psp_id.psi_addr.psa_in_addr; 153 #ifdef HAVE_SETPROCTITLE 154 char *addr; 155 #endif 156 157 if (ia->s_addr == INADDR_ANY) 158 ia = NULL; 159 160 #ifdef HAVE_SETPROCTITLE 161 addr = ia != NULL ? inet_ntoa(*ia) : NULL; 162 setproctitle("[BPF %s] %s%s%s", psp->psp_protostr, psp->psp_ifname, 163 addr != NULL ? " " : "", addr != NULL ? addr : ""); 164 #endif 165 166 ps_freeprocesses(ctx, psp); 167 168 psp->psp_bpf = bpf_open(&psp->psp_ifp, psp->psp_filter, ia); 169 #ifdef DEBUG_FD 170 logdebugx("pid %ld bpf_fd=%d", (long)getpid(), psp->psp_bpf->bpf_fd); 171 #endif 172 if (psp->psp_bpf == NULL) 173 logerr("%s: bpf_open", __func__); 174 #ifdef PRIVSEP_RIGHTS 175 else if (ps_rights_limit_fd(psp->psp_bpf->bpf_fd) == -1) 176 logerr("%s: ps_rights_limit_fd", __func__); 177 #endif 178 else if (eloop_event_add(ctx->eloop, psp->psp_bpf->bpf_fd, ELE_READ, 179 ps_bpf_recvbpf, psp) == -1) 180 logerr("%s: eloop_event_add", __func__); 181 else { 182 psp->psp_work_fd = psp->psp_bpf->bpf_fd; 183 return 0; 184 } 185 186 eloop_exit(ctx->eloop, EXIT_FAILURE); 187 return -1; 188 } 189 190 ssize_t 191 ps_bpf_cmd(struct dhcpcd_ctx *ctx, struct ps_msghdr *psm, struct msghdr *msg) 192 { 193 uint16_t cmd; 194 struct ps_process *psp; 195 pid_t start; 196 struct iovec *iov = msg->msg_iov; 197 struct interface *ifp; 198 struct in_addr *ia = &psm->ps_id.psi_addr.psa_in_addr; 199 const char *addr; 200 201 cmd = (uint16_t)(psm->ps_cmd & ~(PS_START | PS_STOP)); 202 psp = ps_findprocess(ctx, &psm->ps_id); 203 204 #ifdef PRIVSEP_DEBUG 205 logerrx("%s: IN cmd %x, psp %p", __func__, psm->ps_cmd, psp); 206 #endif 207 208 switch (cmd) { 209 #ifdef ARP 210 case PS_BPF_ARP: /* FALLTHROUGH */ 211 #endif 212 case PS_BPF_BOOTP: 213 break; 214 default: 215 logerrx("%s: unknown command %x", __func__, psm->ps_cmd); 216 errno = ENOTSUP; 217 return -1; 218 } 219 220 if (!(psm->ps_cmd & PS_START)) { 221 errno = EINVAL; 222 return -1; 223 } 224 225 if (psp != NULL) 226 return 1; 227 228 psp = ps_newprocess(ctx, &psm->ps_id); 229 if (psp == NULL) 230 return -1; 231 232 ifp = &psp->psp_ifp; 233 assert(msg->msg_iovlen == 1); 234 assert(iov->iov_len == sizeof(*ifp)); 235 memcpy(ifp, iov->iov_base, sizeof(*ifp)); 236 ifp->ctx = psp->psp_ctx; 237 ifp->options = NULL; 238 memset(ifp->if_data, 0, sizeof(ifp->if_data)); 239 240 memcpy(psp->psp_ifname, ifp->name, sizeof(psp->psp_ifname)); 241 242 switch (cmd) { 243 #ifdef ARP 244 case PS_BPF_ARP: 245 psp->psp_proto = ETHERTYPE_ARP; 246 psp->psp_protostr = "ARP"; 247 psp->psp_filter = bpf_filter_arp; 248 break; 249 #endif 250 case PS_BPF_BOOTP: 251 psp->psp_proto = ETHERTYPE_IP; 252 psp->psp_protostr = "BOOTP"; 253 psp->psp_filter = bpf_filter_bootp; 254 break; 255 } 256 257 if (ia->s_addr == INADDR_ANY) 258 addr = NULL; 259 else 260 addr = inet_ntoa(*ia); 261 snprintf(psp->psp_name, sizeof(psp->psp_name), "BPF %s%s%s", 262 psp->psp_protostr, addr != NULL ? " " : "", 263 addr != NULL ? addr : ""); 264 265 start = ps_startprocess(psp, ps_bpf_recvmsg, NULL, ps_bpf_start_bpf, 266 PSF_DROPPRIVS); 267 268 switch (start) { 269 case -1: 270 ps_freeprocess(psp); 271 return -1; 272 case 0: 273 ps_entersandbox("stdio", NULL); 274 break; 275 default: 276 logdebugx("%s: spawned %s on PID %ld", psp->psp_ifname, 277 psp->psp_name, (long)psp->psp_pid); 278 break; 279 } 280 return start; 281 } 282 283 ssize_t 284 ps_bpf_dispatch(struct dhcpcd_ctx *ctx, struct ps_msghdr *psm, 285 struct msghdr *msg) 286 { 287 struct iovec *iov = msg->msg_iov; 288 struct interface *ifp; 289 uint8_t *bpf; 290 size_t bpf_len; 291 292 switch (psm->ps_cmd) { 293 #ifdef ARP 294 case PS_BPF_ARP: 295 #endif 296 case PS_BPF_BOOTP: 297 break; 298 default: 299 errno = ENOTSUP; 300 return -1; 301 } 302 303 ifp = if_findindex(ctx->ifaces, psm->ps_id.psi_ifindex); 304 /* interface may have departed .... */ 305 if (ifp == NULL) 306 return -1; 307 308 bpf = iov->iov_base; 309 bpf_len = iov->iov_len; 310 311 switch (psm->ps_cmd) { 312 #ifdef ARP 313 case PS_BPF_ARP: 314 arp_packet(ifp, bpf, bpf_len, (unsigned int)psm->ps_flags); 315 break; 316 #endif 317 case PS_BPF_BOOTP: 318 dhcp_packet(ifp, bpf, bpf_len, (unsigned int)psm->ps_flags); 319 break; 320 } 321 322 return 1; 323 } 324 325 static ssize_t 326 ps_bpf_send(const struct interface *ifp, const struct in_addr *ia, uint16_t cmd, 327 const void *data, size_t len) 328 { 329 struct dhcpcd_ctx *ctx = ifp->ctx; 330 struct ps_msghdr psm = { 331 .ps_cmd = cmd, 332 .ps_id = { 333 .psi_ifindex = ifp->index, 334 .psi_cmd = (uint8_t)(cmd & ~(PS_START | PS_STOP)), 335 }, 336 }; 337 338 if (ia != NULL) 339 psm.ps_id.psi_addr.psa_in_addr = *ia; 340 341 return ps_sendpsmdata(ctx, PS_ROOT_FD(ctx), &psm, data, len); 342 } 343 344 #ifdef ARP 345 ssize_t 346 ps_bpf_openarp(const struct interface *ifp, const struct in_addr *ia) 347 { 348 assert(ia != NULL); 349 return ps_bpf_send(ifp, ia, PS_BPF_ARP | PS_START, ifp, sizeof(*ifp)); 350 } 351 352 ssize_t 353 ps_bpf_closearp(const struct interface *ifp, const struct in_addr *ia) 354 { 355 return ps_bpf_send(ifp, ia, PS_BPF_ARP | PS_STOP, NULL, 0); 356 } 357 358 ssize_t 359 ps_bpf_sendarp(const struct interface *ifp, const struct in_addr *ia, 360 const void *data, size_t len) 361 { 362 assert(ia != NULL); 363 return ps_bpf_send(ifp, ia, PS_BPF_ARP, data, len); 364 } 365 #endif 366 367 ssize_t 368 ps_bpf_openbootp(const struct interface *ifp) 369 { 370 return ps_bpf_send(ifp, NULL, PS_BPF_BOOTP | PS_START, ifp, 371 sizeof(*ifp)); 372 } 373 374 ssize_t 375 ps_bpf_closebootp(const struct interface *ifp) 376 { 377 return ps_bpf_send(ifp, NULL, PS_BPF_BOOTP | PS_STOP, NULL, 0); 378 } 379 380 ssize_t 381 ps_bpf_sendbootp(const struct interface *ifp, const void *data, size_t len) 382 { 383 return ps_bpf_send(ifp, NULL, PS_BPF_BOOTP, data, len); 384 } 385