Commit | Line | Data |
---|---|---|
b688fc87 | 1 | /*- |
3a1876f4 | 2 | * Copyright (c) 1990-1991 The Regents of the University of California. |
b688fc87 WJ |
3 | * All rights reserved. |
4 | * | |
5 | * This code is derived from the Stanford/CMU enet packet filter, | |
6 | * (net/enet.c) distributed as part of 4.3BSD, and code contributed | |
3a1876f4 DG |
7 | * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence |
8 | * Berkeley Laboratory. | |
b688fc87 WJ |
9 | * |
10 | * Redistribution and use in source and binary forms, with or without | |
11 | * modification, are permitted provided that the following conditions | |
12 | * are met: | |
13 | * 1. Redistributions of source code must retain the above copyright | |
14 | * notice, this list of conditions and the following disclaimer. | |
15 | * 2. Redistributions in binary form must reproduce the above copyright | |
16 | * notice, this list of conditions and the following disclaimer in the | |
17 | * documentation and/or other materials provided with the distribution. | |
18 | * 3. All advertising materials mentioning features or use of this software | |
19 | * must display the following acknowledgement: | |
20 | * This product includes software developed by the University of | |
21 | * California, Berkeley and its contributors. | |
22 | * 4. Neither the name of the University nor the names of its contributors | |
23 | * may be used to endorse or promote products derived from this software | |
24 | * without specific prior written permission. | |
25 | * | |
26 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
27 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
28 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
29 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
30 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
31 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
32 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
33 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
34 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
35 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
36 | * SUCH DAMAGE. | |
37 | * | |
3a1876f4 | 38 | * @(#)bpf.c 7.5 (Berkeley) 7/15/91 |
b688fc87 WJ |
39 | * |
40 | * static char rcsid[] = | |
3a1876f4 DG |
41 | * "$Header: bpf_filter.c,v 1.20 92/04/06 10:43:03 mccanne Exp $"; |
42 | * | |
43 | * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE | |
44 | * -------------------- ----- ---------------------- | |
45 | * CURRENT PATCH LEVEL: 1 00112 | |
46 | * -------------------- ----- ---------------------- | |
47 | * | |
48 | * 14 Mar 93 David Greenman Upgrade bpf to match tcpdump 2.2.1 | |
b688fc87 | 49 | */ |
3a1876f4 DG |
50 | #if !(defined(lint) || defined(KERNEL)) |
51 | static char rcsid[] = | |
52 | "@(#) $Header: bpf_filter.c,v 1.20 92/04/06 10:43:03 mccanne Exp $ (LBL)"; | |
53 | #endif | |
b688fc87 WJ |
54 | |
55 | #include <sys/param.h> | |
56 | #include <sys/types.h> | |
57 | #include <sys/time.h> | |
58 | #include <net/bpf.h> | |
59 | ||
60 | #ifdef sun | |
61 | #include <netinet/in.h> | |
62 | #endif | |
63 | ||
3a1876f4 DG |
64 | #if defined(sparc) || defined(mips) || defined(ibm032) |
65 | #define BPF_ALIGN | |
b688fc87 WJ |
66 | #endif |
67 | ||
3a1876f4 DG |
68 | #ifndef BPF_ALIGN |
69 | #define EXTRACT_SHORT(p) ((u_short)ntohs(*(u_short *)p)) | |
b688fc87 WJ |
70 | #define EXTRACT_LONG(p) (ntohl(*(u_long *)p)) |
71 | #else | |
72 | #define EXTRACT_SHORT(p)\ | |
73 | ((u_short)\ | |
3a1876f4 DG |
74 | ((u_short)*((u_char *)p+0)<<8|\ |
75 | (u_short)*((u_char *)p+1)<<0)) | |
b688fc87 | 76 | #define EXTRACT_LONG(p)\ |
3a1876f4 DG |
77 | ((u_long)*((u_char *)p+0)<<24|\ |
78 | (u_long)*((u_char *)p+1)<<16|\ | |
79 | (u_long)*((u_char *)p+2)<<8|\ | |
80 | (u_long)*((u_char *)p+3)<<0) | |
b688fc87 WJ |
81 | #endif |
82 | ||
83 | #ifdef KERNEL | |
84 | #include <sys/mbuf.h> | |
85 | #define MINDEX(m, k) \ | |
86 | { \ | |
87 | register int len = m->m_len; \ | |
88 | \ | |
89 | while (k >= len) { \ | |
90 | k -= len; \ | |
91 | m = m->m_next; \ | |
92 | if (m == 0) \ | |
93 | return 0; \ | |
94 | len = m->m_len; \ | |
95 | } \ | |
96 | } | |
97 | ||
98 | static int | |
99 | m_xword(m, k, err) | |
100 | register struct mbuf *m; | |
101 | register int k, *err; | |
102 | { | |
103 | register int len; | |
104 | register u_char *cp, *np; | |
105 | register struct mbuf *m0; | |
106 | ||
107 | len = m->m_len; | |
108 | while (k >= len) { | |
109 | k -= len; | |
110 | m = m->m_next; | |
111 | if (m == 0) | |
112 | goto bad; | |
113 | len = m->m_len; | |
114 | } | |
115 | cp = mtod(m, u_char *) + k; | |
116 | if (len - k >= 4) { | |
117 | *err = 0; | |
118 | return EXTRACT_LONG(cp); | |
119 | } | |
120 | m0 = m->m_next; | |
121 | if (m0 == 0 || m0->m_len + len - k < 4) | |
122 | goto bad; | |
123 | *err = 0; | |
124 | np = mtod(m0, u_char *); | |
125 | switch (len - k) { | |
126 | ||
127 | case 1: | |
128 | return (cp[k] << 24) | (np[0] << 16) | (np[1] << 8) | np[2]; | |
129 | ||
130 | case 2: | |
131 | return (cp[k] << 24) | (cp[k + 1] << 16) | (np[0] << 8) | | |
132 | np[1]; | |
133 | ||
134 | default: | |
135 | return (cp[k] << 24) | (cp[k + 1] << 16) | (cp[k + 2] << 8) | | |
136 | np[0]; | |
137 | } | |
138 | bad: | |
139 | *err = 1; | |
140 | return 0; | |
141 | } | |
142 | ||
143 | static int | |
144 | m_xhalf(m, k, err) | |
145 | register struct mbuf *m; | |
146 | register int k, *err; | |
147 | { | |
148 | register int len; | |
3a1876f4 | 149 | register u_char *cp; |
b688fc87 WJ |
150 | register struct mbuf *m0; |
151 | ||
152 | len = m->m_len; | |
153 | while (k >= len) { | |
154 | k -= len; | |
155 | m = m->m_next; | |
156 | if (m == 0) | |
157 | goto bad; | |
158 | len = m->m_len; | |
159 | } | |
160 | cp = mtod(m, u_char *) + k; | |
161 | if (len - k >= 2) { | |
162 | *err = 0; | |
163 | return EXTRACT_SHORT(cp); | |
164 | } | |
165 | m0 = m->m_next; | |
166 | if (m0 == 0) | |
167 | goto bad; | |
168 | *err = 0; | |
169 | return (cp[k] << 8) | mtod(m0, u_char *)[0]; | |
170 | bad: | |
171 | *err = 1; | |
172 | return 0; | |
173 | } | |
b688fc87 WJ |
174 | #endif |
175 | ||
176 | /* | |
177 | * Execute the filter program starting at pc on the packet p | |
178 | * wirelen is the length of the original packet | |
179 | * buflen is the amount of data present | |
180 | */ | |
181 | u_int | |
182 | bpf_filter(pc, p, wirelen, buflen) | |
183 | register struct bpf_insn *pc; | |
184 | register u_char *p; | |
185 | u_int wirelen; | |
186 | register u_int buflen; | |
187 | { | |
3a1876f4 | 188 | register u_long A, X; |
b688fc87 WJ |
189 | register int k; |
190 | long mem[BPF_MEMWORDS]; | |
191 | ||
192 | if (pc == 0) | |
193 | /* | |
194 | * No filter means accept all. | |
195 | */ | |
196 | return (u_int)-1; | |
197 | #ifdef lint | |
198 | A = 0; | |
199 | X = 0; | |
200 | #endif | |
201 | --pc; | |
202 | while (1) { | |
203 | ++pc; | |
204 | switch (pc->code) { | |
205 | ||
206 | default: | |
207 | #ifdef KERNEL | |
208 | return 0; | |
209 | #else | |
210 | abort(); | |
211 | #endif | |
212 | case BPF_RET|BPF_K: | |
213 | return (u_int)pc->k; | |
214 | ||
215 | case BPF_RET|BPF_A: | |
216 | return (u_int)A; | |
217 | ||
218 | case BPF_LD|BPF_W|BPF_ABS: | |
219 | k = pc->k; | |
220 | if (k + sizeof(long) > buflen) { | |
221 | #ifdef KERNEL | |
222 | int merr; | |
223 | ||
224 | if (buflen != 0) | |
225 | return 0; | |
226 | A = m_xword((struct mbuf *)p, k, &merr); | |
227 | if (merr != 0) | |
228 | return 0; | |
229 | continue; | |
230 | #else | |
231 | return 0; | |
232 | #endif | |
233 | } | |
3a1876f4 | 234 | #ifdef BPF_ALIGN |
b688fc87 WJ |
235 | if (((int)(p + k) & 3) != 0) |
236 | A = EXTRACT_LONG(&p[k]); | |
237 | else | |
238 | #endif | |
3a1876f4 | 239 | A = ntohl(*(long *)(p + k)); |
b688fc87 WJ |
240 | continue; |
241 | ||
242 | case BPF_LD|BPF_H|BPF_ABS: | |
243 | k = pc->k; | |
244 | if (k + sizeof(short) > buflen) { | |
245 | #ifdef KERNEL | |
246 | int merr; | |
247 | ||
248 | if (buflen != 0) | |
249 | return 0; | |
250 | A = m_xhalf((struct mbuf *)p, k, &merr); | |
251 | continue; | |
252 | #else | |
253 | return 0; | |
254 | #endif | |
255 | } | |
256 | A = EXTRACT_SHORT(&p[k]); | |
257 | continue; | |
258 | ||
259 | case BPF_LD|BPF_B|BPF_ABS: | |
260 | k = pc->k; | |
261 | if (k >= buflen) { | |
262 | #ifdef KERNEL | |
263 | register struct mbuf *m; | |
264 | ||
265 | if (buflen != 0) | |
266 | return 0; | |
267 | m = (struct mbuf *)p; | |
268 | MINDEX(m, k); | |
269 | A = mtod(m, u_char *)[k]; | |
270 | continue; | |
271 | #else | |
272 | return 0; | |
273 | #endif | |
274 | } | |
275 | A = p[k]; | |
276 | continue; | |
277 | ||
278 | case BPF_LD|BPF_W|BPF_LEN: | |
279 | A = wirelen; | |
280 | continue; | |
281 | ||
282 | case BPF_LDX|BPF_W|BPF_LEN: | |
283 | X = wirelen; | |
284 | continue; | |
285 | ||
286 | case BPF_LD|BPF_W|BPF_IND: | |
287 | k = X + pc->k; | |
288 | if (k + sizeof(long) > buflen) { | |
289 | #ifdef KERNEL | |
290 | int merr; | |
291 | ||
292 | if (buflen != 0) | |
293 | return 0; | |
294 | A = m_xword((struct mbuf *)p, k, &merr); | |
295 | if (merr != 0) | |
296 | return 0; | |
297 | continue; | |
298 | #else | |
299 | return 0; | |
300 | #endif | |
301 | } | |
3a1876f4 | 302 | #ifdef BPF_ALIGN |
b688fc87 WJ |
303 | if (((int)(p + k) & 3) != 0) |
304 | A = EXTRACT_LONG(&p[k]); | |
305 | else | |
306 | #endif | |
3a1876f4 | 307 | A = ntohl(*(long *)(p + k)); |
b688fc87 WJ |
308 | continue; |
309 | ||
310 | case BPF_LD|BPF_H|BPF_IND: | |
311 | k = X + pc->k; | |
312 | if (k + sizeof(short) > buflen) { | |
313 | #ifdef KERNEL | |
314 | int merr; | |
315 | ||
316 | if (buflen != 0) | |
317 | return 0; | |
318 | A = m_xhalf((struct mbuf *)p, k, &merr); | |
319 | if (merr != 0) | |
320 | return 0; | |
321 | continue; | |
322 | #else | |
323 | return 0; | |
324 | #endif | |
325 | } | |
326 | A = EXTRACT_SHORT(&p[k]); | |
327 | continue; | |
328 | ||
329 | case BPF_LD|BPF_B|BPF_IND: | |
330 | k = X + pc->k; | |
331 | if (k >= buflen) { | |
332 | #ifdef KERNEL | |
333 | register struct mbuf *m; | |
334 | ||
335 | if (buflen != 0) | |
336 | return 0; | |
337 | m = (struct mbuf *)p; | |
338 | MINDEX(m, k); | |
339 | A = mtod(m, char *)[k]; | |
340 | continue; | |
341 | #else | |
342 | return 0; | |
343 | #endif | |
344 | } | |
345 | A = p[k]; | |
346 | continue; | |
347 | ||
348 | case BPF_LDX|BPF_MSH|BPF_B: | |
349 | k = pc->k; | |
350 | if (k >= buflen) { | |
351 | #ifdef KERNEL | |
352 | register struct mbuf *m; | |
353 | ||
354 | if (buflen != 0) | |
355 | return 0; | |
356 | m = (struct mbuf *)p; | |
357 | MINDEX(m, k); | |
358 | X = (mtod(m, char *)[k] & 0xf) << 2; | |
359 | continue; | |
360 | #else | |
361 | return 0; | |
362 | #endif | |
363 | } | |
364 | X = (p[pc->k] & 0xf) << 2; | |
365 | continue; | |
366 | ||
367 | case BPF_LD|BPF_IMM: | |
368 | A = pc->k; | |
369 | continue; | |
370 | ||
371 | case BPF_LDX|BPF_IMM: | |
372 | X = pc->k; | |
373 | continue; | |
374 | ||
375 | case BPF_LD|BPF_MEM: | |
376 | A = mem[pc->k]; | |
377 | continue; | |
378 | ||
379 | case BPF_LDX|BPF_MEM: | |
380 | X = mem[pc->k]; | |
381 | continue; | |
382 | ||
383 | case BPF_ST: | |
384 | mem[pc->k] = A; | |
385 | continue; | |
386 | ||
387 | case BPF_STX: | |
388 | mem[pc->k] = X; | |
389 | continue; | |
390 | ||
391 | case BPF_JMP|BPF_JA: | |
392 | pc += pc->k; | |
393 | continue; | |
394 | ||
395 | case BPF_JMP|BPF_JGT|BPF_K: | |
396 | pc += (A > pc->k) ? pc->jt : pc->jf; | |
397 | continue; | |
398 | ||
399 | case BPF_JMP|BPF_JGE|BPF_K: | |
400 | pc += (A >= pc->k) ? pc->jt : pc->jf; | |
401 | continue; | |
402 | ||
403 | case BPF_JMP|BPF_JEQ|BPF_K: | |
404 | pc += (A == pc->k) ? pc->jt : pc->jf; | |
405 | continue; | |
406 | ||
407 | case BPF_JMP|BPF_JSET|BPF_K: | |
408 | pc += (A & pc->k) ? pc->jt : pc->jf; | |
409 | continue; | |
410 | ||
411 | case BPF_JMP|BPF_JGT|BPF_X: | |
412 | pc += (A > X) ? pc->jt : pc->jf; | |
413 | continue; | |
414 | ||
415 | case BPF_JMP|BPF_JGE|BPF_X: | |
416 | pc += (A >= X) ? pc->jt : pc->jf; | |
417 | continue; | |
418 | ||
419 | case BPF_JMP|BPF_JEQ|BPF_X: | |
420 | pc += (A == X) ? pc->jt : pc->jf; | |
421 | continue; | |
422 | ||
423 | case BPF_JMP|BPF_JSET|BPF_X: | |
424 | pc += (A & X) ? pc->jt : pc->jf; | |
425 | continue; | |
426 | ||
427 | case BPF_ALU|BPF_ADD|BPF_X: | |
428 | A += X; | |
429 | continue; | |
430 | ||
431 | case BPF_ALU|BPF_SUB|BPF_X: | |
432 | A -= X; | |
433 | continue; | |
434 | ||
435 | case BPF_ALU|BPF_MUL|BPF_X: | |
436 | A *= X; | |
437 | continue; | |
438 | ||
439 | case BPF_ALU|BPF_DIV|BPF_X: | |
440 | if (X == 0) | |
441 | return 0; | |
442 | A /= X; | |
443 | continue; | |
444 | ||
445 | case BPF_ALU|BPF_AND|BPF_X: | |
446 | A &= X; | |
447 | continue; | |
448 | ||
449 | case BPF_ALU|BPF_OR|BPF_X: | |
450 | A |= X; | |
451 | continue; | |
452 | ||
453 | case BPF_ALU|BPF_LSH|BPF_X: | |
454 | A <<= X; | |
455 | continue; | |
456 | ||
457 | case BPF_ALU|BPF_RSH|BPF_X: | |
458 | A >>= X; | |
459 | continue; | |
460 | ||
461 | case BPF_ALU|BPF_ADD|BPF_K: | |
462 | A += pc->k; | |
463 | continue; | |
464 | ||
465 | case BPF_ALU|BPF_SUB|BPF_K: | |
466 | A -= pc->k; | |
467 | continue; | |
468 | ||
469 | case BPF_ALU|BPF_MUL|BPF_K: | |
470 | A *= pc->k; | |
471 | continue; | |
472 | ||
473 | case BPF_ALU|BPF_DIV|BPF_K: | |
474 | A /= pc->k; | |
475 | continue; | |
476 | ||
477 | case BPF_ALU|BPF_AND|BPF_K: | |
478 | A &= pc->k; | |
479 | continue; | |
480 | ||
481 | case BPF_ALU|BPF_OR|BPF_K: | |
482 | A |= pc->k; | |
483 | continue; | |
484 | ||
485 | case BPF_ALU|BPF_LSH|BPF_K: | |
486 | A <<= pc->k; | |
487 | continue; | |
488 | ||
489 | case BPF_ALU|BPF_RSH|BPF_K: | |
490 | A >>= pc->k; | |
491 | continue; | |
492 | ||
493 | case BPF_ALU|BPF_NEG: | |
494 | A = -A; | |
495 | continue; | |
496 | ||
497 | case BPF_MISC|BPF_TAX: | |
498 | X = A; | |
499 | continue; | |
500 | ||
501 | case BPF_MISC|BPF_TXA: | |
502 | A = X; | |
503 | continue; | |
504 | } | |
505 | } | |
506 | } | |
507 | ||
508 | #ifdef KERNEL | |
509 | /* | |
510 | * Return true if the 'fcode' is a valid filter program. | |
511 | * The constraints are that each jump be forward and to a valid | |
512 | * code. The code must terminate with either an accept or reject. | |
513 | * 'valid' is an array for use by the routine (it must be at least | |
514 | * 'len' bytes long). | |
515 | * | |
516 | * The kernel needs to be able to verify an application's filter code. | |
517 | * Otherwise, a bogus program could easily crash the system. | |
518 | */ | |
519 | int | |
520 | bpf_validate(f, len) | |
521 | struct bpf_insn *f; | |
522 | int len; | |
523 | { | |
524 | register int i; | |
525 | register struct bpf_insn *p; | |
526 | ||
527 | for (i = 0; i < len; ++i) { | |
528 | /* | |
529 | * Check that that jumps are forward, and within | |
530 | * the code block. | |
531 | */ | |
532 | p = &f[i]; | |
533 | if (BPF_CLASS(p->code) == BPF_JMP) { | |
534 | register int from = i + 1; | |
535 | ||
536 | if (BPF_OP(p->code) == BPF_JA) { | |
537 | if (from + p->k >= len) | |
538 | return 0; | |
539 | } | |
540 | else if (from + p->jt >= len || from + p->jf >= len) | |
541 | return 0; | |
542 | } | |
543 | /* | |
544 | * Check that memory operations use valid addresses. | |
545 | */ | |
546 | if ((BPF_CLASS(p->code) == BPF_ST || | |
547 | (BPF_CLASS(p->code) == BPF_LD && | |
548 | (p->code & 0xe0) == BPF_MEM)) && | |
549 | (p->k >= BPF_MEMWORDS || p->k < 0)) | |
550 | return 0; | |
551 | /* | |
552 | * Check for constant division by 0. | |
553 | */ | |
3a1876f4 DG |
554 | if (p->code == (BPF_ALU|BPF_DIV|BPF_K) && p->k == 0) |
555 | return 0; | |
b688fc87 WJ |
556 | } |
557 | return BPF_CLASS(f[len - 1].code) == BPF_RET; | |
558 | } | |
559 | #endif |