]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - tools/regression/bpf/bpf_filter/bpf_test.c
Merge ntpd & friends 4.2.4p5 from vendor/ntp/dist into head. Next commit
[FreeBSD/FreeBSD.git] / tools / regression / bpf / bpf_filter / bpf_test.c
1 /*-
2  * Copyright (C) 2008 Jung-uk Kim <jkim@FreeBSD.org>. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23  * SUCH DAMAGE.
24  */
25
26 #include <sys/cdefs.h>
27 __FBSDID("$FreeBSD$");
28
29 #include <signal.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32
33 #include <sys/types.h>
34
35 #include <net/bpf.h>
36
37 #include BPF_TEST_H
38
39 #define PASSED          0
40 #define FAILED          1
41 #define FATAL           -1
42
43 #ifndef LOG_LEVEL
44 #define LOG_LEVEL       1
45 #endif
46
47 static void     sig_handler(int);
48
49 static int      nins = sizeof(pc) / sizeof(pc[0]);
50 static int      verbose = LOG_LEVEL;
51
52 #ifdef BPF_JIT_COMPILER
53
54 #include <string.h>
55
56 #include <net/bpf_jitter.h>
57
58 bpf_filter_func bpf_jit_compile(struct bpf_insn *, u_int, int *);
59
60 static u_int
61 bpf_compile_and_filter(void)
62 {
63         bpf_jit_filter  filter;
64         u_int           ret;
65
66         /* Do not use BPF JIT compiler for an empty program */
67         if (nins == 0)
68                 return (0);
69
70         /* Allocate the filter's memory */
71         if ((filter.mem = (int *)malloc(BPF_MEMWORDS * sizeof(int))) == NULL)
72                 goto fail;
73
74         /* Create the binary */
75         if ((filter.func = bpf_jit_compile(pc, nins, filter.mem)) == NULL)
76                 goto fail;
77
78         ret = (*(filter.func))(pkt, wirelen, buflen);
79
80         free(filter.mem);
81         free(filter.func);
82
83         return (ret);
84
85 fail:
86         if (filter.mem != NULL)
87                 free(filter.mem);
88
89         if (verbose > 1)
90                 printf("Failed to allocate memory:\t");
91         if (verbose > 0)
92                 printf("FATAL\n");
93         exit(FATAL);
94 }
95
96 #else
97
98 u_int           bpf_filter(struct bpf_insn *, u_char *, u_int, u_int);
99
100 #endif
101
102 #ifdef BPF_VALIDATE
103 /*
104  * XXX Copied from sys/net/bpf_filter.c and modified.
105  *
106  * Return true if the 'fcode' is a valid filter program.
107  * The constraints are that each jump be forward and to a valid
108  * code.  The code must terminate with either an accept or reject.
109  *
110  * The kernel needs to be able to verify an application's filter code.
111  * Otherwise, a bogus program could easily crash the system.
112  */
113 static int
114 bpf_validate(const struct bpf_insn *f, int len)
115 {
116         register int i;
117         register const struct bpf_insn *p;
118
119         /* Do not accept negative length filter. */
120         if (len < 0)
121                 return (0);
122
123         /* An empty filter means accept all. */
124         if (len == 0)
125                 return (1);
126
127         for (i = 0; i < len; ++i) {
128                 /*
129                  * Check that that jumps are forward, and within
130                  * the code block.
131                  */
132                 p = &f[i];
133                 if (BPF_CLASS(p->code) == BPF_JMP) {
134                         register int from = i + 1;
135
136                         if (BPF_OP(p->code) == BPF_JA) {
137                                 if (from >= len || p->k >= (u_int)len - from)
138                                         return (0);
139                         }
140                         else if (from >= len || p->jt >= len - from ||
141                                  p->jf >= len - from)
142                                 return (0);
143                 }
144                 /*
145                  * Check that memory operations use valid addresses.
146                  */
147                 if ((BPF_CLASS(p->code) == BPF_ST ||
148                      (BPF_CLASS(p->code) == BPF_LD &&
149                       (p->code & 0xe0) == BPF_MEM)) &&
150                     p->k >= BPF_MEMWORDS)
151                         return (0);
152                 /*
153                  * Check for constant division by 0.
154                  */
155                 if (p->code == (BPF_ALU|BPF_DIV|BPF_K) && p->k == 0)
156                         return (0);
157         }
158         return (BPF_CLASS(f[len - 1].code) == BPF_RET);
159 }
160 #endif
161
162 int
163 main(void)
164 {
165         u_int   ret;
166         int     sig;
167 #ifdef BPF_VALIDATE
168         int     valid;
169 #endif
170
171         /* Try to catch all signals */
172         for (sig = SIGHUP; sig <= SIGUSR2; sig++)
173                 signal(sig, sig_handler);
174
175 #ifdef BPF_VALIDATE
176         valid = bpf_validate(pc, nins);
177         if (valid != 0 && invalid != 0) {
178                 if (verbose > 1)
179                         printf("Validated invalid instructions:\t");
180                 if (verbose > 0)
181                         printf("FAILED\n");
182                 return (FAILED);
183         } else if (valid == 0 && invalid == 0) {
184                 if (verbose > 1)
185                         printf("Invalidated valid instructions:\t");
186                 if (verbose > 0)
187                         printf("FAILED\n");
188                 return (FAILED);
189         }
190 #endif
191
192 #ifdef BPF_JIT_COMPILER
193         ret = bpf_compile_and_filter();
194 #else
195         ret = bpf_filter(pc, pkt, wirelen, buflen);
196 #endif
197         if (ret != expect) {
198                 if (verbose > 1)
199                         printf("Expected 0x%x but got 0x%x:\t", expect, ret);
200                 if (verbose > 0)
201                         printf("FAILED\n");
202                 return (FAILED);
203         }
204         if (verbose > 1)
205                 printf("Expected and got 0x%x:\t", ret);
206         if (verbose > 0)
207                 printf("PASSED\n");
208
209         return (PASSED);
210 }
211
212 static void
213 sig_handler(int sig)
214 {
215
216         if (expect_signal == 0) {
217                 if (verbose > 1)
218                         printf("Received unexpected signal %d:\t", sig);
219                 if (verbose > 0)
220                         printf("FATAL\n");
221                 exit(FATAL);
222         }
223         if (expect_signal != sig) {
224                 if (verbose > 1)
225                         printf("Expected signal %d but got %d:\t",
226                             expect_signal, sig);
227                 if (verbose > 0)
228                         printf("FAILED\n");
229                 exit(FAILED);
230         }
231
232         if (verbose > 1)
233                 printf("Expected and got signal %d:\t", sig);
234         if (verbose > 0)
235                 printf("PASSED\n");
236
237         exit(PASSED);
238 }