1 /* $NetBSD: t_bpfilter.c,v 1.10 2015/02/11 23:39:07 alnsn Exp $ */
4 * Copyright (c) 2012 The NetBSD Foundation, Inc.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
16 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 #include <sys/cdefs.h>
28 __RCSID("$NetBSD: t_bpfilter.c,v 1.10 2015/02/11 23:39:07 alnsn Exp $");
30 #include <sys/param.h>
31 #include <sys/ioctl.h>
32 #include <sys/socket.h>
34 #include <sys/sysctl.h>
40 #include <net/if_ether.h>
48 #include <rump/rump.h>
49 #include <rump/rump_syscalls.h>
51 /* XXX: atf-c.h has collisions with mbuf */
56 #include "../../h_macros.h"
57 #include "../config/netconfig.c"
60 #define SNAPLEN UINT32_MAX
62 #define BMAGIC UINT32_C(0x37)
63 #define HMAGIC UINT32_C(0xc2c2)
64 #define WMAGIC UINT32_C(0x7d7d7d7d)
66 static const char magic_echo_reply_tail
[7] = {
77 * Match ICMP_ECHOREPLY packet with 7 magic bytes at the end.
79 static struct bpf_insn magic_echo_reply_prog
[] = {
80 BPF_STMT(BPF_LD
+BPF_ABS
+BPF_B
,
81 sizeof(struct ip
) + offsetof(struct icmp
, icmp_type
)),
82 BPF_JUMP(BPF_JMP
+BPF_JEQ
+BPF_K
, ICMP_ECHOREPLY
, 1, 0),
83 BPF_STMT(BPF_RET
+BPF_K
, 0),
85 BPF_STMT(BPF_LD
+BPF_W
+BPF_LEN
, 0), /* A <- len */
86 BPF_STMT(BPF_ALU
+BPF_SUB
+BPF_K
, 7), /* A <- A - 7 */
87 BPF_STMT(BPF_MISC
+BPF_TAX
, 0), /* X <- A */
89 BPF_STMT(BPF_LD
+BPF_IND
+BPF_B
, 0),
90 BPF_JUMP(BPF_JMP
+BPF_JEQ
+BPF_K
, BMAGIC
, 1, 0),
91 BPF_STMT(BPF_RET
+BPF_K
, 0),
93 BPF_STMT(BPF_LD
+BPF_IND
+BPF_H
, 1),
94 BPF_JUMP(BPF_JMP
+BPF_JEQ
+BPF_K
, HMAGIC
, 1, 0),
95 BPF_STMT(BPF_RET
+BPF_K
, 0),
97 BPF_STMT(BPF_LD
+BPF_IND
+BPF_W
, 3),
98 BPF_JUMP(BPF_JMP
+BPF_JEQ
+BPF_K
, WMAGIC
, 1, 0),
99 BPF_STMT(BPF_RET
+BPF_K
, 0),
101 BPF_STMT(BPF_RET
+BPF_K
, SNAPLEN
)
104 static struct bpf_insn badmem_prog
[] = {
105 BPF_STMT(BPF_LD
+BPF_MEM
, 5),
106 BPF_STMT(BPF_RET
+BPF_A
, 0),
109 static struct bpf_insn noinitA_prog
[] = {
110 BPF_STMT(BPF_RET
+BPF_A
, 0),
113 static struct bpf_insn noinitX_prog
[] = {
114 BPF_STMT(BPF_MISC
+BPF_TXA
, 0),
115 BPF_STMT(BPF_RET
+BPF_A
, 0),
118 static struct bpf_insn badjmp_prog
[] = {
119 BPF_STMT(BPF_JMP
+BPF_JA
, 5),
120 BPF_STMT(BPF_RET
+BPF_A
, 0),
123 static struct bpf_insn negjmp_prog
[] = {
124 BPF_STMT(BPF_JMP
+BPF_JA
, 0),
125 BPF_STMT(BPF_JMP
+BPF_JA
, UINT32_MAX
- 1), // -2
126 BPF_STMT(BPF_RET
+BPF_A
, 0),
129 static struct bpf_insn badret_prog
[] = {
130 BPF_STMT(BPF_RET
+BPF_A
+0x8000, 0),
134 in_cksum(void *data
, size_t len
)
136 uint16_t *buf
= data
;
139 for (sum
= 0; len
> 1; len
-= 2)
142 sum
+= *(uint8_t *)buf
;
144 sum
= (sum
>> 16) + (sum
& 0xffff);
151 * Based on netcfg_rump_pingtest().
154 pingtest(const char *dst
, unsigned int wirelen
, const char tail
[7])
157 struct sockaddr_in sin
;
160 unsigned int pktsize
;
165 if (wirelen
< ETHER_HDR_LEN
+ sizeof(struct ip
))
168 pktsize
= wirelen
- ETHER_HDR_LEN
- sizeof(struct ip
);
169 if (pktsize
< sizeof(struct icmp
) + 7)
172 s
= rump_sys_socket(PF_INET
, SOCK_RAW
, IPPROTO_ICMP
);
180 if (rump_sys_setsockopt(s
, SOL_SOCKET
, SO_RCVTIMEO
,
181 &tv
, sizeof(tv
)) == -1)
184 memset(&sin
, 0, sizeof(sin
));
185 sin
.sin_len
= sizeof(sin
);
186 sin
.sin_family
= AF_INET
;
187 sin
.sin_addr
.s_addr
= inet_addr(dst
);
189 pkt
= calloc(1, pktsize
);
190 icmp
= (struct icmp
*)pkt
;
194 memcpy(pkt
+ pktsize
- 7, tail
, 7);
195 icmp
->icmp_type
= ICMP_ECHO
;
196 icmp
->icmp_id
= htons(37);
197 icmp
->icmp_seq
= htons(1);
198 icmp
->icmp_cksum
= in_cksum(pkt
, pktsize
);
201 if (rump_sys_sendto(s
, pkt
, pktsize
, 0,
202 (struct sockaddr
*)&sin
, slen
) == -1) {
206 if (rump_sys_recvfrom(s
, pkt
, pktsize
, 0,
207 (struct sockaddr
*)&sin
, &slen
) == -1)
219 magic_ping_test(const char *name
, unsigned int wirelen
)
221 struct bpf_program prog
;
222 struct bpf_stat bstat
;
225 unsigned int bufsize
;
238 prog
.bf_len
= __arraycount(magic_echo_reply_prog
);
239 prog
.bf_insns
= magic_echo_reply_prog
;
243 netcfg_rump_makeshmif(name
, ifr
.ifr_name
);
247 atf_tc_fail_errno("fork failed");
249 netcfg_rump_if(ifr
.ifr_name
, "10.1.1.10", "255.0.0.0");
251 ATF_CHECK(write(channel
[1], "U", 1) == 1);
259 netcfg_rump_if(ifr
.ifr_name
, "10.1.1.20", "255.0.0.0");
261 RL(bpfd
= rump_sys_open("/dev/bpf", O_RDONLY
));
265 RL(rump_sys_ioctl(bpfd
, BIOCSRTIMEOUT
, &tv
));
267 RL(rump_sys_ioctl(bpfd
, BIOCGBLEN
, &bufsize
));
268 RL(rump_sys_ioctl(bpfd
, BIOCSETF
, &prog
));
269 RL(rump_sys_ioctl(bpfd
, BIOCSETIF
, &ifr
));
272 ATF_CHECK(read(channel
[0], &token
, 1) == 1 && token
== 'U');
274 pinged
= pingtest("10.1.1.10", wirelen
, magic_echo_reply_tail
);
277 buf
= malloc(bufsize
);
278 hdr
= (struct bpf_hdr
*)buf
;
279 ATF_REQUIRE(buf
!= NULL
);
280 ATF_REQUIRE(bufsize
> sizeof(struct bpf_hdr
));
282 n
= rump_sys_read(bpfd
, buf
, bufsize
);
284 ATF_CHECK(n
> (int)sizeof(struct bpf_hdr
));
285 ATF_CHECK(hdr
->bh_caplen
== MIN(SNAPLEN
, wirelen
));
287 RL(rump_sys_ioctl(bpfd
, BIOCGSTATS
, &bstat
));
288 ATF_CHECK(bstat
.bs_capt
>= 1); /* XXX == 1 */
290 rump_sys_close(bpfd
);
295 kill(child
, SIGKILL
);
299 send_bpf_prog(const char *ifname
, struct bpf_program
*prog
)
305 netcfg_rump_makeshmif(ifname
, ifr
.ifr_name
);
306 netcfg_rump_if(ifr
.ifr_name
, "10.1.1.20", "255.0.0.0");
308 RL(bpfd
= rump_sys_open("/dev/bpf", O_RDONLY
));
310 rv
= rump_sys_ioctl(bpfd
, BIOCSETF
, prog
);
313 rump_sys_close(bpfd
);
319 ATF_TC(bpfiltercontig
);
320 ATF_TC_HEAD(bpfiltercontig
, tc
)
323 atf_tc_set_md_var(tc
, "descr", "Checks that bpf program "
324 "can read bytes from contiguous buffer.");
325 atf_tc_set_md_var(tc
, "timeout", "30");
328 ATF_TC_BODY(bpfiltercontig
, tc
)
331 magic_ping_test("bpfiltercontig", 128);
335 ATF_TC(bpfiltermchain
);
336 ATF_TC_HEAD(bpfiltermchain
, tc
)
339 atf_tc_set_md_var(tc
, "descr", "Checks that bpf program "
340 "can read bytes from mbuf chain.");
341 atf_tc_set_md_var(tc
, "timeout", "30");
344 ATF_TC_BODY(bpfiltermchain
, tc
)
347 magic_ping_test("bpfiltermchain", MINCLSIZE
+ 1);
351 ATF_TC(bpfilterbadmem
);
352 ATF_TC_HEAD(bpfilterbadmem
, tc
)
355 atf_tc_set_md_var(tc
, "descr", "Checks that bpf program that "
356 "doesn't initialize memomy store is rejected by the kernel");
357 atf_tc_set_md_var(tc
, "timeout", "30");
360 ATF_TC_BODY(bpfilterbadmem
, tc
)
362 struct bpf_program prog
;
364 prog
.bf_len
= __arraycount(badmem_prog
);
365 prog
.bf_insns
= badmem_prog
;
366 ATF_CHECK_ERRNO(EINVAL
, send_bpf_prog("bpfilterbadmem", &prog
) == -1);
369 ATF_TC(bpfilternoinitA
);
370 ATF_TC_HEAD(bpfilternoinitA
, tc
)
373 atf_tc_set_md_var(tc
, "descr", "Checks that bpf program that "
374 "doesn't initialize the A register is accepted by the kernel");
375 atf_tc_set_md_var(tc
, "timeout", "30");
378 ATF_TC_BODY(bpfilternoinitA
, tc
)
380 struct bpf_program prog
;
382 prog
.bf_len
= __arraycount(noinitA_prog
);
383 prog
.bf_insns
= noinitA_prog
;
384 RL(send_bpf_prog("bpfilternoinitA", &prog
));
387 ATF_TC(bpfilternoinitX
);
388 ATF_TC_HEAD(bpfilternoinitX
, tc
)
391 atf_tc_set_md_var(tc
, "descr", "Checks that bpf program that "
392 "doesn't initialize the X register is accepted by the kernel");
393 atf_tc_set_md_var(tc
, "timeout", "30");
396 ATF_TC_BODY(bpfilternoinitX
, tc
)
398 struct bpf_program prog
;
400 prog
.bf_len
= __arraycount(noinitX_prog
);
401 prog
.bf_insns
= noinitX_prog
;
402 RL(send_bpf_prog("bpfilternoinitX", &prog
));
405 ATF_TC(bpfilterbadjmp
);
406 ATF_TC_HEAD(bpfilterbadjmp
, tc
)
409 atf_tc_set_md_var(tc
, "descr", "Checks that bpf program that "
410 "jumps to invalid destination is rejected by the kernel");
411 atf_tc_set_md_var(tc
, "timeout", "30");
414 ATF_TC_BODY(bpfilterbadjmp
, tc
)
416 struct bpf_program prog
;
418 prog
.bf_len
= __arraycount(badjmp_prog
);
419 prog
.bf_insns
= badjmp_prog
;
420 ATF_CHECK_ERRNO(EINVAL
, send_bpf_prog("bpfilterbadjmp", &prog
) == -1);
423 ATF_TC(bpfilternegjmp
);
424 ATF_TC_HEAD(bpfilternegjmp
, tc
)
427 atf_tc_set_md_var(tc
, "descr", "Checks that bpf program that "
428 "jumps backwards is rejected by the kernel");
429 atf_tc_set_md_var(tc
, "timeout", "30");
432 ATF_TC_BODY(bpfilternegjmp
, tc
)
434 struct bpf_program prog
;
436 prog
.bf_len
= __arraycount(negjmp_prog
);
437 prog
.bf_insns
= negjmp_prog
;
438 ATF_CHECK_ERRNO(EINVAL
, send_bpf_prog("bpfilternegjmp", &prog
) == -1);
441 ATF_TC(bpfilterbadret
);
442 ATF_TC_HEAD(bpfilterbadret
, tc
)
445 atf_tc_set_md_var(tc
, "descr", "Checks that bpf program that "
446 "ends with invalid BPF_RET instruction is rejected by the kernel");
447 atf_tc_set_md_var(tc
, "timeout", "30");
450 ATF_TC_BODY(bpfilterbadret
, tc
)
452 struct bpf_program prog
;
453 struct bpf_insn
*last
;
455 prog
.bf_len
= __arraycount(badret_prog
);
456 prog
.bf_insns
= badret_prog
;
459 * The point of this test is checking a bad instruction of
460 * a valid class and with a valid BPF_RVAL data.
462 last
= &prog
.bf_insns
[prog
.bf_len
- 1];
463 ATF_CHECK(BPF_CLASS(last
->code
) == BPF_RET
&&
464 (BPF_RVAL(last
->code
) == BPF_K
|| BPF_RVAL(last
->code
) == BPF_A
));
466 ATF_CHECK_ERRNO(EINVAL
, send_bpf_prog("bpfilterbadret", &prog
) == -1);
472 ATF_TP_ADD_TC(tp
, bpfiltercontig
);
473 ATF_TP_ADD_TC(tp
, bpfiltermchain
);
474 ATF_TP_ADD_TC(tp
, bpfilterbadmem
);
475 ATF_TP_ADD_TC(tp
, bpfilternoinitA
);
476 ATF_TP_ADD_TC(tp
, bpfilternoinitX
);
477 ATF_TP_ADD_TC(tp
, bpfilterbadjmp
);
478 ATF_TP_ADD_TC(tp
, bpfilternegjmp
);
479 ATF_TP_ADD_TC(tp
, bpfilterbadret
);
481 return atf_no_error();