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>
56 /* We expect to have open 3 SEQPACKET and one RAW fd */
59 ps_bpf_recvbpf(void *arg
, unsigned short events
)
61 struct ps_process
*psp
= arg
;
62 struct bpf
*bpf
= psp
->psp_bpf
;
63 uint8_t buf
[FRAMELEN_MAX
];
65 struct ps_msghdr psm
= {
67 .ps_cmd
= psp
->psp_id
.psi_cmd
,
70 if (events
!= ELE_READ
)
71 logerrx("%s: unexpected event 0x%04x", __func__
, events
);
73 bpf
->bpf_flags
&= ~BPF_EOF
;
74 /* A BPF read can read more than one filtered packet at time.
75 * This mechanism allows us to read each packet from the buffer. */
76 while (!(bpf
->bpf_flags
& BPF_EOF
)) {
77 len
= bpf_read(bpf
, buf
, sizeof(buf
));
81 if (errno
!= ENETDOWN
)
82 logerr("%s: %s", psp
->psp_ifname
, __func__
);
85 /* If the interface has departed, close the BPF
86 * socket. This stops log spam if RTM_IFANNOUNCE is
87 * delayed in announcing the departing interface. */
88 eloop_event_delete(psp
->psp_ctx
->eloop
, bpf
->bpf_fd
);
95 psm
.ps_flags
= bpf
->bpf_flags
;
96 len
= ps_sendpsmdata(psp
->psp_ctx
, psp
->psp_ctx
->ps_data_fd
,
97 &psm
, buf
, (size_t)len
);
100 if (len
== -1 || len
== 0)
106 ps_bpf_recvmsgcb(void *arg
, struct ps_msghdr
*psm
, struct msghdr
*msg
)
108 struct ps_process
*psp
= arg
;
109 struct iovec
*iov
= msg
->msg_iov
;
112 logerrx("%s: IN cmd %x, psp %p", __func__
, psm
->ps_cmd
, psp
);
115 switch(psm
->ps_cmd
) {
117 case PS_BPF_ARP
: /* FALLTHROUGH */
122 /* IPC failure, we should not be processing any commands
128 /* We might have had an earlier ENXIO error. */
129 if (psp
->psp_bpf
== NULL
) {
134 return bpf_send(psp
->psp_bpf
, psp
->psp_proto
,
135 iov
->iov_base
, iov
->iov_len
);
139 ps_bpf_recvmsg(void *arg
, unsigned short events
)
141 struct ps_process
*psp
= arg
;
143 if (ps_recvpsmsg(psp
->psp_ctx
, psp
->psp_fd
, events
,
144 ps_bpf_recvmsgcb
, arg
) == -1)
149 ps_bpf_start_bpf(struct ps_process
*psp
)
151 struct dhcpcd_ctx
*ctx
= psp
->psp_ctx
;
153 struct in_addr
*ia
= &psp
->psp_id
.psi_addr
.psa_in_addr
;
155 if (ia
->s_addr
== INADDR_ANY
) {
159 addr
= inet_ntoa(*ia
);
160 setproctitle("[BPF %s] %s%s%s", psp
->psp_protostr
, psp
->psp_ifname
,
161 addr
!= NULL
? " " : "", addr
!= NULL
? addr
: "");
162 ps_freeprocesses(ctx
, psp
);
164 psp
->psp_bpf
= bpf_open(&psp
->psp_ifp
, psp
->psp_filter
, ia
);
166 logdebugx("pid %d bpf_fd=%d", getpid(), psp
->psp_bpf
->bpf_fd
);
168 if (psp
->psp_bpf
== NULL
)
169 logerr("%s: bpf_open",__func__
);
170 #ifdef PRIVSEP_RIGHTS
171 else if (ps_rights_limit_fd(psp
->psp_bpf
->bpf_fd
) == -1)
172 logerr("%s: ps_rights_limit_fd", __func__
);
174 else if (eloop_event_add(ctx
->eloop
, psp
->psp_bpf
->bpf_fd
, ELE_READ
,
175 ps_bpf_recvbpf
, psp
) == -1)
176 logerr("%s: eloop_event_add", __func__
);
178 psp
->psp_work_fd
= psp
->psp_bpf
->bpf_fd
;
182 eloop_exit(ctx
->eloop
, EXIT_FAILURE
);
187 ps_bpf_cmd(struct dhcpcd_ctx
*ctx
, struct ps_msghdr
*psm
, struct msghdr
*msg
)
190 struct ps_process
*psp
;
192 struct iovec
*iov
= msg
->msg_iov
;
193 struct interface
*ifp
;
194 struct in_addr
*ia
= &psm
->ps_id
.psi_addr
.psa_in_addr
;
197 cmd
= (uint16_t)(psm
->ps_cmd
& ~(PS_START
| PS_STOP
));
198 psp
= ps_findprocess(ctx
, &psm
->ps_id
);
201 logerrx("%s: IN cmd %x, psp %p", __func__
, psm
->ps_cmd
, psp
);
206 case PS_BPF_ARP
: /* FALLTHROUGH */
211 logerrx("%s: unknown command %x", __func__
, psm
->ps_cmd
);
216 if (!(psm
->ps_cmd
& PS_START
)) {
224 psp
= ps_newprocess(ctx
, &psm
->ps_id
);
229 assert(msg
->msg_iovlen
== 1);
230 assert(iov
->iov_len
== sizeof(*ifp
));
231 memcpy(ifp
, iov
->iov_base
, sizeof(*ifp
));
232 ifp
->ctx
= psp
->psp_ctx
;
234 memset(ifp
->if_data
, 0, sizeof(ifp
->if_data
));
236 memcpy(psp
->psp_ifname
, ifp
->name
, sizeof(psp
->psp_ifname
));
241 psp
->psp_proto
= ETHERTYPE_ARP
;
242 psp
->psp_protostr
= "ARP";
243 psp
->psp_filter
= bpf_arp
;
247 psp
->psp_proto
= ETHERTYPE_IP
;
248 psp
->psp_protostr
= "BOOTP";
249 psp
->psp_filter
= bpf_bootp
;
253 if (ia
->s_addr
== INADDR_ANY
)
256 addr
= inet_ntoa(*ia
);
257 snprintf(psp
->psp_name
, sizeof(psp
->psp_name
), "BPF %s%s%s",
259 addr
!= NULL
? " " : "", addr
!= NULL
? addr
: "");
261 start
= ps_startprocess(psp
, ps_bpf_recvmsg
, NULL
,
262 ps_bpf_start_bpf
, NULL
, PSF_DROPPRIVS
);
268 ps_entersandbox("stdio", NULL
);
271 logdebugx("%s: spawned %s on PID %d",
272 psp
->psp_ifname
, psp
->psp_name
, psp
->psp_pid
);
279 ps_bpf_dispatch(struct dhcpcd_ctx
*ctx
,
280 struct ps_msghdr
*psm
, struct msghdr
*msg
)
282 struct iovec
*iov
= msg
->msg_iov
;
283 struct interface
*ifp
;
287 switch (psm
->ps_cmd
) {
298 ifp
= if_findindex(ctx
->ifaces
, psm
->ps_id
.psi_ifindex
);
299 /* interface may have departed .... */
304 bpf_len
= iov
->iov_len
;
306 switch (psm
->ps_cmd
) {
309 arp_packet(ifp
, bpf
, bpf_len
, (unsigned int)psm
->ps_flags
);
313 dhcp_packet(ifp
, bpf
, bpf_len
, (unsigned int)psm
->ps_flags
);
321 ps_bpf_send(const struct interface
*ifp
, const struct in_addr
*ia
,
322 uint16_t cmd
, const void *data
, size_t len
)
324 struct dhcpcd_ctx
*ctx
= ifp
->ctx
;
325 struct ps_msghdr psm
= {
328 .psi_ifindex
= ifp
->index
,
329 .psi_cmd
= (uint8_t)(cmd
& ~(PS_START
| PS_STOP
)),
334 psm
.ps_id
.psi_addr
.psa_in_addr
= *ia
;
336 return ps_sendpsmdata(ctx
, PS_ROOT_FD(ctx
), &psm
, data
, len
);
341 ps_bpf_openarp(const struct interface
*ifp
, const struct in_addr
*ia
)
345 return ps_bpf_send(ifp
, ia
, PS_BPF_ARP
| PS_START
,
350 ps_bpf_closearp(const struct interface
*ifp
, const struct in_addr
*ia
)
353 return ps_bpf_send(ifp
, ia
, PS_BPF_ARP
| PS_STOP
, NULL
, 0);
357 ps_bpf_sendarp(const struct interface
*ifp
, const struct in_addr
*ia
,
358 const void *data
, size_t len
)
362 return ps_bpf_send(ifp
, ia
, PS_BPF_ARP
, data
, len
);
367 ps_bpf_openbootp(const struct interface
*ifp
)
370 return ps_bpf_send(ifp
, NULL
, PS_BPF_BOOTP
| PS_START
,
375 ps_bpf_closebootp(const struct interface
*ifp
)
378 return ps_bpf_send(ifp
, NULL
, PS_BPF_BOOTP
| PS_STOP
, NULL
, 0);
382 ps_bpf_sendbootp(const struct interface
*ifp
, const void *data
, size_t len
)
385 return ps_bpf_send(ifp
, NULL
, PS_BPF_BOOTP
, data
, len
);