bpf_filter.c revision 41571
1/*
2 * Copyright (c) 1990, 1991, 1993
3 *	The Regents of the University of California.  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 and Van Jacobson both of Lawrence
8 * Berkeley Laboratory.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 *    must display the following acknowledgement:
20 *	This product includes software developed by the University of
21 *	California, Berkeley and its contributors.
22 * 4. Neither the name of the University nor the names of its contributors
23 *    may be used to endorse or promote products derived from this software
24 *    without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
37 *
38 *      @(#)bpf_filter.c	8.1 (Berkeley) 6/10/93
39 *
40 * $Id: bpf_filter.c,v 1.10 1998/10/31 10:45:03 dfr Exp $
41 */
42
43#include <sys/param.h>
44
45#ifdef sun
46#include <netinet/in.h>
47#endif
48
49#if defined(sparc) || defined(mips) || defined(ibm032) || defined(__alpha__)
50#define BPF_ALIGN
51#endif
52
53#ifndef BPF_ALIGN
54#define EXTRACT_SHORT(p)	((u_int16_t)ntohs(*(u_int16_t *)p))
55#define EXTRACT_LONG(p)		(ntohl(*(u_int32_t *)p))
56#else
57#define EXTRACT_SHORT(p)\
58	((u_int16_t)\
59		((u_int16_t)*((u_char *)p+0)<<8|\
60		 (u_int16_t)*((u_char *)p+1)<<0))
61#define EXTRACT_LONG(p)\
62		((u_int32_t)*((u_char *)p+0)<<24|\
63		 (u_int32_t)*((u_char *)p+1)<<16|\
64		 (u_int32_t)*((u_char *)p+2)<<8|\
65		 (u_int32_t)*((u_char *)p+3)<<0)
66#endif
67
68#ifdef KERNEL
69#include <sys/mbuf.h>
70#define MINDEX(m, k) \
71{ \
72	register int len = m->m_len; \
73 \
74	while (k >= len) { \
75		k -= len; \
76		m = m->m_next; \
77		if (m == 0) \
78			return 0; \
79		len = m->m_len; \
80	} \
81}
82
83static int	m_xhalf __P((struct mbuf *m, int k, int *err));
84static int	m_xword __P((struct mbuf *m, int k, int *err));
85
86static int
87m_xword(m, k, err)
88	register struct mbuf *m;
89	register int k, *err;
90{
91	register int len;
92	register u_char *cp, *np;
93	register struct mbuf *m0;
94
95	len = m->m_len;
96	while (k >= len) {
97		k -= len;
98		m = m->m_next;
99		if (m == 0)
100			goto bad;
101		len = m->m_len;
102	}
103	cp = mtod(m, u_char *) + k;
104	if (len - k >= 4) {
105		*err = 0;
106		return EXTRACT_LONG(cp);
107	}
108	m0 = m->m_next;
109	if (m0 == 0 || m0->m_len + len - k < 4)
110		goto bad;
111	*err = 0;
112	np = mtod(m0, u_char *);
113	switch (len - k) {
114
115	case 1:
116		return (cp[0] << 24) | (np[0] << 16) | (np[1] << 8) | np[2];
117
118	case 2:
119		return (cp[0] << 24) | (cp[1] << 16) | (np[0] << 8) |
120			np[1];
121
122	default:
123		return (cp[0] << 24) | (cp[1] << 16) | (cp[2] << 8) |
124			np[0];
125	}
126    bad:
127	*err = 1;
128	return 0;
129}
130
131static int
132m_xhalf(m, k, err)
133	register struct mbuf *m;
134	register int k, *err;
135{
136	register int len;
137	register u_char *cp;
138	register struct mbuf *m0;
139
140	len = m->m_len;
141	while (k >= len) {
142		k -= len;
143		m = m->m_next;
144		if (m == 0)
145			goto bad;
146		len = m->m_len;
147	}
148	cp = mtod(m, u_char *) + k;
149	if (len - k >= 2) {
150		*err = 0;
151		return EXTRACT_SHORT(cp);
152	}
153	m0 = m->m_next;
154	if (m0 == 0)
155		goto bad;
156	*err = 0;
157	return (cp[0] << 8) | mtod(m0, u_char *)[0];
158 bad:
159	*err = 1;
160	return 0;
161}
162#endif
163
164#include <net/bpf.h>
165/*
166 * Execute the filter program starting at pc on the packet p
167 * wirelen is the length of the original packet
168 * buflen is the amount of data present
169 */
170u_int
171bpf_filter(pc, p, wirelen, buflen)
172	register struct bpf_insn *pc;
173	register u_char *p;
174	u_int wirelen;
175	register u_int buflen;
176{
177	register u_int32_t A = 0, X = 0;
178	register int k;
179	int32_t mem[BPF_MEMWORDS];
180
181	if (pc == 0)
182		/*
183		 * No filter means accept all.
184		 */
185		return (u_int)-1;
186
187	--pc;
188	while (1) {
189		++pc;
190		switch (pc->code) {
191
192		default:
193#ifdef KERNEL
194			return 0;
195#else
196			abort();
197#endif
198		case BPF_RET|BPF_K:
199			return (u_int)pc->k;
200
201		case BPF_RET|BPF_A:
202			return (u_int)A;
203
204		case BPF_LD|BPF_W|BPF_ABS:
205			k = pc->k;
206			if (k + sizeof(int32_t) > buflen) {
207#ifdef KERNEL
208				int merr;
209
210				if (buflen != 0)
211					return 0;
212				A = m_xword((struct mbuf *)p, k, &merr);
213				if (merr != 0)
214					return 0;
215				continue;
216#else
217				return 0;
218#endif
219			}
220#ifdef BPF_ALIGN
221			if (((intptr_t)(p + k) & 3) != 0)
222				A = EXTRACT_LONG(&p[k]);
223			else
224#endif
225				A = ntohl(*(int32_t *)(p + k));
226			continue;
227
228		case BPF_LD|BPF_H|BPF_ABS:
229			k = pc->k;
230			if (k + sizeof(int16_t) > buflen) {
231#ifdef KERNEL
232				int merr;
233
234				if (buflen != 0)
235					return 0;
236				A = m_xhalf((struct mbuf *)p, k, &merr);
237				continue;
238#else
239				return 0;
240#endif
241			}
242			A = EXTRACT_SHORT(&p[k]);
243			continue;
244
245		case BPF_LD|BPF_B|BPF_ABS:
246			k = pc->k;
247			if (k >= buflen) {
248#ifdef KERNEL
249				register struct mbuf *m;
250
251				if (buflen != 0)
252					return 0;
253				m = (struct mbuf *)p;
254				MINDEX(m, k);
255				A = mtod(m, u_char *)[k];
256				continue;
257#else
258				return 0;
259#endif
260			}
261			A = p[k];
262			continue;
263
264		case BPF_LD|BPF_W|BPF_LEN:
265			A = wirelen;
266			continue;
267
268		case BPF_LDX|BPF_W|BPF_LEN:
269			X = wirelen;
270			continue;
271
272		case BPF_LD|BPF_W|BPF_IND:
273			k = X + pc->k;
274			if (k + sizeof(int32_t) > buflen) {
275#ifdef KERNEL
276				int merr;
277
278				if (buflen != 0)
279					return 0;
280				A = m_xword((struct mbuf *)p, k, &merr);
281				if (merr != 0)
282					return 0;
283				continue;
284#else
285				return 0;
286#endif
287			}
288#ifdef BPF_ALIGN
289			if (((intptr_t)(p + k) & 3) != 0)
290				A = EXTRACT_LONG(&p[k]);
291			else
292#endif
293				A = ntohl(*(int32_t *)(p + k));
294			continue;
295
296		case BPF_LD|BPF_H|BPF_IND:
297			k = X + pc->k;
298			if (k + sizeof(int16_t) > buflen) {
299#ifdef KERNEL
300				int merr;
301
302				if (buflen != 0)
303					return 0;
304				A = m_xhalf((struct mbuf *)p, k, &merr);
305				if (merr != 0)
306					return 0;
307				continue;
308#else
309				return 0;
310#endif
311			}
312			A = EXTRACT_SHORT(&p[k]);
313			continue;
314
315		case BPF_LD|BPF_B|BPF_IND:
316			k = X + pc->k;
317			if (k >= buflen) {
318#ifdef KERNEL
319				register struct mbuf *m;
320
321				if (buflen != 0)
322					return 0;
323				m = (struct mbuf *)p;
324				MINDEX(m, k);
325				A = mtod(m, char *)[k];
326				continue;
327#else
328				return 0;
329#endif
330			}
331			A = p[k];
332			continue;
333
334		case BPF_LDX|BPF_MSH|BPF_B:
335			k = pc->k;
336			if (k >= buflen) {
337#ifdef KERNEL
338				register struct mbuf *m;
339
340				if (buflen != 0)
341					return 0;
342				m = (struct mbuf *)p;
343				MINDEX(m, k);
344				X = (mtod(m, char *)[k] & 0xf) << 2;
345				continue;
346#else
347				return 0;
348#endif
349			}
350			X = (p[pc->k] & 0xf) << 2;
351			continue;
352
353		case BPF_LD|BPF_IMM:
354			A = pc->k;
355			continue;
356
357		case BPF_LDX|BPF_IMM:
358			X = pc->k;
359			continue;
360
361		case BPF_LD|BPF_MEM:
362			A = mem[pc->k];
363			continue;
364
365		case BPF_LDX|BPF_MEM:
366			X = mem[pc->k];
367			continue;
368
369		case BPF_ST:
370			mem[pc->k] = A;
371			continue;
372
373		case BPF_STX:
374			mem[pc->k] = X;
375			continue;
376
377		case BPF_JMP|BPF_JA:
378			pc += pc->k;
379			continue;
380
381		case BPF_JMP|BPF_JGT|BPF_K:
382			pc += (A > pc->k) ? pc->jt : pc->jf;
383			continue;
384
385		case BPF_JMP|BPF_JGE|BPF_K:
386			pc += (A >= pc->k) ? pc->jt : pc->jf;
387			continue;
388
389		case BPF_JMP|BPF_JEQ|BPF_K:
390			pc += (A == pc->k) ? pc->jt : pc->jf;
391			continue;
392
393		case BPF_JMP|BPF_JSET|BPF_K:
394			pc += (A & pc->k) ? pc->jt : pc->jf;
395			continue;
396
397		case BPF_JMP|BPF_JGT|BPF_X:
398			pc += (A > X) ? pc->jt : pc->jf;
399			continue;
400
401		case BPF_JMP|BPF_JGE|BPF_X:
402			pc += (A >= X) ? pc->jt : pc->jf;
403			continue;
404
405		case BPF_JMP|BPF_JEQ|BPF_X:
406			pc += (A == X) ? pc->jt : pc->jf;
407			continue;
408
409		case BPF_JMP|BPF_JSET|BPF_X:
410			pc += (A & X) ? pc->jt : pc->jf;
411			continue;
412
413		case BPF_ALU|BPF_ADD|BPF_X:
414			A += X;
415			continue;
416
417		case BPF_ALU|BPF_SUB|BPF_X:
418			A -= X;
419			continue;
420
421		case BPF_ALU|BPF_MUL|BPF_X:
422			A *= X;
423			continue;
424
425		case BPF_ALU|BPF_DIV|BPF_X:
426			if (X == 0)
427				return 0;
428			A /= X;
429			continue;
430
431		case BPF_ALU|BPF_AND|BPF_X:
432			A &= X;
433			continue;
434
435		case BPF_ALU|BPF_OR|BPF_X:
436			A |= X;
437			continue;
438
439		case BPF_ALU|BPF_LSH|BPF_X:
440			A <<= X;
441			continue;
442
443		case BPF_ALU|BPF_RSH|BPF_X:
444			A >>= X;
445			continue;
446
447		case BPF_ALU|BPF_ADD|BPF_K:
448			A += pc->k;
449			continue;
450
451		case BPF_ALU|BPF_SUB|BPF_K:
452			A -= pc->k;
453			continue;
454
455		case BPF_ALU|BPF_MUL|BPF_K:
456			A *= pc->k;
457			continue;
458
459		case BPF_ALU|BPF_DIV|BPF_K:
460			A /= pc->k;
461			continue;
462
463		case BPF_ALU|BPF_AND|BPF_K:
464			A &= pc->k;
465			continue;
466
467		case BPF_ALU|BPF_OR|BPF_K:
468			A |= pc->k;
469			continue;
470
471		case BPF_ALU|BPF_LSH|BPF_K:
472			A <<= pc->k;
473			continue;
474
475		case BPF_ALU|BPF_RSH|BPF_K:
476			A >>= pc->k;
477			continue;
478
479		case BPF_ALU|BPF_NEG:
480			A = -A;
481			continue;
482
483		case BPF_MISC|BPF_TAX:
484			X = A;
485			continue;
486
487		case BPF_MISC|BPF_TXA:
488			A = X;
489			continue;
490		}
491	}
492}
493
494#ifdef KERNEL
495/*
496 * Return true if the 'fcode' is a valid filter program.
497 * The constraints are that each jump be forward and to a valid
498 * code.  The code must terminate with either an accept or reject.
499 * 'valid' is an array for use by the routine (it must be at least
500 * 'len' bytes long).
501 *
502 * The kernel needs to be able to verify an application's filter code.
503 * Otherwise, a bogus program could easily crash the system.
504 */
505int
506bpf_validate(f, len)
507	struct bpf_insn *f;
508	int len;
509{
510	register int i;
511	register struct bpf_insn *p;
512
513	for (i = 0; i < len; ++i) {
514		/*
515		 * Check that that jumps are forward, and within
516		 * the code block.
517		 */
518		p = &f[i];
519		if (BPF_CLASS(p->code) == BPF_JMP) {
520			register int from = i + 1;
521
522			if (BPF_OP(p->code) == BPF_JA) {
523				if (from + p->k >= len)
524					return 0;
525			}
526			else if (from + p->jt >= len || from + p->jf >= len)
527				return 0;
528		}
529		/*
530		 * Check that memory operations use valid addresses.
531		 */
532		if ((BPF_CLASS(p->code) == BPF_ST ||
533		     (BPF_CLASS(p->code) == BPF_LD &&
534		      (p->code & 0xe0) == BPF_MEM)) &&
535		    (p->k >= BPF_MEMWORDS))
536			return 0;
537		/*
538		 * Check for constant division by 0.
539		 */
540		if (p->code == (BPF_ALU|BPF_DIV|BPF_K) && p->k == 0)
541			return 0;
542	}
543	return BPF_CLASS(f[len - 1].code) == BPF_RET;
544}
545#endif
546