1 /* SPDX-License-Identifier: BSD-2-Clause */
3 * Privilege Separation BPF Initiator
4 * Copyright (c) 2006-2020 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 #include <sys/capsicum.h>
61 ps_bpf_recvbpf(void *arg
)
63 struct ps_process
*psp
= arg
;
64 struct bpf
*bpf
= psp
->psp_bpf
;
65 uint8_t buf
[FRAMELEN_MAX
];
67 struct ps_msghdr psm
= {
69 .ps_cmd
= psp
->psp_id
.psi_cmd
,
72 bpf
->bpf_flags
&= ~BPF_EOF
;
73 /* A BPF read can read more than one filtered packet at time.
74 * This mechanism allows us to read each packet from the buffer. */
75 while (!(bpf
->bpf_flags
& BPF_EOF
)) {
76 len
= bpf_read(bpf
, buf
, sizeof(buf
));
79 if (len
== -1 || len
== 0)
81 psm
.ps_flags
= bpf
->bpf_flags
;
82 len
= ps_sendpsmdata(psp
->psp_ctx
, psp
->psp_ctx
->ps_data_fd
,
83 &psm
, buf
, (size_t)len
);
86 if (len
== -1 || len
== 0)
92 ps_bpf_recvmsgcb(void *arg
, struct ps_msghdr
*psm
, struct msghdr
*msg
)
94 struct ps_process
*psp
= arg
;
95 struct iovec
*iov
= msg
->msg_iov
;
98 logerrx("%s: IN cmd %x, psp %p", __func__
, psm
->ps_cmd
, psp
);
101 switch(psm
->ps_cmd
) {
103 case PS_BPF_ARP
: /* FALLTHROUGH */
108 /* IPC failure, we should not be processing any commands
114 return bpf_send(psp
->psp_bpf
, psp
->psp_proto
,
115 iov
->iov_base
, iov
->iov_len
);
119 ps_bpf_recvmsg(void *arg
)
121 struct ps_process
*psp
= arg
;
123 if (ps_recvpsmsg(psp
->psp_ctx
, psp
->psp_fd
,
124 ps_bpf_recvmsgcb
, arg
) == -1)
129 ps_bpf_start_bpf(void *arg
)
131 struct ps_process
*psp
= arg
;
132 struct dhcpcd_ctx
*ctx
= psp
->psp_ctx
;
134 struct in_addr
*ia
= &psp
->psp_id
.psi_addr
.psa_in_addr
;
138 /* We need CAP_IOCTL so we can change the BPF filter when we
140 cap_rights_init(&rights
, CAP_READ
, CAP_WRITE
, CAP_EVENT
, CAP_IOCTL
);
143 if (ia
->s_addr
== INADDR_ANY
) {
147 addr
= inet_ntoa(*ia
);
148 setproctitle("[BPF %s] %s%s%s", psp
->psp_protostr
, psp
->psp_ifname
,
149 addr
!= NULL
? " " : "", addr
!= NULL
? addr
: "");
150 ps_freeprocesses(ctx
, psp
);
152 psp
->psp_bpf
= bpf_open(&psp
->psp_ifp
, psp
->psp_filter
, ia
);
153 if (psp
->psp_bpf
== NULL
)
154 logerr("%s: bpf_open",__func__
);
156 else if (cap_rights_limit(psp
->psp_bpf
->bpf_fd
, &rights
) == -1 &&
158 logerr("%s: cap_rights_limit", __func__
);
160 else if (eloop_event_add(ctx
->eloop
,
161 psp
->psp_bpf
->bpf_fd
, ps_bpf_recvbpf
, psp
) == -1)
162 logerr("%s: eloop_event_add", __func__
);
164 psp
->psp_work_fd
= psp
->psp_bpf
->bpf_fd
;
168 eloop_exit(ctx
->eloop
, EXIT_FAILURE
);
173 ps_bpf_cmd(struct dhcpcd_ctx
*ctx
, struct ps_msghdr
*psm
, struct msghdr
*msg
)
176 struct ps_process
*psp
;
178 struct iovec
*iov
= msg
->msg_iov
;
179 struct interface
*ifp
;
181 cmd
= (uint16_t)(psm
->ps_cmd
& ~(PS_START
| PS_STOP
));
182 psp
= ps_findprocess(ctx
, &psm
->ps_id
);
185 logerrx("%s: IN cmd %x, psp %p", __func__
, psm
->ps_cmd
, psp
);
190 case PS_BPF_ARP
: /* FALLTHROUGH */
195 logerrx("%s: unknown command %x", __func__
, psm
->ps_cmd
);
200 if (!(psm
->ps_cmd
& PS_START
)) {
208 psp
= ps_newprocess(ctx
, &psm
->ps_id
);
213 assert(msg
->msg_iovlen
== 1);
214 assert(iov
->iov_len
== sizeof(*ifp
));
215 memcpy(ifp
, iov
->iov_base
, sizeof(*ifp
));
216 ifp
->ctx
= psp
->psp_ctx
;
218 memset(ifp
->if_data
, 0, sizeof(ifp
->if_data
));
220 memcpy(psp
->psp_ifname
, ifp
->name
, sizeof(psp
->psp_ifname
));
225 psp
->psp_proto
= ETHERTYPE_ARP
;
226 psp
->psp_protostr
= "ARP";
227 psp
->psp_filter
= bpf_arp
;
231 psp
->psp_proto
= ETHERTYPE_IP
;
232 psp
->psp_protostr
= "BOOTP";
233 psp
->psp_filter
= bpf_bootp
;
237 start
= ps_dostart(ctx
,
238 &psp
->psp_pid
, &psp
->psp_fd
,
239 ps_bpf_recvmsg
, NULL
, psp
,
240 ps_bpf_start_bpf
, NULL
,
248 if (cap_enter() == -1 && errno
!= ENOSYS
)
249 logerr("%s: cap_enter", __func__
);
252 if (pledge("stdio", NULL
) == -1)
253 logerr("%s: pledge", __func__
);
258 logdebugx("%s: spawned BPF %s on PID %d",
259 psp
->psp_ifname
, psp
->psp_protostr
, start
);
267 ps_bpf_dispatch(struct dhcpcd_ctx
*ctx
,
268 struct ps_msghdr
*psm
, struct msghdr
*msg
)
270 struct iovec
*iov
= msg
->msg_iov
;
271 struct interface
*ifp
;
275 ifp
= if_findindex(ctx
->ifaces
, psm
->ps_id
.psi_ifindex
);
277 bpf_len
= iov
->iov_len
;
279 switch (psm
->ps_cmd
) {
282 arp_packet(ifp
, bpf
, bpf_len
, (unsigned int)psm
->ps_flags
);
286 dhcp_packet(ifp
, bpf
, bpf_len
, (unsigned int)psm
->ps_flags
);
297 ps_bpf_send(const struct interface
*ifp
, const struct in_addr
*ia
,
298 uint16_t cmd
, const void *data
, size_t len
)
300 struct dhcpcd_ctx
*ctx
= ifp
->ctx
;
301 struct ps_msghdr psm
= {
304 .psi_ifindex
= ifp
->index
,
305 .psi_cmd
= (uint8_t)(cmd
& ~(PS_START
| PS_STOP
)),
310 psm
.ps_id
.psi_addr
.psa_in_addr
= *ia
;
312 return ps_sendpsmdata(ctx
, ctx
->ps_root_fd
, &psm
, data
, len
);
317 ps_bpf_openarp(const struct interface
*ifp
, const struct in_addr
*ia
)
321 return ps_bpf_send(ifp
, ia
, PS_BPF_ARP
| PS_START
,
326 ps_bpf_closearp(const struct interface
*ifp
, const struct in_addr
*ia
)
329 return ps_bpf_send(ifp
, ia
, PS_BPF_ARP
| PS_STOP
, NULL
, 0);
333 ps_bpf_sendarp(const struct interface
*ifp
, const struct in_addr
*ia
,
334 const void *data
, size_t len
)
338 return ps_bpf_send(ifp
, ia
, PS_BPF_ARP
, data
, len
);
343 ps_bpf_openbootp(const struct interface
*ifp
)
346 return ps_bpf_send(ifp
, NULL
, PS_BPF_BOOTP
| PS_START
,
351 ps_bpf_closebootp(const struct interface
*ifp
)
354 return ps_bpf_send(ifp
, NULL
, PS_BPF_BOOTP
| PS_STOP
, NULL
, 0);
358 ps_bpf_sendbootp(const struct interface
*ifp
, const void *data
, size_t len
)
361 return ps_bpf_send(ifp
, NULL
, PS_BPF_BOOTP
, data
, len
);