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