1 /* SPDX-License-Identifier: BSD-2-Clause */
3 * Privilege Separation BPF Initiator
4 * Copyright (c) 2006-2023 Roy Marples <roy@marples.name>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
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
29 #include <sys/socket.h>
30 #include <sys/types.h>
32 /* Need these headers just for if_ether on some OS. */
35 #include <net/if_arp.h>
36 #include <netinet/in.h>
38 #include <netinet/if_ether.h>
57 ps_bpf_recvbpf(void *arg
, unsigned short events
)
59 struct ps_process
*psp
= arg
;
60 struct bpf
*bpf
= psp
->psp_bpf
;
61 uint8_t buf
[FRAMELEN_MAX
];
63 struct ps_msghdr psm
= {
65 .ps_cmd
= psp
->psp_id
.psi_cmd
,
68 if (events
!= ELE_READ
)
69 logerrx("%s: unexpected event 0x%04x", __func__
, events
);
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
));
79 if (errno
!= ENETDOWN
)
80 logerr("%s: %s", psp
->psp_ifname
, __func__
);
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
);
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
);
98 if (len
== -1 || len
== 0)
104 ps_bpf_recvmsgcb(void *arg
, struct ps_msghdr
*psm
, struct msghdr
*msg
)
106 struct ps_process
*psp
= arg
;
107 struct iovec
*iov
= msg
->msg_iov
;
110 logerrx("%s: IN cmd %x, psp %p", __func__
, psm
->ps_cmd
, psp
);
113 switch(psm
->ps_cmd
) {
115 case PS_BPF_ARP
: /* FALLTHROUGH */
120 /* IPC failure, we should not be processing any commands
126 /* We might have had an earlier ENXIO error. */
127 if (psp
->psp_bpf
== NULL
) {
132 return bpf_send(psp
->psp_bpf
, psp
->psp_proto
,
133 iov
->iov_base
, iov
->iov_len
);
137 ps_bpf_recvmsg(void *arg
, unsigned short events
)
139 struct ps_process
*psp
= arg
;
141 if (ps_recvpsmsg(psp
->psp_ctx
, psp
->psp_fd
, events
,
142 ps_bpf_recvmsgcb
, arg
) == -1)
147 ps_bpf_start_bpf(struct ps_process
*psp
)
149 struct dhcpcd_ctx
*ctx
= psp
->psp_ctx
;
151 struct in_addr
*ia
= &psp
->psp_id
.psi_addr
.psa_in_addr
;
153 if (ia
->s_addr
== INADDR_ANY
) {
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
);
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__
);
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__
);
173 psp
->psp_work_fd
= psp
->psp_bpf
->bpf_fd
;
177 eloop_exit(ctx
->eloop
, EXIT_FAILURE
);
182 ps_bpf_cmd(struct dhcpcd_ctx
*ctx
, struct ps_msghdr
*psm
, struct msghdr
*msg
)
185 struct ps_process
*psp
;
187 struct iovec
*iov
= msg
->msg_iov
;
188 struct interface
*ifp
;
189 struct in_addr
*ia
= &psm
->ps_id
.psi_addr
.psa_in_addr
;
192 cmd
= (uint16_t)(psm
->ps_cmd
& ~(PS_START
| PS_STOP
));
193 psp
= ps_findprocess(ctx
, &psm
->ps_id
);
196 logerrx("%s: IN cmd %x, psp %p", __func__
, psm
->ps_cmd
, psp
);
201 case PS_BPF_ARP
: /* FALLTHROUGH */
206 logerrx("%s: unknown command %x", __func__
, psm
->ps_cmd
);
211 if (!(psm
->ps_cmd
& PS_START
)) {
219 psp
= ps_newprocess(ctx
, &psm
->ps_id
);
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
;
229 memset(ifp
->if_data
, 0, sizeof(ifp
->if_data
));
231 memcpy(psp
->psp_ifname
, ifp
->name
, sizeof(psp
->psp_ifname
));
236 psp
->psp_proto
= ETHERTYPE_ARP
;
237 psp
->psp_protostr
= "ARP";
238 psp
->psp_filter
= bpf_arp
;
242 psp
->psp_proto
= ETHERTYPE_IP
;
243 psp
->psp_protostr
= "BOOTP";
244 psp
->psp_filter
= bpf_bootp
;
248 if (ia
->s_addr
== INADDR_ANY
)
251 addr
= inet_ntoa(*ia
);
252 snprintf(psp
->psp_name
, sizeof(psp
->psp_name
), "BPF %s%s%s",
254 addr
!= NULL
? " " : "", addr
!= NULL
? addr
: "");
256 start
= ps_startprocess(psp
, ps_bpf_recvmsg
, NULL
,
257 ps_bpf_start_bpf
, NULL
, PSF_DROPPRIVS
);
263 ps_entersandbox("stdio", NULL
);
266 logdebugx("%s: spawned %s on PID %d",
267 psp
->psp_ifname
, psp
->psp_name
, psp
->psp_pid
);
274 ps_bpf_dispatch(struct dhcpcd_ctx
*ctx
,
275 struct ps_msghdr
*psm
, struct msghdr
*msg
)
277 struct iovec
*iov
= msg
->msg_iov
;
278 struct interface
*ifp
;
282 switch (psm
->ps_cmd
) {
293 ifp
= if_findindex(ctx
->ifaces
, psm
->ps_id
.psi_ifindex
);
294 /* interface may have departed .... */
299 bpf_len
= iov
->iov_len
;
301 switch (psm
->ps_cmd
) {
304 arp_packet(ifp
, bpf
, bpf_len
, (unsigned int)psm
->ps_flags
);
308 dhcp_packet(ifp
, bpf
, bpf_len
, (unsigned int)psm
->ps_flags
);
316 ps_bpf_send(const struct interface
*ifp
, const struct in_addr
*ia
,
317 uint16_t cmd
, const void *data
, size_t len
)
319 struct dhcpcd_ctx
*ctx
= ifp
->ctx
;
320 struct ps_msghdr psm
= {
323 .psi_ifindex
= ifp
->index
,
324 .psi_cmd
= (uint8_t)(cmd
& ~(PS_START
| PS_STOP
)),
329 psm
.ps_id
.psi_addr
.psa_in_addr
= *ia
;
331 return ps_sendpsmdata(ctx
, PS_ROOT_FD(ctx
), &psm
, data
, len
);
336 ps_bpf_openarp(const struct interface
*ifp
, const struct in_addr
*ia
)
340 return ps_bpf_send(ifp
, ia
, PS_BPF_ARP
| PS_START
,
345 ps_bpf_closearp(const struct interface
*ifp
, const struct in_addr
*ia
)
348 return ps_bpf_send(ifp
, ia
, PS_BPF_ARP
| PS_STOP
, NULL
, 0);
352 ps_bpf_sendarp(const struct interface
*ifp
, const struct in_addr
*ia
,
353 const void *data
, size_t len
)
357 return ps_bpf_send(ifp
, ia
, PS_BPF_ARP
, data
, len
);
362 ps_bpf_openbootp(const struct interface
*ifp
)
365 return ps_bpf_send(ifp
, NULL
, PS_BPF_BOOTP
| PS_START
,
370 ps_bpf_closebootp(const struct interface
*ifp
)
373 return ps_bpf_send(ifp
, NULL
, PS_BPF_BOOTP
| PS_STOP
, NULL
, 0);
377 ps_bpf_sendbootp(const struct interface
*ifp
, const void *data
, size_t len
)
380 return ps_bpf_send(ifp
, NULL
, PS_BPF_BOOTP
, data
, len
);