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