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