1 /* SPDX-License-Identifier: BSD-2-Clause */ 2 /* 3 * Privilege Separation BPF Initiator 4 * Copyright (c) 2006-2020 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 <signal.h> 44 #include <stdlib.h> 45 #include <string.h> 46 #include <unistd.h> 47 48 #include "arp.h" 49 #include "bpf.h" 50 #include "dhcp.h" 51 #include "dhcp6.h" 52 #include "eloop.h" 53 #include "ipv6nd.h" 54 #include "logerr.h" 55 #include "privsep.h" 56 57 static void 58 ps_bpf_recvbpf(void *arg) 59 { 60 struct ps_process *psp = arg; 61 unsigned int flags; 62 uint8_t buf[FRAMELEN_MAX]; 63 ssize_t len; 64 struct ps_msghdr psm = { 65 .ps_id = psp->psp_id, 66 .ps_cmd = psp->psp_id.psi_cmd, 67 }; 68 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 flags = 0; 72 while (!(flags & BPF_EOF)) { 73 len = bpf_read(&psp->psp_ifp, psp->psp_work_fd, 74 buf, sizeof(buf), &flags); 75 if (len == -1) 76 logerr(__func__); 77 if (len == -1 || len == 0) 78 break; 79 len = ps_sendpsmdata(psp->psp_ctx, psp->psp_ctx->ps_data_fd, 80 &psm, buf, (size_t)len); 81 if (len == -1 && errno != ECONNRESET) 82 logerr(__func__); 83 if (len == -1 || len == 0) 84 break; 85 } 86 } 87 88 #ifdef ARP 89 static ssize_t 90 ps_bpf_arp_addr(uint8_t cmd, struct ps_process *psp, struct msghdr *msg) 91 { 92 struct interface *ifp = &psp->psp_ifp; 93 struct iovec *iov = msg->msg_iov; 94 struct in_addr addr; 95 struct arp_state *astate; 96 97 if (psp == NULL) { 98 errno = ESRCH; 99 return -1; 100 } 101 102 assert(msg->msg_iovlen == 1); 103 assert(iov->iov_len == sizeof(addr)); 104 memcpy(&addr, iov->iov_base, sizeof(addr)); 105 if (cmd & PS_START) { 106 astate = arp_new(ifp, &addr); 107 if (astate == NULL) 108 return -1; 109 } else if (cmd & PS_DELETE) { 110 astate = arp_find(ifp, &addr); 111 if (astate == NULL) { 112 errno = ESRCH; 113 return -1; 114 } 115 arp_free(astate); 116 } else { 117 errno = EINVAL; 118 return -1; 119 } 120 121 return bpf_arp(ifp, psp->psp_work_fd); 122 } 123 #endif 124 125 static ssize_t 126 ps_bpf_recvmsgcb(void *arg, struct ps_msghdr *psm, struct msghdr *msg) 127 { 128 struct ps_process *psp = arg; 129 struct iovec *iov = msg->msg_iov; 130 131 #ifdef ARP 132 if (psm->ps_cmd & (PS_START | PS_DELETE)) 133 return ps_bpf_arp_addr(psm->ps_cmd, psp, msg); 134 #endif 135 136 return bpf_send(&psp->psp_ifp, psp->psp_work_fd, psp->psp_proto, 137 iov->iov_base, iov->iov_len); 138 } 139 140 static void 141 ps_bpf_recvmsg(void *arg) 142 { 143 struct ps_process *psp = arg; 144 145 if (ps_recvpsmsg(psp->psp_ctx, psp->psp_fd, 146 ps_bpf_recvmsgcb, arg) == -1) 147 logerr(__func__); 148 } 149 150 static int 151 ps_bpf_start_bpf(void *arg) 152 { 153 struct ps_process *psp = arg; 154 struct dhcpcd_ctx *ctx = psp->psp_ctx; 155 156 setproctitle("[BPF %s] %s", psp->psp_protostr, psp->psp_ifname); 157 158 ps_freeprocesses(ctx, psp); 159 160 psp->psp_work_fd = bpf_open(&psp->psp_ifp, psp->psp_filter); 161 if (psp->psp_work_fd == -1) 162 logerr("%s: bpf_open",__func__); 163 else if (eloop_event_add(ctx->eloop, 164 psp->psp_work_fd, ps_bpf_recvbpf, psp) == -1) 165 logerr("%s: eloop_event_add", __func__); 166 else 167 return 0; 168 169 eloop_exit(ctx->eloop, EXIT_FAILURE); 170 return -1; 171 } 172 173 static void 174 ps_bpf_signal_bpfcb(int sig, void *arg) 175 { 176 struct dhcpcd_ctx *ctx = arg; 177 178 eloop_exit(ctx->eloop, sig == SIGTERM ? EXIT_SUCCESS : EXIT_FAILURE); 179 } 180 181 ssize_t 182 ps_bpf_cmd(struct dhcpcd_ctx *ctx, struct ps_msghdr *psm, struct msghdr *msg) 183 { 184 uint8_t cmd; 185 struct ps_process *psp; 186 pid_t start; 187 struct iovec *iov = msg->msg_iov; 188 struct interface *ifp; 189 struct ipv4_state *istate; 190 191 cmd = (uint8_t)(psm->ps_cmd & ~(PS_START | PS_STOP)); 192 psp = ps_findprocess(ctx, &psm->ps_id); 193 194 #ifdef PRIVSEP_DEBUG 195 logerrx("%s: IN cmd %x, psp %p", __func__, psm->ps_cmd, psp); 196 #endif 197 198 switch (cmd) { 199 #ifdef ARP 200 case PS_BPF_ARP: /* FALLTHROUGH */ 201 #endif 202 case PS_BPF_BOOTP: 203 break; 204 default: 205 logerrx("%s: unknown command %x", __func__, psm->ps_cmd); 206 errno = ENOTSUP; 207 return -1; 208 } 209 210 if (!(psm->ps_cmd & PS_START)) { 211 errno = EINVAL; 212 return -1; 213 } 214 215 if (psp != NULL) 216 return 1; 217 218 psp = ps_newprocess(ctx, &psm->ps_id); 219 if (psp == NULL) 220 return -1; 221 222 ifp = &psp->psp_ifp; 223 assert(msg->msg_iovlen == 1); 224 assert(iov->iov_len == sizeof(*ifp)); 225 memcpy(ifp, iov->iov_base, sizeof(*ifp)); 226 ifp->ctx = psp->psp_ctx; 227 ifp->options = NULL; 228 memset(ifp->if_data, 0, sizeof(ifp->if_data)); 229 230 if ((istate = ipv4_getstate(ifp)) == NULL) { 231 ps_freeprocess(psp); 232 return -1; 233 } 234 235 memcpy(psp->psp_ifname, ifp->name, sizeof(psp->psp_ifname)); 236 237 switch (cmd) { 238 #ifdef ARP 239 case PS_BPF_ARP: 240 psp->psp_proto = ETHERTYPE_ARP; 241 psp->psp_protostr = "ARP"; 242 psp->psp_filter = bpf_arp; 243 break; 244 #endif 245 case PS_BPF_BOOTP: 246 psp->psp_proto = ETHERTYPE_IP; 247 psp->psp_protostr = "BOOTP"; 248 psp->psp_filter = bpf_bootp; 249 break; 250 } 251 252 start = ps_dostart(ctx, 253 &psp->psp_pid, &psp->psp_fd, 254 ps_bpf_recvmsg, NULL, psp, 255 ps_bpf_start_bpf, ps_bpf_signal_bpfcb, PSF_DROPPRIVS); 256 switch (start) { 257 case -1: 258 ps_freeprocess(psp); 259 return -1; 260 case 0: 261 break; 262 default: 263 #ifdef PRIVSEP_DEBUG 264 logdebugx("%s: spawned BPF %s on PID %d", 265 psp->psp_ifname, psp->psp_protostr, start); 266 #endif 267 break; 268 } 269 return start; 270 } 271 272 ssize_t 273 ps_bpf_dispatch(struct dhcpcd_ctx *ctx, 274 struct ps_msghdr *psm, struct msghdr *msg) 275 { 276 struct iovec *iov = msg->msg_iov; 277 struct interface *ifp; 278 279 ifp = if_findindex(ctx->ifaces, psm->ps_id.psi_ifindex); 280 281 switch (psm->ps_cmd) { 282 #ifdef ARP 283 case PS_BPF_ARP: 284 arp_packet(ifp, iov->iov_base, iov->iov_len); 285 break; 286 #endif 287 case PS_BPF_BOOTP: 288 dhcp_packet(ifp, iov->iov_base, iov->iov_len); 289 break; 290 default: 291 errno = ENOTSUP; 292 return -1; 293 } 294 295 return 1; 296 } 297 298 static ssize_t 299 ps_bpf_send(const struct interface *ifp, uint8_t cmd, 300 const void *data, size_t len) 301 { 302 struct dhcpcd_ctx *ctx = ifp->ctx; 303 struct ps_msghdr psm = { 304 .ps_cmd = cmd, 305 .ps_id = { 306 .psi_ifindex = ifp->index, 307 .psi_cmd = (uint8_t)(cmd & 308 ~(PS_START | PS_STOP | PS_DELETE)), 309 }, 310 }; 311 312 if (psm.ps_id.psi_cmd == PS_BPF_ARP_ADDR) 313 psm.ps_id.psi_cmd = PS_BPF_ARP; 314 315 return ps_sendpsmdata(ctx, ctx->ps_root_fd, &psm, data, len); 316 } 317 318 #ifdef ARP 319 ssize_t 320 ps_bpf_openarp(const struct interface *ifp) 321 { 322 323 return ps_bpf_send(ifp, PS_BPF_ARP | PS_START, ifp, sizeof(*ifp)); 324 } 325 326 ssize_t 327 ps_bpf_addaddr(const struct interface *ifp, const struct in_addr *addr) 328 { 329 330 return ps_bpf_send(ifp, PS_BPF_ARP_ADDR | PS_START, addr, sizeof(*addr)); 331 } 332 333 ssize_t 334 ps_bpf_deladdr(const struct interface *ifp, const struct in_addr *addr) 335 { 336 337 return ps_bpf_send(ifp, PS_BPF_ARP_ADDR | PS_DELETE, addr, sizeof(*addr)); 338 } 339 340 ssize_t 341 ps_bpf_closearp(const struct interface *ifp) 342 { 343 344 return ps_bpf_send(ifp, PS_BPF_ARP | PS_STOP, NULL, 0); 345 } 346 347 ssize_t 348 ps_bpf_sendarp(const struct interface *ifp, const void *data, size_t len) 349 { 350 351 return ps_bpf_send(ifp, PS_BPF_ARP, data, len); 352 } 353 #endif 354 355 ssize_t 356 ps_bpf_openbootp(const struct interface *ifp) 357 { 358 359 return ps_bpf_send(ifp, PS_BPF_BOOTP | PS_START, ifp, sizeof(*ifp)); 360 } 361 362 ssize_t 363 ps_bpf_closebootp(const struct interface *ifp) 364 { 365 366 return ps_bpf_send(ifp, PS_BPF_BOOTP | PS_STOP, NULL, 0); 367 } 368 369 ssize_t 370 ps_bpf_sendbootp(const struct interface *ifp, const void *data, size_t len) 371 { 372 373 return ps_bpf_send(ifp, PS_BPF_BOOTP, data, len); 374 } 375