Commit | Line | Data |
---|---|---|
6cfe221b KB |
1 | /*- |
2 | * Copyright (c) 1991 The Regents of the University of California. | |
54c31626 SM |
3 | * All rights reserved. |
4 | * | |
6cfe221b KB |
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 | |
7 | * to Berkeley by Steven McCanne of Lawrence Berkeley Laboratory. | |
8 | * | |
9 | * %sccs.include.redist.c% | |
10 | * | |
033112db | 11 | * @(#)bpf_filter.c 7.2 (Berkeley) %G% |
6cfe221b KB |
12 | * |
13 | * static char rcsid[] = | |
14 | * "@(#) $Header: bpf_filter.c,v 1.10 91/04/24 22:07:07 mccanne Locked $ (LBL)"; | |
54c31626 | 15 | */ |
54c31626 | 16 | |
f8e186b1 | 17 | #include <sys/param.h> |
54c31626 | 18 | #include <sys/types.h> |
54c31626 SM |
19 | #include <sys/time.h> |
20 | #include <net/bpf.h> | |
21 | ||
033112db SM |
22 | #ifdef sun |
23 | #include <netinet/in.h> | |
24 | #endif | |
25 | ||
54c31626 SM |
26 | #if defined(sparc) || defined(mips) |
27 | #define ALIGN | |
28 | #endif | |
29 | ||
30 | #ifndef ALIGN | |
31 | #define EXTRACT_SHORT(p) (ntohs(*(u_short *)p)) | |
32 | #define EXTRACT_LONG(p) (ntohl(*(u_long *)p)) | |
33 | #else | |
34 | #define EXTRACT_SHORT(p)\ | |
35 | ((u_short)\ | |
033112db SM |
36 | (*((u_char *)(p)+0)<<8|\ |
37 | *((u_char *)(p)+1)<<0)) | |
54c31626 | 38 | #define EXTRACT_LONG(p)\ |
033112db SM |
39 | (*((u_char *)(p)+0)<<24|\ |
40 | *((u_char *)(p)+1)<<16|\ | |
41 | *((u_char *)(p)+2)<<8|\ | |
42 | *((u_char *)(p)+3)<<0) | |
54c31626 SM |
43 | #endif |
44 | ||
a277f25c SM |
45 | #ifdef KERNEL |
46 | #include <sys/mbuf.h> | |
47 | #define MINDEX(m, k) \ | |
48 | { \ | |
49 | register int len = m->m_len; \ | |
50 | \ | |
51 | while (k >= len) { \ | |
52 | k -= len; \ | |
53 | m = m->m_next; \ | |
54 | if (m == 0) \ | |
55 | return 0; \ | |
56 | len = m->m_len; \ | |
57 | } \ | |
58 | } | |
033112db SM |
59 | |
60 | static int | |
61 | m_xword(m, k, err) | |
62 | register struct mbuf *m; | |
63 | register int k, *err; | |
64 | { | |
65 | register int len; | |
66 | register u_char *cp, *np; | |
67 | register struct mbuf *m0; | |
68 | ||
69 | len = m->m_len; | |
70 | while (k >= len) { | |
71 | k -= len; | |
72 | m = m->m_next; | |
73 | if (m == 0) | |
74 | goto bad; | |
75 | len = m->m_len; | |
76 | } | |
77 | cp = mtod(m, u_char *) + k; | |
78 | if (len - k >= 4) { | |
79 | *err = 0; | |
80 | return EXTRACT_LONG(cp); | |
81 | } | |
82 | m0 = m->m_next; | |
83 | if (m0 == 0 || m0->m_len + len - k < 4) | |
84 | goto bad; | |
85 | *err = 0; | |
86 | np = mtod(m0, u_char *); | |
87 | switch (len - k) { | |
88 | ||
89 | case 1: | |
90 | return (cp[k] << 24) | (np[0] << 16) | (np[1] << 8) | np[2]; | |
91 | ||
92 | case 2: | |
93 | return (cp[k] << 24) | (cp[k + 1] << 16) | (np[0] << 8) | | |
94 | np[1]; | |
95 | ||
96 | default: | |
97 | return (cp[k] << 24) | (cp[k + 1] << 16) | (cp[k + 2] << 8) | | |
98 | np[0]; | |
99 | } | |
100 | bad: | |
101 | *err = 1; | |
102 | return 0; | |
103 | } | |
104 | ||
105 | static int | |
106 | m_xhalf(m, k, err) | |
107 | register struct mbuf *m; | |
108 | register int k, *err; | |
109 | { | |
110 | register int len; | |
111 | register u_char *cp, *np; | |
112 | register struct mbuf *m0; | |
113 | ||
114 | len = m->m_len; | |
115 | while (k >= len) { | |
116 | k -= len; | |
117 | m = m->m_next; | |
118 | if (m == 0) | |
119 | goto bad; | |
120 | len = m->m_len; | |
121 | } | |
122 | cp = mtod(m, u_char *) + k; | |
123 | if (len - k >= 2) { | |
124 | *err = 0; | |
125 | return EXTRACT_SHORT(cp); | |
126 | } | |
127 | m0 = m->m_next; | |
128 | if (m0 == 0) | |
129 | goto bad; | |
130 | *err = 0; | |
131 | return (cp[k] << 8) | mtod(m0, u_char *)[0]; | |
132 | bad: | |
133 | *err = 1; | |
134 | return 0; | |
135 | } | |
136 | ||
137 | ||
a277f25c SM |
138 | #endif |
139 | ||
54c31626 | 140 | /* |
61f2dc53 SM |
141 | * Execute the filter program starting at pc on the packet p |
142 | * wirelen is the length of the original packet | |
143 | * buflen is the amount of data present | |
54c31626 SM |
144 | */ |
145 | u_int | |
146 | bpf_filter(pc, p, wirelen, buflen) | |
147 | register struct bpf_insn *pc; | |
148 | register u_char *p; | |
149 | u_int wirelen; | |
61f2dc53 | 150 | register u_int buflen; |
54c31626 | 151 | { |
54c31626 | 152 | register long A, X; |
61f2dc53 | 153 | register int k; |
54c31626 SM |
154 | long mem[BPF_MEMWORDS]; |
155 | ||
156 | if (pc == 0) | |
157 | /* | |
158 | * No filter means accept all. | |
159 | */ | |
61f2dc53 | 160 | return (u_int)-1; |
54c31626 SM |
161 | #ifdef lint |
162 | A = 0; | |
163 | X = 0; | |
164 | #endif | |
61f2dc53 | 165 | --pc; |
54c31626 | 166 | while (1) { |
61f2dc53 | 167 | ++pc; |
54c31626 SM |
168 | switch (pc->code) { |
169 | ||
170 | default: | |
171 | #ifdef KERNEL | |
172 | return 0; | |
173 | #else | |
174 | abort(); | |
175 | #endif | |
61f2dc53 | 176 | case BPF_RET|BPF_K: |
54c31626 SM |
177 | return (u_int)pc->k; |
178 | ||
61f2dc53 | 179 | case BPF_RET|BPF_A: |
54c31626 SM |
180 | return (u_int)A; |
181 | ||
61f2dc53 SM |
182 | case BPF_LD|BPF_W|BPF_ABS: |
183 | k = pc->k; | |
a277f25c SM |
184 | if (k + sizeof(long) > buflen) { |
185 | #ifdef KERNEL | |
033112db | 186 | int merr; |
a277f25c SM |
187 | |
188 | if (buflen != 0) | |
189 | return 0; | |
033112db SM |
190 | A = m_xword((struct mbuf *)p, k, &merr); |
191 | if (merr != 0) | |
192 | return 0; | |
193 | continue; | |
a277f25c | 194 | #else |
54c31626 | 195 | return 0; |
a277f25c SM |
196 | #endif |
197 | } | |
61f2dc53 SM |
198 | #ifdef ALIGN |
199 | if (((int)(p + k) & 3) != 0) | |
200 | A = EXTRACT_LONG(&p[k]); | |
201 | else | |
202 | #endif | |
203 | A = *(long *)(p + k); | |
033112db | 204 | continue; |
54c31626 | 205 | |
61f2dc53 SM |
206 | case BPF_LD|BPF_H|BPF_ABS: |
207 | k = pc->k; | |
a277f25c SM |
208 | if (k + sizeof(short) > buflen) { |
209 | #ifdef KERNEL | |
033112db | 210 | int merr; |
a277f25c SM |
211 | |
212 | if (buflen != 0) | |
213 | return 0; | |
033112db SM |
214 | A = m_xhalf((struct mbuf *)p, k, &merr); |
215 | continue; | |
a277f25c | 216 | #else |
54c31626 | 217 | return 0; |
a277f25c SM |
218 | #endif |
219 | } | |
61f2dc53 | 220 | A = EXTRACT_SHORT(&p[k]); |
033112db | 221 | continue; |
54c31626 | 222 | |
61f2dc53 SM |
223 | case BPF_LD|BPF_B|BPF_ABS: |
224 | k = pc->k; | |
a277f25c SM |
225 | if (k >= buflen) { |
226 | #ifdef KERNEL | |
227 | register struct mbuf *m; | |
228 | ||
229 | if (buflen != 0) | |
230 | return 0; | |
231 | m = (struct mbuf *)p; | |
232 | MINDEX(m, k); | |
033112db SM |
233 | A = mtod(m, u_char *)[k]; |
234 | continue; | |
a277f25c | 235 | #else |
54c31626 | 236 | return 0; |
a277f25c SM |
237 | #endif |
238 | } | |
61f2dc53 | 239 | A = p[k]; |
033112db | 240 | continue; |
54c31626 | 241 | |
61f2dc53 | 242 | case BPF_LD|BPF_W|BPF_LEN: |
54c31626 | 243 | A = wirelen; |
033112db | 244 | continue; |
54c31626 | 245 | |
61f2dc53 SM |
246 | case BPF_LDX|BPF_W|BPF_LEN: |
247 | X = wirelen; | |
033112db | 248 | continue; |
61f2dc53 SM |
249 | |
250 | case BPF_LD|BPF_W|BPF_IND: | |
251 | k = X + pc->k; | |
a277f25c SM |
252 | if (k + sizeof(long) > buflen) { |
253 | #ifdef KERNEL | |
033112db | 254 | int merr; |
a277f25c SM |
255 | |
256 | if (buflen != 0) | |
257 | return 0; | |
033112db SM |
258 | A = m_xword((struct mbuf *)p, k, &merr); |
259 | if (merr != 0) | |
260 | return 0; | |
261 | continue; | |
a277f25c | 262 | #else |
54c31626 | 263 | return 0; |
a277f25c SM |
264 | #endif |
265 | } | |
61f2dc53 SM |
266 | #ifdef ALIGN |
267 | if (((int)(p + k) & 3) != 0) | |
268 | A = EXTRACT_LONG(&p[k]); | |
269 | else | |
270 | #endif | |
271 | A = *(long *)(p + k); | |
033112db | 272 | continue; |
54c31626 | 273 | |
61f2dc53 SM |
274 | case BPF_LD|BPF_H|BPF_IND: |
275 | k = X + pc->k; | |
a277f25c SM |
276 | if (k + sizeof(short) > buflen) { |
277 | #ifdef KERNEL | |
033112db | 278 | int merr; |
a277f25c SM |
279 | |
280 | if (buflen != 0) | |
281 | return 0; | |
033112db SM |
282 | A = m_xhalf((struct mbuf *)p, k, &merr); |
283 | if (merr != 0) | |
284 | return 0; | |
285 | continue; | |
a277f25c | 286 | #else |
54c31626 | 287 | return 0; |
a277f25c SM |
288 | #endif |
289 | } | |
61f2dc53 | 290 | A = EXTRACT_SHORT(&p[k]); |
033112db | 291 | continue; |
54c31626 | 292 | |
61f2dc53 SM |
293 | case BPF_LD|BPF_B|BPF_IND: |
294 | k = X + pc->k; | |
a277f25c SM |
295 | if (k >= buflen) { |
296 | #ifdef KERNEL | |
297 | register struct mbuf *m; | |
298 | ||
299 | if (buflen != 0) | |
300 | return 0; | |
301 | m = (struct mbuf *)p; | |
302 | MINDEX(m, k); | |
303 | A = mtod(m, char *)[k]; | |
033112db | 304 | continue; |
a277f25c | 305 | #else |
54c31626 | 306 | return 0; |
a277f25c SM |
307 | #endif |
308 | } | |
61f2dc53 | 309 | A = p[k]; |
033112db | 310 | continue; |
54c31626 | 311 | |
a277f25c SM |
312 | case BPF_LDX|BPF_MSH|BPF_B: |
313 | k = pc->k; | |
314 | if (k >= buflen) { | |
315 | #ifdef KERNEL | |
316 | register struct mbuf *m; | |
317 | ||
318 | if (buflen != 0) | |
319 | return 0; | |
320 | m = (struct mbuf *)p; | |
321 | MINDEX(m, k); | |
322 | X = (mtod(m, char *)[k] & 0xf) << 2; | |
033112db | 323 | continue; |
a277f25c SM |
324 | #else |
325 | return 0; | |
326 | #endif | |
327 | } | |
328 | X = (p[pc->k] & 0xf) << 2; | |
033112db | 329 | continue; |
a277f25c | 330 | |
61f2dc53 | 331 | case BPF_LD|BPF_IMM: |
54c31626 | 332 | A = pc->k; |
033112db | 333 | continue; |
54c31626 | 334 | |
61f2dc53 | 335 | case BPF_LDX|BPF_IMM: |
54c31626 | 336 | X = pc->k; |
033112db | 337 | continue; |
54c31626 | 338 | |
61f2dc53 SM |
339 | case BPF_LD|BPF_MEM: |
340 | A = mem[pc->k]; | |
033112db | 341 | continue; |
61f2dc53 SM |
342 | |
343 | case BPF_LDX|BPF_MEM: | |
344 | X = mem[pc->k]; | |
033112db | 345 | continue; |
54c31626 | 346 | |
61f2dc53 | 347 | case BPF_ST: |
54c31626 | 348 | mem[pc->k] = A; |
033112db | 349 | continue; |
54c31626 | 350 | |
61f2dc53 | 351 | case BPF_STX: |
54c31626 | 352 | mem[pc->k] = X; |
033112db | 353 | continue; |
54c31626 | 354 | |
61f2dc53 SM |
355 | case BPF_JMP|BPF_JA: |
356 | pc += pc->k; | |
033112db | 357 | continue; |
61f2dc53 SM |
358 | |
359 | case BPF_JMP|BPF_JGT|BPF_K: | |
360 | pc += (A > pc->k) ? pc->jt : pc->jf; | |
033112db | 361 | continue; |
61f2dc53 SM |
362 | |
363 | case BPF_JMP|BPF_JGE|BPF_K: | |
364 | pc += (A >= pc->k) ? pc->jt : pc->jf; | |
033112db | 365 | continue; |
54c31626 | 366 | |
61f2dc53 SM |
367 | case BPF_JMP|BPF_JEQ|BPF_K: |
368 | pc += (A == pc->k) ? pc->jt : pc->jf; | |
033112db | 369 | continue; |
54c31626 | 370 | |
61f2dc53 SM |
371 | case BPF_JMP|BPF_JSET|BPF_K: |
372 | pc += (A & pc->k) ? pc->jt : pc->jf; | |
033112db | 373 | continue; |
61f2dc53 SM |
374 | |
375 | case BPF_JMP|BPF_JGT|BPF_X: | |
376 | pc += (A > X) ? pc->jt : pc->jf; | |
033112db | 377 | continue; |
54c31626 | 378 | |
61f2dc53 SM |
379 | case BPF_JMP|BPF_JGE|BPF_X: |
380 | pc += (A >= X) ? pc->jt : pc->jf; | |
033112db | 381 | continue; |
61f2dc53 SM |
382 | |
383 | case BPF_JMP|BPF_JEQ|BPF_X: | |
384 | pc += (A == X) ? pc->jt : pc->jf; | |
033112db | 385 | continue; |
54c31626 | 386 | |
61f2dc53 SM |
387 | case BPF_JMP|BPF_JSET|BPF_X: |
388 | pc += (A & X) ? pc->jt : pc->jf; | |
033112db | 389 | continue; |
54c31626 | 390 | |
61f2dc53 | 391 | case BPF_ALU|BPF_ADD|BPF_X: |
54c31626 | 392 | A += X; |
033112db | 393 | continue; |
54c31626 | 394 | |
61f2dc53 | 395 | case BPF_ALU|BPF_SUB|BPF_X: |
54c31626 | 396 | A -= X; |
033112db | 397 | continue; |
54c31626 | 398 | |
61f2dc53 | 399 | case BPF_ALU|BPF_MUL|BPF_X: |
54c31626 | 400 | A *= X; |
033112db | 401 | continue; |
54c31626 | 402 | |
61f2dc53 | 403 | case BPF_ALU|BPF_DIV|BPF_X: |
54c31626 SM |
404 | if (X == 0) |
405 | return 0; | |
406 | A /= X; | |
033112db | 407 | continue; |
54c31626 | 408 | |
61f2dc53 | 409 | case BPF_ALU|BPF_AND|BPF_X: |
54c31626 | 410 | A &= X; |
033112db | 411 | continue; |
54c31626 | 412 | |
61f2dc53 | 413 | case BPF_ALU|BPF_OR|BPF_X: |
54c31626 | 414 | A |= X; |
033112db | 415 | continue; |
54c31626 | 416 | |
61f2dc53 | 417 | case BPF_ALU|BPF_LSH|BPF_X: |
54c31626 | 418 | A <<= X; |
033112db | 419 | continue; |
54c31626 | 420 | |
61f2dc53 | 421 | case BPF_ALU|BPF_RSH|BPF_X: |
54c31626 | 422 | A >>= X; |
033112db | 423 | continue; |
54c31626 | 424 | |
61f2dc53 | 425 | case BPF_ALU|BPF_ADD|BPF_K: |
54c31626 | 426 | A += pc->k; |
033112db | 427 | continue; |
54c31626 | 428 | |
61f2dc53 | 429 | case BPF_ALU|BPF_SUB|BPF_K: |
54c31626 | 430 | A -= pc->k; |
033112db | 431 | continue; |
54c31626 | 432 | |
61f2dc53 | 433 | case BPF_ALU|BPF_MUL|BPF_K: |
54c31626 | 434 | A *= pc->k; |
033112db | 435 | continue; |
54c31626 | 436 | |
61f2dc53 | 437 | case BPF_ALU|BPF_DIV|BPF_K: |
54c31626 | 438 | A /= pc->k; |
033112db | 439 | continue; |
54c31626 | 440 | |
61f2dc53 | 441 | case BPF_ALU|BPF_AND|BPF_K: |
54c31626 | 442 | A &= pc->k; |
033112db | 443 | continue; |
54c31626 | 444 | |
61f2dc53 | 445 | case BPF_ALU|BPF_OR|BPF_K: |
54c31626 | 446 | A |= pc->k; |
033112db | 447 | continue; |
54c31626 | 448 | |
61f2dc53 | 449 | case BPF_ALU|BPF_LSH|BPF_K: |
54c31626 | 450 | A <<= pc->k; |
033112db | 451 | continue; |
54c31626 | 452 | |
61f2dc53 | 453 | case BPF_ALU|BPF_RSH|BPF_K: |
54c31626 | 454 | A >>= pc->k; |
033112db | 455 | continue; |
54c31626 | 456 | |
61f2dc53 | 457 | case BPF_ALU|BPF_NEG: |
54c31626 | 458 | A = -A; |
033112db | 459 | continue; |
61f2dc53 SM |
460 | |
461 | case BPF_MISC|BPF_TAX: | |
462 | X = A; | |
033112db | 463 | continue; |
61f2dc53 SM |
464 | |
465 | case BPF_MISC|BPF_TXA: | |
466 | A = X; | |
033112db | 467 | continue; |
54c31626 | 468 | } |
54c31626 SM |
469 | } |
470 | } | |
471 | ||
472 | #ifdef KERNEL | |
473 | /* | |
474 | * Return true if the 'fcode' is a valid filter program. | |
475 | * The constraints are that each jump be forward and to a valid | |
476 | * code. The code must terminate with either an accept or reject. | |
477 | * 'valid' is an array for use by the routine (it must be at least | |
478 | * 'len' bytes long). | |
479 | * | |
480 | * The kernel needs to be able to verify an application's filter code. | |
481 | * Otherwise, a bogus program could easily crash the system. | |
482 | */ | |
483 | int | |
61f2dc53 SM |
484 | bpf_validate(f, len) |
485 | struct bpf_insn *f; | |
54c31626 SM |
486 | int len; |
487 | { | |
61f2dc53 SM |
488 | register int i; |
489 | register struct bpf_insn *p; | |
54c31626 | 490 | |
61f2dc53 | 491 | for (i = 0; i < len; ++i) { |
54c31626 SM |
492 | /* |
493 | * Check that that jumps are forward, and within | |
494 | * the code block. | |
495 | */ | |
61f2dc53 SM |
496 | p = &f[i]; |
497 | if (BPF_CLASS(p->code) == BPF_JMP) { | |
498 | register int from = i + 1; | |
499 | ||
500 | if (BPF_OP(p->code) == BPF_JA) { | |
501 | if (from + p->k >= len) | |
502 | return 0; | |
503 | } | |
504 | else if (from + p->jt >= len || from + p->jf >= len) | |
505 | return 0; | |
506 | } | |
54c31626 SM |
507 | /* |
508 | * Check that memory operations use valid addresses. | |
509 | */ | |
61f2dc53 SM |
510 | if ((BPF_CLASS(p->code) == BPF_ST || |
511 | (BPF_CLASS(p->code) == BPF_LD && | |
512 | (p->code & 0xe0) == BPF_MEM)) && | |
513 | (p->k >= BPF_MEMWORDS || p->k < 0)) | |
514 | return 0; | |
515 | /* | |
516 | * Check for constant division by 0. | |
517 | */ | |
518 | if (p->code == BPF_ALU|BPF_DIV|BPF_K && p->k == 0) | |
519 | return; | |
54c31626 | 520 | } |
61f2dc53 | 521 | return BPF_CLASS(f[len - 1].code) == BPF_RET; |
54c31626 SM |
522 | } |
523 | #endif |