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 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 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 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 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 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 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 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 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 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 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 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 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 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