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, ctx->ps_root->psp_fd, &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