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