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