]>
Commit | Line | Data |
---|---|---|
1c79356b | 1 | /* |
5ba3f43e | 2 | * Copyright (c) 2000-2017 Apple Inc. All rights reserved. |
5d5c5d0d | 3 | * |
2d21ac55 | 4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ |
0a7de745 | 5 | * |
2d21ac55 A |
6 | * This file contains Original Code and/or Modifications of Original Code |
7 | * as defined in and that are subject to the Apple Public Source License | |
8 | * Version 2.0 (the 'License'). You may not use this file except in | |
9 | * compliance with the License. The rights granted to you under the License | |
10 | * may not be used to create, or enable the creation or redistribution of, | |
11 | * unlawful or unlicensed copies of an Apple operating system, or to | |
12 | * circumvent, violate, or enable the circumvention or violation of, any | |
13 | * terms of an Apple operating system software license agreement. | |
0a7de745 | 14 | * |
2d21ac55 A |
15 | * Please obtain a copy of the License at |
16 | * http://www.opensource.apple.com/apsl/ and read it before using this file. | |
0a7de745 | 17 | * |
2d21ac55 A |
18 | * The Original Code and all software distributed under the License are |
19 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
8f6c56a5 A |
20 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
21 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
2d21ac55 A |
22 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. |
23 | * Please see the License for the specific language governing rights and | |
24 | * limitations under the License. | |
0a7de745 | 25 | * |
2d21ac55 | 26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ |
1c79356b A |
27 | */ |
28 | /* | |
29 | * Copyright (c) 1990, 1991, 1993 | |
30 | * The Regents of the University of California. All rights reserved. | |
31 | * | |
32 | * This code is derived from the Stanford/CMU enet packet filter, | |
33 | * (net/enet.c) distributed as part of 4.3BSD, and code contributed | |
34 | * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence | |
35 | * Berkeley Laboratory. | |
36 | * | |
37 | * Redistribution and use in source and binary forms, with or without | |
38 | * modification, are permitted provided that the following conditions | |
39 | * are met: | |
40 | * 1. Redistributions of source code must retain the above copyright | |
41 | * notice, this list of conditions and the following disclaimer. | |
42 | * 2. Redistributions in binary form must reproduce the above copyright | |
43 | * notice, this list of conditions and the following disclaimer in the | |
44 | * documentation and/or other materials provided with the distribution. | |
45 | * 3. All advertising materials mentioning features or use of this software | |
46 | * must display the following acknowledgement: | |
47 | * This product includes software developed by the University of | |
48 | * California, Berkeley and its contributors. | |
49 | * 4. Neither the name of the University nor the names of its contributors | |
50 | * may be used to endorse or promote products derived from this software | |
51 | * without specific prior written permission. | |
52 | * | |
53 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
54 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
55 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
56 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
57 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
58 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
59 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
60 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
61 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
62 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
63 | * SUCH DAMAGE. | |
64 | * | |
65 | * @(#)bpf_filter.c 8.1 (Berkeley) 6/10/93 | |
66 | * | |
9bccf70c | 67 | * $FreeBSD: src/sys/net/bpf_filter.c,v 1.17 1999/12/29 04:38:31 peter Exp $ |
1c79356b A |
68 | */ |
69 | ||
70 | #include <sys/param.h> | |
316670eb | 71 | #include <string.h> |
1c79356b A |
72 | |
73 | #ifdef sun | |
74 | #include <netinet/in.h> | |
75 | #endif | |
76 | ||
1c79356b A |
77 | #ifdef KERNEL |
78 | #include <sys/mbuf.h> | |
79 | #endif | |
80 | #include <net/bpf.h> | |
81 | #ifdef KERNEL | |
1c79356b | 82 | |
6d2010ae A |
83 | extern unsigned int bpf_maxbufsize; |
84 | ||
5ba3f43e A |
85 | static inline u_int32_t |
86 | get_word_from_buffers(u_char * cp, u_char * np, int num_from_cp) | |
87 | { | |
0a7de745 | 88 | u_int32_t val; |
1c79356b | 89 | |
5ba3f43e A |
90 | switch (num_from_cp) { |
91 | case 1: | |
92 | val = ((u_int32_t)cp[0] << 24) | | |
0a7de745 A |
93 | ((u_int32_t)np[0] << 16) | |
94 | ((u_int32_t)np[1] << 8) | | |
95 | (u_int32_t)np[2]; | |
5ba3f43e A |
96 | break; |
97 | ||
98 | case 2: | |
99 | val = ((u_int32_t)cp[0] << 24) | | |
0a7de745 A |
100 | ((u_int32_t)cp[1] << 16) | |
101 | ((u_int32_t)np[0] << 8) | | |
102 | (u_int32_t)np[1]; | |
5ba3f43e A |
103 | break; |
104 | default: | |
105 | val = ((u_int32_t)cp[0] << 24) | | |
0a7de745 A |
106 | ((u_int32_t)cp[1] << 16) | |
107 | ((u_int32_t)cp[2] << 8) | | |
108 | (u_int32_t)np[0]; | |
5ba3f43e A |
109 | break; |
110 | } | |
0a7de745 | 111 | return val; |
5ba3f43e A |
112 | } |
113 | ||
114 | static u_char * | |
115 | m_hdr_offset(struct mbuf **m_p, void * hdr, size_t hdrlen, bpf_u_int32 * k_p, | |
116 | size_t * len_p) | |
1c79356b | 117 | { |
0a7de745 | 118 | u_char *cp; |
5ba3f43e | 119 | bpf_u_int32 k = *k_p; |
39037602 | 120 | size_t len; |
5ba3f43e A |
121 | |
122 | if (k >= hdrlen) { | |
123 | struct mbuf *m = *m_p; | |
124 | ||
125 | /* there's no header or the offset we want is past the header */ | |
126 | k -= hdrlen; | |
1c79356b | 127 | len = m->m_len; |
5ba3f43e A |
128 | while (k >= len) { |
129 | k -= len; | |
130 | m = m->m_next; | |
0a7de745 A |
131 | if (m == NULL) { |
132 | return NULL; | |
133 | } | |
5ba3f43e A |
134 | len = m->m_len; |
135 | } | |
136 | cp = mtod(m, u_char *) + k; | |
137 | ||
138 | /* return next mbuf, in case it's needed */ | |
139 | *m_p = m->m_next; | |
140 | ||
141 | /* update the offset */ | |
142 | *k_p = k; | |
143 | } else { | |
144 | len = hdrlen; | |
145 | cp = (u_char *)hdr + k; | |
1c79356b | 146 | } |
5ba3f43e | 147 | *len_p = len; |
0a7de745 | 148 | return cp; |
5ba3f43e A |
149 | } |
150 | ||
151 | static u_int32_t | |
152 | m_xword(struct mbuf *m, void * hdr, size_t hdrlen, bpf_u_int32 k, int *err) | |
153 | { | |
154 | size_t len; | |
155 | u_char *cp, *np; | |
156 | ||
157 | cp = m_hdr_offset(&m, hdr, hdrlen, &k, &len); | |
0a7de745 | 158 | if (cp == NULL) { |
5ba3f43e | 159 | goto bad; |
0a7de745 | 160 | } |
1c79356b A |
161 | if (len - k >= 4) { |
162 | *err = 0; | |
163 | return EXTRACT_LONG(cp); | |
164 | } | |
0a7de745 | 165 | if (m == 0 || m->m_len + len - k < 4) { |
1c79356b | 166 | goto bad; |
0a7de745 | 167 | } |
1c79356b | 168 | *err = 0; |
5ba3f43e A |
169 | np = mtod(m, u_char *); |
170 | return get_word_from_buffers(cp, np, len - k); | |
1c79356b | 171 | |
0a7de745 | 172 | bad: |
1c79356b A |
173 | *err = 1; |
174 | return 0; | |
175 | } | |
176 | ||
177 | static u_int16_t | |
5ba3f43e | 178 | m_xhalf(struct mbuf *m, void * hdr, size_t hdrlen, bpf_u_int32 k, int *err) |
1c79356b | 179 | { |
39037602 A |
180 | size_t len; |
181 | u_char *cp; | |
5ba3f43e A |
182 | |
183 | cp = m_hdr_offset(&m, hdr, hdrlen, &k, &len); | |
0a7de745 | 184 | if (cp == NULL) { |
5ba3f43e | 185 | goto bad; |
0a7de745 | 186 | } |
1c79356b A |
187 | if (len - k >= 2) { |
188 | *err = 0; | |
189 | return EXTRACT_SHORT(cp); | |
190 | } | |
0a7de745 | 191 | if (m == 0) { |
5ba3f43e | 192 | goto bad; |
0a7de745 | 193 | } |
5ba3f43e A |
194 | *err = 0; |
195 | return (cp[0] << 8) | mtod(m, u_char *)[0]; | |
0a7de745 | 196 | bad: |
5ba3f43e A |
197 | *err = 1; |
198 | return 0; | |
199 | } | |
200 | ||
201 | static u_int8_t | |
202 | m_xbyte(struct mbuf *m, void * hdr, size_t hdrlen, bpf_u_int32 k, int *err) | |
203 | { | |
204 | size_t len; | |
205 | u_char *cp; | |
206 | ||
207 | cp = m_hdr_offset(&m, hdr, hdrlen, &k, &len); | |
0a7de745 | 208 | if (cp == NULL) { |
1c79356b | 209 | goto bad; |
0a7de745 | 210 | } |
1c79356b | 211 | *err = 0; |
0a7de745 A |
212 | return *cp; |
213 | bad: | |
1c79356b A |
214 | *err = 1; |
215 | return 0; | |
5ba3f43e A |
216 | } |
217 | ||
218 | ||
219 | static u_int32_t | |
220 | bp_xword(struct bpf_packet *bp, bpf_u_int32 k, int *err) | |
221 | { | |
0a7de745 A |
222 | void * hdr = bp->bpfp_header; |
223 | size_t hdrlen = bp->bpfp_header_length; | |
5ba3f43e A |
224 | |
225 | switch (bp->bpfp_type) { | |
226 | case BPF_PACKET_TYPE_MBUF: | |
227 | return m_xword(bp->bpfp_mbuf, hdr, hdrlen, k, err); | |
228 | default: | |
229 | break; | |
230 | } | |
231 | *err = 1; | |
232 | return 0; | |
5ba3f43e A |
233 | } |
234 | ||
235 | static u_int16_t | |
236 | bp_xhalf(struct bpf_packet *bp, bpf_u_int32 k, int *err) | |
237 | { | |
0a7de745 A |
238 | void * hdr = bp->bpfp_header; |
239 | size_t hdrlen = bp->bpfp_header_length; | |
5ba3f43e A |
240 | |
241 | switch (bp->bpfp_type) { | |
242 | case BPF_PACKET_TYPE_MBUF: | |
243 | return m_xhalf(bp->bpfp_mbuf, hdr, hdrlen, k, err); | |
244 | default: | |
245 | break; | |
246 | } | |
247 | *err = 1; | |
248 | return 0; | |
1c79356b | 249 | } |
5ba3f43e A |
250 | |
251 | static u_int8_t | |
252 | bp_xbyte(struct bpf_packet *bp, bpf_u_int32 k, int *err) | |
253 | { | |
0a7de745 A |
254 | void * hdr = bp->bpfp_header; |
255 | size_t hdrlen = bp->bpfp_header_length; | |
5ba3f43e A |
256 | |
257 | switch (bp->bpfp_type) { | |
258 | case BPF_PACKET_TYPE_MBUF: | |
259 | return m_xbyte(bp->bpfp_mbuf, hdr, hdrlen, k, err); | |
260 | default: | |
261 | break; | |
262 | } | |
263 | *err = 1; | |
264 | return 0; | |
5ba3f43e A |
265 | } |
266 | ||
1c79356b A |
267 | #endif |
268 | ||
269 | /* | |
270 | * Execute the filter program starting at pc on the packet p | |
271 | * wirelen is the length of the original packet | |
272 | * buflen is the amount of data present | |
273 | */ | |
274 | u_int | |
91447636 | 275 | bpf_filter(const struct bpf_insn *pc, u_char *p, u_int wirelen, u_int buflen) |
1c79356b | 276 | { |
39037602 A |
277 | u_int32_t A = 0, X = 0; |
278 | bpf_u_int32 k; | |
1c79356b | 279 | int32_t mem[BPF_MEMWORDS]; |
5ba3f43e A |
280 | #ifdef KERNEL |
281 | int merr; | |
282 | struct bpf_packet * bp = (struct bpf_packet *)(void *)p; | |
283 | #endif /* KERNEL */ | |
1c79356b | 284 | |
316670eb A |
285 | bzero(mem, sizeof(mem)); |
286 | ||
0a7de745 | 287 | if (pc == 0) { |
1c79356b A |
288 | /* |
289 | * No filter means accept all. | |
290 | */ | |
0a7de745 A |
291 | return (u_int) - 1; |
292 | } | |
1c79356b A |
293 | |
294 | --pc; | |
295 | while (1) { | |
296 | ++pc; | |
297 | switch (pc->code) { | |
1c79356b A |
298 | default: |
299 | #ifdef KERNEL | |
300 | return 0; | |
5ba3f43e | 301 | #else /* KERNEL */ |
1c79356b | 302 | abort(); |
5ba3f43e | 303 | #endif /* KERNEL */ |
0a7de745 | 304 | case BPF_RET | BPF_K: |
1c79356b A |
305 | return (u_int)pc->k; |
306 | ||
0a7de745 | 307 | case BPF_RET | BPF_A: |
1c79356b A |
308 | return (u_int)A; |
309 | ||
0a7de745 | 310 | case BPF_LD | BPF_W | BPF_ABS: |
1c79356b A |
311 | k = pc->k; |
312 | if (k > buflen || sizeof(int32_t) > buflen - k) { | |
313 | #ifdef KERNEL | |
0a7de745 | 314 | if (buflen != 0) { |
1c79356b | 315 | return 0; |
0a7de745 | 316 | } |
5ba3f43e | 317 | A = bp_xword(bp, k, &merr); |
0a7de745 | 318 | if (merr != 0) { |
1c79356b | 319 | return 0; |
0a7de745 | 320 | } |
1c79356b | 321 | continue; |
5ba3f43e | 322 | #else /* KERNEL */ |
1c79356b | 323 | return 0; |
5ba3f43e | 324 | #endif /* KERNEL */ |
1c79356b A |
325 | } |
326 | #if BPF_ALIGN | |
0a7de745 | 327 | if (((intptr_t)(p + k) & 3) != 0) { |
1c79356b | 328 | A = EXTRACT_LONG(&p[k]); |
0a7de745 | 329 | } else |
5ba3f43e | 330 | #endif /* BPF_ALIGN */ |
0a7de745 | 331 | A = ntohl(*(int32_t *)(void *)(p + k)); |
1c79356b A |
332 | continue; |
333 | ||
0a7de745 | 334 | case BPF_LD | BPF_H | BPF_ABS: |
1c79356b A |
335 | k = pc->k; |
336 | if (k > buflen || sizeof(int16_t) > buflen - k) { | |
337 | #ifdef KERNEL | |
0a7de745 | 338 | if (buflen != 0) { |
1c79356b | 339 | return 0; |
0a7de745 | 340 | } |
5ba3f43e | 341 | A = bp_xhalf(bp, k, &merr); |
0a7de745 | 342 | if (merr != 0) { |
5ba3f43e | 343 | return 0; |
0a7de745 | 344 | } |
1c79356b | 345 | continue; |
5ba3f43e | 346 | #else /* KERNEL */ |
1c79356b | 347 | return 0; |
5ba3f43e | 348 | #endif /* KERNEL */ |
1c79356b A |
349 | } |
350 | A = EXTRACT_SHORT(&p[k]); | |
351 | continue; | |
352 | ||
0a7de745 | 353 | case BPF_LD | BPF_B | BPF_ABS: |
1c79356b A |
354 | k = pc->k; |
355 | if (k >= buflen) { | |
356 | #ifdef KERNEL | |
0a7de745 | 357 | if (buflen != 0) { |
1c79356b | 358 | return 0; |
0a7de745 | 359 | } |
5ba3f43e | 360 | A = bp_xbyte(bp, k, &merr); |
0a7de745 | 361 | if (merr != 0) { |
5ba3f43e | 362 | return 0; |
0a7de745 | 363 | } |
1c79356b | 364 | continue; |
5ba3f43e | 365 | #else /* KERNEL */ |
1c79356b | 366 | return 0; |
5ba3f43e | 367 | #endif /* KERNEL */ |
1c79356b A |
368 | } |
369 | A = p[k]; | |
370 | continue; | |
371 | ||
0a7de745 | 372 | case BPF_LD | BPF_W | BPF_LEN: |
1c79356b A |
373 | A = wirelen; |
374 | continue; | |
375 | ||
0a7de745 | 376 | case BPF_LDX | BPF_W | BPF_LEN: |
1c79356b A |
377 | X = wirelen; |
378 | continue; | |
379 | ||
0a7de745 | 380 | case BPF_LD | BPF_W | BPF_IND: |
1c79356b | 381 | k = X + pc->k; |
9bccf70c A |
382 | if (pc->k > buflen || X > buflen - pc->k || |
383 | sizeof(int32_t) > buflen - k) { | |
1c79356b | 384 | #ifdef KERNEL |
0a7de745 | 385 | if (buflen != 0) { |
1c79356b | 386 | return 0; |
0a7de745 | 387 | } |
5ba3f43e | 388 | A = bp_xword(bp, k, &merr); |
0a7de745 | 389 | if (merr != 0) { |
1c79356b | 390 | return 0; |
0a7de745 | 391 | } |
1c79356b | 392 | continue; |
5ba3f43e | 393 | #else /* KERNEL */ |
1c79356b | 394 | return 0; |
5ba3f43e | 395 | #endif /* KERNEL */ |
1c79356b A |
396 | } |
397 | #if BPF_ALIGN | |
0a7de745 | 398 | if (((intptr_t)(p + k) & 3) != 0) { |
1c79356b | 399 | A = EXTRACT_LONG(&p[k]); |
0a7de745 | 400 | } else |
5ba3f43e | 401 | #endif /* BPF_ALIGN */ |
0a7de745 | 402 | A = ntohl(*(int32_t *)(void *)(p + k)); |
1c79356b A |
403 | continue; |
404 | ||
0a7de745 | 405 | case BPF_LD | BPF_H | BPF_IND: |
1c79356b | 406 | k = X + pc->k; |
9bccf70c A |
407 | if (X > buflen || pc->k > buflen - X || |
408 | sizeof(int16_t) > buflen - k) { | |
1c79356b | 409 | #ifdef KERNEL |
0a7de745 | 410 | if (buflen != 0) { |
1c79356b | 411 | return 0; |
0a7de745 | 412 | } |
5ba3f43e | 413 | A = bp_xhalf(bp, k, &merr); |
0a7de745 | 414 | if (merr != 0) { |
1c79356b | 415 | return 0; |
0a7de745 | 416 | } |
1c79356b | 417 | continue; |
5ba3f43e | 418 | #else /* KERNEL */ |
1c79356b | 419 | return 0; |
5ba3f43e | 420 | #endif /* KERNEL */ |
1c79356b A |
421 | } |
422 | A = EXTRACT_SHORT(&p[k]); | |
423 | continue; | |
424 | ||
0a7de745 | 425 | case BPF_LD | BPF_B | BPF_IND: |
1c79356b A |
426 | k = X + pc->k; |
427 | if (pc->k >= buflen || X >= buflen - pc->k) { | |
428 | #ifdef KERNEL | |
0a7de745 | 429 | if (buflen != 0) { |
1c79356b | 430 | return 0; |
0a7de745 | 431 | } |
5ba3f43e | 432 | A = bp_xbyte(bp, k, &merr); |
0a7de745 | 433 | if (merr != 0) { |
5ba3f43e | 434 | return 0; |
0a7de745 | 435 | } |
1c79356b | 436 | continue; |
5ba3f43e | 437 | #else /* KERNEL */ |
1c79356b | 438 | return 0; |
5ba3f43e | 439 | #endif /* KERNEL */ |
1c79356b A |
440 | } |
441 | A = p[k]; | |
442 | continue; | |
443 | ||
0a7de745 | 444 | case BPF_LDX | BPF_MSH | BPF_B: |
1c79356b A |
445 | k = pc->k; |
446 | if (k >= buflen) { | |
447 | #ifdef KERNEL | |
0a7de745 | 448 | if (buflen != 0) { |
1c79356b | 449 | return 0; |
0a7de745 | 450 | } |
5ba3f43e | 451 | X = bp_xbyte(bp, k, &merr); |
0a7de745 | 452 | if (merr != 0) { |
5ba3f43e | 453 | return 0; |
0a7de745 | 454 | } |
5ba3f43e | 455 | X = (X & 0xf) << 2; |
1c79356b A |
456 | continue; |
457 | #else | |
458 | return 0; | |
459 | #endif | |
460 | } | |
461 | X = (p[pc->k] & 0xf) << 2; | |
462 | continue; | |
463 | ||
0a7de745 | 464 | case BPF_LD | BPF_IMM: |
1c79356b A |
465 | A = pc->k; |
466 | continue; | |
467 | ||
0a7de745 | 468 | case BPF_LDX | BPF_IMM: |
1c79356b A |
469 | X = pc->k; |
470 | continue; | |
471 | ||
0a7de745 | 472 | case BPF_LD | BPF_MEM: |
cb323159 A |
473 | if (pc->k >= BPF_MEMWORDS) { |
474 | return 0; | |
475 | } | |
1c79356b A |
476 | A = mem[pc->k]; |
477 | continue; | |
478 | ||
0a7de745 | 479 | case BPF_LDX | BPF_MEM: |
cb323159 A |
480 | if (pc->k >= BPF_MEMWORDS) { |
481 | return 0; | |
482 | } | |
1c79356b A |
483 | X = mem[pc->k]; |
484 | continue; | |
485 | ||
486 | case BPF_ST: | |
0a7de745 | 487 | if (pc->k >= BPF_MEMWORDS) { |
39236c6e | 488 | return 0; |
0a7de745 | 489 | } |
1c79356b A |
490 | mem[pc->k] = A; |
491 | continue; | |
492 | ||
493 | case BPF_STX: | |
0a7de745 | 494 | if (pc->k >= BPF_MEMWORDS) { |
39236c6e | 495 | return 0; |
0a7de745 | 496 | } |
1c79356b A |
497 | mem[pc->k] = X; |
498 | continue; | |
499 | ||
0a7de745 | 500 | case BPF_JMP | BPF_JA: |
1c79356b A |
501 | pc += pc->k; |
502 | continue; | |
503 | ||
0a7de745 | 504 | case BPF_JMP | BPF_JGT | BPF_K: |
1c79356b A |
505 | pc += (A > pc->k) ? pc->jt : pc->jf; |
506 | continue; | |
507 | ||
0a7de745 | 508 | case BPF_JMP | BPF_JGE | BPF_K: |
1c79356b A |
509 | pc += (A >= pc->k) ? pc->jt : pc->jf; |
510 | continue; | |
511 | ||
0a7de745 | 512 | case BPF_JMP | BPF_JEQ | BPF_K: |
1c79356b A |
513 | pc += (A == pc->k) ? pc->jt : pc->jf; |
514 | continue; | |
515 | ||
0a7de745 | 516 | case BPF_JMP | BPF_JSET | BPF_K: |
1c79356b A |
517 | pc += (A & pc->k) ? pc->jt : pc->jf; |
518 | continue; | |
519 | ||
0a7de745 | 520 | case BPF_JMP | BPF_JGT | BPF_X: |
1c79356b A |
521 | pc += (A > X) ? pc->jt : pc->jf; |
522 | continue; | |
523 | ||
0a7de745 | 524 | case BPF_JMP | BPF_JGE | BPF_X: |
1c79356b A |
525 | pc += (A >= X) ? pc->jt : pc->jf; |
526 | continue; | |
527 | ||
0a7de745 | 528 | case BPF_JMP | BPF_JEQ | BPF_X: |
1c79356b A |
529 | pc += (A == X) ? pc->jt : pc->jf; |
530 | continue; | |
531 | ||
0a7de745 | 532 | case BPF_JMP | BPF_JSET | BPF_X: |
1c79356b A |
533 | pc += (A & X) ? pc->jt : pc->jf; |
534 | continue; | |
535 | ||
0a7de745 | 536 | case BPF_ALU | BPF_ADD | BPF_X: |
1c79356b A |
537 | A += X; |
538 | continue; | |
539 | ||
0a7de745 | 540 | case BPF_ALU | BPF_SUB | BPF_X: |
1c79356b A |
541 | A -= X; |
542 | continue; | |
543 | ||
0a7de745 | 544 | case BPF_ALU | BPF_MUL | BPF_X: |
1c79356b A |
545 | A *= X; |
546 | continue; | |
547 | ||
0a7de745 A |
548 | case BPF_ALU | BPF_DIV | BPF_X: |
549 | if (X == 0) { | |
1c79356b | 550 | return 0; |
0a7de745 | 551 | } |
1c79356b A |
552 | A /= X; |
553 | continue; | |
554 | ||
0a7de745 | 555 | case BPF_ALU | BPF_AND | BPF_X: |
1c79356b A |
556 | A &= X; |
557 | continue; | |
558 | ||
0a7de745 | 559 | case BPF_ALU | BPF_OR | BPF_X: |
1c79356b A |
560 | A |= X; |
561 | continue; | |
562 | ||
0a7de745 | 563 | case BPF_ALU | BPF_LSH | BPF_X: |
1c79356b A |
564 | A <<= X; |
565 | continue; | |
566 | ||
0a7de745 | 567 | case BPF_ALU | BPF_RSH | BPF_X: |
1c79356b A |
568 | A >>= X; |
569 | continue; | |
570 | ||
0a7de745 | 571 | case BPF_ALU | BPF_ADD | BPF_K: |
1c79356b A |
572 | A += pc->k; |
573 | continue; | |
574 | ||
0a7de745 | 575 | case BPF_ALU | BPF_SUB | BPF_K: |
1c79356b A |
576 | A -= pc->k; |
577 | continue; | |
578 | ||
0a7de745 | 579 | case BPF_ALU | BPF_MUL | BPF_K: |
1c79356b A |
580 | A *= pc->k; |
581 | continue; | |
582 | ||
0a7de745 | 583 | case BPF_ALU | BPF_DIV | BPF_K: |
1c79356b A |
584 | A /= pc->k; |
585 | continue; | |
586 | ||
0a7de745 | 587 | case BPF_ALU | BPF_AND | BPF_K: |
1c79356b A |
588 | A &= pc->k; |
589 | continue; | |
590 | ||
0a7de745 | 591 | case BPF_ALU | BPF_OR | BPF_K: |
1c79356b A |
592 | A |= pc->k; |
593 | continue; | |
594 | ||
0a7de745 | 595 | case BPF_ALU | BPF_LSH | BPF_K: |
1c79356b A |
596 | A <<= pc->k; |
597 | continue; | |
598 | ||
0a7de745 | 599 | case BPF_ALU | BPF_RSH | BPF_K: |
1c79356b A |
600 | A >>= pc->k; |
601 | continue; | |
602 | ||
0a7de745 | 603 | case BPF_ALU | BPF_NEG: |
1c79356b A |
604 | A = -A; |
605 | continue; | |
606 | ||
0a7de745 | 607 | case BPF_MISC | BPF_TAX: |
1c79356b A |
608 | X = A; |
609 | continue; | |
610 | ||
0a7de745 | 611 | case BPF_MISC | BPF_TXA: |
1c79356b A |
612 | A = X; |
613 | continue; | |
614 | } | |
615 | } | |
616 | } | |
617 | ||
618 | #ifdef KERNEL | |
619 | /* | |
620 | * Return true if the 'fcode' is a valid filter program. | |
621 | * The constraints are that each jump be forward and to a valid | |
0a7de745 | 622 | * code, that memory accesses are within valid ranges (to the |
6d2010ae A |
623 | * extent that this can be checked statically; loads of packet data |
624 | * have to be, and are, also checked at run time), and that | |
625 | * the code terminates with either an accept or reject. | |
1c79356b A |
626 | * |
627 | * The kernel needs to be able to verify an application's filter code. | |
628 | * Otherwise, a bogus program could easily crash the system. | |
629 | */ | |
630 | int | |
91447636 | 631 | bpf_validate(const struct bpf_insn *f, int len) |
1c79356b | 632 | { |
6d2010ae | 633 | u_int i, from; |
9bccf70c | 634 | const struct bpf_insn *p; |
1c79356b | 635 | |
0a7de745 | 636 | if (len < 1 || len > BPF_MAXINSNS) { |
6d2010ae | 637 | return 0; |
0a7de745 A |
638 | } |
639 | ||
6d2010ae | 640 | for (i = 0; i < ((u_int)len); ++i) { |
1c79356b | 641 | p = &f[i]; |
6d2010ae | 642 | switch (BPF_CLASS(p->code)) { |
0a7de745 A |
643 | /* |
644 | * Check that memory operations use valid addresses | |
645 | */ | |
646 | case BPF_LD: | |
647 | case BPF_LDX: | |
648 | switch (BPF_MODE(p->code)) { | |
649 | case BPF_IMM: | |
6d2010ae | 650 | break; |
0a7de745 A |
651 | case BPF_ABS: |
652 | case BPF_IND: | |
653 | case BPF_MSH: | |
654 | /* | |
655 | * More strict check with actual packet length | |
656 | * is done runtime. | |
657 | */ | |
658 | if (p->k >= bpf_maxbufsize) { | |
1c79356b | 659 | return 0; |
0a7de745 | 660 | } |
6d2010ae | 661 | break; |
0a7de745 A |
662 | case BPF_MEM: |
663 | if (p->k >= BPF_MEMWORDS) { | |
664 | return 0; | |
6d2010ae A |
665 | } |
666 | break; | |
0a7de745 A |
667 | case BPF_LEN: |
668 | break; | |
669 | default: | |
670 | return 0; | |
671 | } | |
672 | break; | |
673 | case BPF_ST: | |
674 | case BPF_STX: | |
675 | if (p->k >= BPF_MEMWORDS) { | |
676 | return 0; | |
677 | } | |
678 | break; | |
679 | case BPF_ALU: | |
680 | switch (BPF_OP(p->code)) { | |
681 | case BPF_ADD: | |
682 | case BPF_SUB: | |
683 | case BPF_MUL: | |
684 | case BPF_OR: | |
685 | case BPF_AND: | |
686 | case BPF_LSH: | |
687 | case BPF_RSH: | |
688 | case BPF_NEG: | |
689 | break; | |
690 | case BPF_DIV: | |
6d2010ae | 691 | /* |
0a7de745 | 692 | * Check for constant division by 0 |
6d2010ae | 693 | */ |
0a7de745 A |
694 | if (BPF_SRC(p->code) == BPF_K && p->k == 0) { |
695 | return 0; | |
6d2010ae A |
696 | } |
697 | break; | |
0a7de745 A |
698 | default: |
699 | return 0; | |
700 | } | |
701 | break; | |
702 | case BPF_JMP: | |
703 | /* | |
704 | * Check that jumps are within the code block, | |
705 | * and that unconditional branches don't go | |
706 | * backwards as a result of an overflow. | |
707 | * Unconditional branches have a 32-bit offset, | |
708 | * so they could overflow; we check to make | |
709 | * sure they don't. Conditional branches have | |
710 | * an 8-bit offset, and the from address is | |
711 | * less than equal to BPF_MAXINSNS, and we assume that | |
712 | * BPF_MAXINSNS is sufficiently small that adding 255 | |
713 | * to it won't overlflow | |
714 | * | |
715 | * We know that len is <= BPF_MAXINSNS, and we | |
716 | * assume that BPF_MAXINSNS is less than the maximum | |
717 | * size of a u_int, so that i+1 doesn't overflow | |
718 | */ | |
719 | from = i + 1; | |
720 | switch (BPF_OP(p->code)) { | |
721 | case BPF_JA: | |
722 | if (from + p->k < from || from + p->k >= ((u_int)len)) { | |
723 | return 0; | |
724 | } | |
6d2010ae | 725 | break; |
0a7de745 A |
726 | case BPF_JEQ: |
727 | case BPF_JGT: | |
728 | case BPF_JGE: | |
729 | case BPF_JSET: | |
730 | if (from + p->jt >= ((u_int)len) || from + p->jf >= ((u_int)len)) { | |
731 | return 0; | |
732 | } | |
6d2010ae A |
733 | break; |
734 | default: | |
1c79356b | 735 | return 0; |
0a7de745 A |
736 | } |
737 | break; | |
738 | case BPF_RET: | |
739 | break; | |
740 | case BPF_MISC: | |
741 | break; | |
742 | default: | |
743 | return 0; | |
1c79356b | 744 | } |
1c79356b | 745 | } |
0a7de745 | 746 | return BPF_CLASS(f[len - 1].code) == BPF_RET; |
1c79356b A |
747 | } |
748 | #endif |