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