bpf_test.c revision 182175
1240616Sjimharris/*-
2240616Sjimharris * Copyright (C) 2008 Jung-uk Kim <jkim@FreeBSD.org>. All rights reserved.
3240616Sjimharris *
4240616Sjimharris * Redistribution and use in source and binary forms, with or without
5240616Sjimharris * modification, are permitted provided that the following conditions
6240616Sjimharris * are met:
7240616Sjimharris * 1. Redistributions of source code must retain the above copyright
8240616Sjimharris *    notice, this list of conditions and the following disclaimer.
9240616Sjimharris * 2. Redistributions in binary form must reproduce the above copyright
10240616Sjimharris *    notice, this list of conditions and the following disclaimer in the
11240616Sjimharris *    documentation and/or other materials provided with the distribution.
12240616Sjimharris *
13240616Sjimharris * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14240616Sjimharris * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15240616Sjimharris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16240616Sjimharris * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
17240616Sjimharris * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18240616Sjimharris * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19240616Sjimharris * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20240616Sjimharris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21240616Sjimharris * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22240616Sjimharris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23240616Sjimharris * SUCH DAMAGE.
24240616Sjimharris */
25240616Sjimharris
26240616Sjimharris#include <sys/cdefs.h>
27240616Sjimharris__FBSDID("$FreeBSD: head/tools/regression/bpf/bpf_filter/bpf_test.c 182175 2008-08-25 21:33:12Z jkim $");
28240616Sjimharris
29240616Sjimharris#include <signal.h>
30240616Sjimharris#include <stdio.h>
31240616Sjimharris#include <stdlib.h>
32240616Sjimharris
33240616Sjimharris#include <sys/types.h>
34240616Sjimharris
35240616Sjimharris#include <net/bpf.h>
36240616Sjimharris
37240616Sjimharris#include BPF_TEST_H
38240616Sjimharris
39240616Sjimharris#define	PASSED		0
40240616Sjimharris#define	FAILED		1
41240616Sjimharris#define	FATAL		-1
42240616Sjimharris
43240616Sjimharris#ifndef LOG_LEVEL
44240616Sjimharris#define	LOG_LEVEL	1
45240616Sjimharris#endif
46240616Sjimharris
47240616Sjimharrisstatic void	sig_handler(int);
48240616Sjimharris
49240616Sjimharrisstatic int	nins = sizeof(pc) / sizeof(pc[0]);
50240616Sjimharrisstatic int	verbose = LOG_LEVEL;
51240616Sjimharris
52240616Sjimharris#ifdef BPF_JIT_COMPILER
53240616Sjimharris
54240616Sjimharris#include <string.h>
55240616Sjimharris
56240616Sjimharris#include <net/bpf_jitter.h>
57240616Sjimharris
58240616Sjimharrisbpf_filter_func	bpf_jit_compile(struct bpf_insn *, u_int, int *);
59240616Sjimharris
60240616Sjimharrisstatic u_int
61240616Sjimharrisbpf_compile_and_filter(void)
62240616Sjimharris{
63240616Sjimharris	bpf_jit_filter	filter;
64240616Sjimharris	u_int		ret;
65240616Sjimharris
66240616Sjimharris	/* Do not use BPF JIT compiler for an empty program */
67240616Sjimharris	if (nins == 0)
68240616Sjimharris		return (0);
69240616Sjimharris
70240616Sjimharris	/* Create the binary */
71240616Sjimharris	if ((filter.func = bpf_jit_compile(pc, nins, filter.mem)) == NULL) {
72240616Sjimharris		if (verbose > 1)
73240616Sjimharris			printf("Failed to allocate memory:\t");
74240616Sjimharris		if (verbose > 0)
75240616Sjimharris			printf("FATAL\n");
76240616Sjimharris		exit(FATAL);
77240616Sjimharris	}
78240616Sjimharris
79240616Sjimharris	ret = (*(filter.func))(pkt, wirelen, buflen);
80240616Sjimharris
81240616Sjimharris	free(filter.func);
82240616Sjimharris
83240616Sjimharris	return (ret);
84240616Sjimharris}
85240616Sjimharris
86240616Sjimharris#else
87240616Sjimharris
88240616Sjimharrisu_int		bpf_filter(struct bpf_insn *, u_char *, u_int, u_int);
89240616Sjimharris
90240616Sjimharris#endif
91240616Sjimharris
92240616Sjimharris#ifdef BPF_VALIDATE
93240616Sjimharris/*
94240616Sjimharris * XXX Copied from sys/net/bpf_filter.c and modified.
95240616Sjimharris *
96240616Sjimharris * Return true if the 'fcode' is a valid filter program.
97240616Sjimharris * The constraints are that each jump be forward and to a valid
98240616Sjimharris * code.  The code must terminate with either an accept or reject.
99240616Sjimharris *
100240616Sjimharris * The kernel needs to be able to verify an application's filter code.
101240616Sjimharris * Otherwise, a bogus program could easily crash the system.
102240616Sjimharris */
103240616Sjimharrisstatic int
104240616Sjimharrisbpf_validate(const struct bpf_insn *f, int len)
105240616Sjimharris{
106240616Sjimharris	register int i;
107240616Sjimharris	register const struct bpf_insn *p;
108240616Sjimharris
109240616Sjimharris	/* Do not accept negative length filter. */
110240616Sjimharris	if (len < 0)
111240616Sjimharris		return (0);
112240616Sjimharris
113240616Sjimharris	/* An empty filter means accept all. */
114240616Sjimharris	if (len == 0)
115240616Sjimharris		return (1);
116240616Sjimharris
117240616Sjimharris	for (i = 0; i < len; ++i) {
118240616Sjimharris		/*
119240616Sjimharris		 * Check that that jumps are forward, and within
120240616Sjimharris		 * the code block.
121		 */
122		p = &f[i];
123		if (BPF_CLASS(p->code) == BPF_JMP) {
124			register int from = i + 1;
125
126			if (BPF_OP(p->code) == BPF_JA) {
127				if (from >= len || p->k >= (u_int)len - from)
128					return (0);
129			}
130			else if (from >= len || p->jt >= len - from ||
131				 p->jf >= len - from)
132				return (0);
133		}
134		/*
135		 * Check that memory operations use valid addresses.
136		 */
137		if ((BPF_CLASS(p->code) == BPF_ST ||
138		     (BPF_CLASS(p->code) == BPF_LD &&
139		      (p->code & 0xe0) == BPF_MEM)) &&
140		    p->k >= BPF_MEMWORDS)
141			return (0);
142		/*
143		 * Check for constant division by 0.
144		 */
145		if (p->code == (BPF_ALU|BPF_DIV|BPF_K) && p->k == 0)
146			return (0);
147	}
148	return (BPF_CLASS(f[len - 1].code) == BPF_RET);
149}
150#endif
151
152int
153main(void)
154{
155	u_int   ret;
156	int     sig;
157#ifdef BPF_VALIDATE
158	int	valid;
159#endif
160
161	/* Try to catch all signals */
162	for (sig = SIGHUP; sig <= SIGUSR2; sig++)
163		signal(sig, sig_handler);
164
165#ifdef BPF_VALIDATE
166	valid = bpf_validate(pc, nins);
167	if (valid != 0 && invalid != 0) {
168		if (verbose > 1)
169			printf("Validated invalid instructions:\t");
170		if (verbose > 0)
171			printf("FAILED\n");
172		return (FAILED);
173	} else if (valid == 0 && invalid == 0) {
174		if (verbose > 1)
175			printf("Invalidated valid instructions:\t");
176		if (verbose > 0)
177			printf("FAILED\n");
178		return (FAILED);
179	}
180#endif
181
182#ifdef BPF_JIT_COMPILER
183	ret = bpf_compile_and_filter();
184#else
185	ret = bpf_filter(pc, pkt, wirelen, buflen);
186#endif
187	if (ret != expect) {
188		if (verbose > 1)
189			printf("Expected 0x%x but got 0x%x:\t", expect, ret);
190		if (verbose > 0)
191			printf("FAILED\n");
192		return (FAILED);
193	}
194	if (verbose > 1)
195		printf("Expected and got 0x%x:\t", ret);
196	if (verbose > 0)
197		printf("PASSED\n");
198
199	return (PASSED);
200}
201
202static void
203sig_handler(int sig)
204{
205
206	if (expect_signal == 0) {
207		if (verbose > 1)
208			printf("Received unexpected signal %d:\t", sig);
209		if (verbose > 0)
210			printf("FATAL\n");
211		exit(FATAL);
212	}
213	if (expect_signal != sig) {
214		if (verbose > 1)
215			printf("Expected signal %d but got %d:\t",
216			    expect_signal, sig);
217		if (verbose > 0)
218			printf("FAILED\n");
219		exit(FAILED);
220	}
221
222	if (verbose > 1)
223		printf("Expected and got signal %d:\t", sig);
224	if (verbose > 0)
225		printf("PASSED\n");
226
227	exit(PASSED);
228}
229