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