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 | * |
e887745e | 12 | * @(#)bpf_filter.c 7.5 (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) |
e887745e | 28 | #define BPF_ALIGN |
54c31626 SM |
29 | #endif |
30 | ||
e887745e SM |
31 | #ifndef BPF_ALIGN |
32 | #define EXTRACT_SHORT(p) ((u_short)ntohs(*(u_short *)p)) | |
54c31626 SM |
33 | #define EXTRACT_LONG(p) (ntohl(*(u_long *)p)) |
34 | #else | |
35 | #define EXTRACT_SHORT(p)\ | |
36 | ((u_short)\ | |
e887745e SM |
37 | ((u_short)*((u_char *)p+0)<<8|\ |
38 | (u_short)*((u_char *)p+1)<<0)) | |
54c31626 | 39 | #define EXTRACT_LONG(p)\ |
e887745e SM |
40 | ((u_long)*((u_char *)p+0)<<24|\ |
41 | (u_long)*((u_char *)p+1)<<16|\ | |
42 | (u_long)*((u_char *)p+2)<<8|\ | |
43 | (u_long)*((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 | } | |
a277f25c SM |
137 | #endif |
138 | ||
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 |