xref: /csrg-svn/sys/net/bpf_filter.c (revision 63211)
151441Smccanne /*
2*63211Sbostic  * Copyright (c) 1990, 1991, 1993
3*63211Sbostic  *	The Regents of the University of California.  All rights reserved.
447585Smccanne  *
549284Sbostic  * This code is derived from the Stanford/CMU enet packet filter,
649284Sbostic  * (net/enet.c) distributed as part of 4.3BSD, and code contributed
751441Smccanne  * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence
851428Smccanne  * Berkeley Laboratory.
949284Sbostic  *
1051441Smccanne  * %sccs.include.redist.c%
1149284Sbostic  *
12*63211Sbostic  *      @(#)bpf_filter.c	8.1 (Berkeley) 06/10/93
1349284Sbostic  *
1449284Sbostic  * static char rcsid[] =
1551428Smccanne  * "$Header: bpf_filter.c,v 1.16 91/10/27 21:22:35 mccanne Exp $";
1647585Smccanne  */
1747585Smccanne 
1848931Smccanne #include <sys/param.h>
1947585Smccanne #include <sys/types.h>
2047585Smccanne #include <sys/time.h>
2147585Smccanne 
2249724Smccanne #ifdef sun
2349724Smccanne #include <netinet/in.h>
2449724Smccanne #endif
2549724Smccanne 
2651428Smccanne #if defined(sparc) || defined(mips) || defined(ibm032)
2753950Smccanne #define BPF_ALIGN
2847585Smccanne #endif
2947585Smccanne 
3053950Smccanne #ifndef BPF_ALIGN
3153950Smccanne #define EXTRACT_SHORT(p)	((u_short)ntohs(*(u_short *)p))
3247585Smccanne #define EXTRACT_LONG(p)		(ntohl(*(u_long *)p))
3347585Smccanne #else
3447585Smccanne #define EXTRACT_SHORT(p)\
3547585Smccanne 	((u_short)\
3653950Smccanne 		((u_short)*((u_char *)p+0)<<8|\
3753950Smccanne 		 (u_short)*((u_char *)p+1)<<0))
3847585Smccanne #define EXTRACT_LONG(p)\
3953950Smccanne 		((u_long)*((u_char *)p+0)<<24|\
4053950Smccanne 		 (u_long)*((u_char *)p+1)<<16|\
4153950Smccanne 		 (u_long)*((u_char *)p+2)<<8|\
4253950Smccanne 		 (u_long)*((u_char *)p+3)<<0)
4347585Smccanne #endif
4447585Smccanne 
4549200Smccanne #ifdef KERNEL
4649200Smccanne #include <sys/mbuf.h>
4749200Smccanne #define MINDEX(m, k) \
4849200Smccanne { \
4949200Smccanne 	register int len = m->m_len; \
5049200Smccanne  \
5149200Smccanne 	while (k >= len) { \
5249200Smccanne 		k -= len; \
5349200Smccanne 		m = m->m_next; \
5449200Smccanne 		if (m == 0) \
5549200Smccanne 			return 0; \
5649200Smccanne 		len = m->m_len; \
5749200Smccanne 	} \
5849200Smccanne }
5949724Smccanne 
6049724Smccanne static int
m_xword(m,k,err)6149724Smccanne m_xword(m, k, err)
6249724Smccanne 	register struct mbuf *m;
6349724Smccanne 	register int k, *err;
6449724Smccanne {
6549724Smccanne 	register int len;
6649724Smccanne 	register u_char *cp, *np;
6749724Smccanne 	register struct mbuf *m0;
6849724Smccanne 
6949724Smccanne 	len = m->m_len;
7049724Smccanne 	while (k >= len) {
7149724Smccanne 		k -= len;
7249724Smccanne 		m = m->m_next;
7349724Smccanne 		if (m == 0)
7449724Smccanne 			goto bad;
7549724Smccanne 		len = m->m_len;
7649724Smccanne 	}
7749724Smccanne 	cp = mtod(m, u_char *) + k;
7849724Smccanne 	if (len - k >= 4) {
7949724Smccanne 		*err = 0;
8049724Smccanne 		return EXTRACT_LONG(cp);
8149724Smccanne 	}
8249724Smccanne 	m0 = m->m_next;
8349724Smccanne 	if (m0 == 0 || m0->m_len + len - k < 4)
8449724Smccanne 		goto bad;
8549724Smccanne 	*err = 0;
8649724Smccanne 	np = mtod(m0, u_char *);
8749724Smccanne 	switch (len - k) {
8849724Smccanne 
8949724Smccanne 	case 1:
9049724Smccanne 		return (cp[k] << 24) | (np[0] << 16) | (np[1] << 8) | np[2];
9149724Smccanne 
9249724Smccanne 	case 2:
9349724Smccanne 		return (cp[k] << 24) | (cp[k + 1] << 16) | (np[0] << 8) |
9449724Smccanne 			np[1];
9549724Smccanne 
9649724Smccanne 	default:
9749724Smccanne 		return (cp[k] << 24) | (cp[k + 1] << 16) | (cp[k + 2] << 8) |
9849724Smccanne 			np[0];
9949724Smccanne 	}
10049724Smccanne     bad:
10149724Smccanne 	*err = 1;
10249724Smccanne 	return 0;
10349724Smccanne }
10449724Smccanne 
10549724Smccanne static int
m_xhalf(m,k,err)10649724Smccanne m_xhalf(m, k, err)
10749724Smccanne 	register struct mbuf *m;
10849724Smccanne 	register int k, *err;
10949724Smccanne {
11049724Smccanne 	register int len;
11151428Smccanne 	register u_char *cp;
11249724Smccanne 	register struct mbuf *m0;
11349724Smccanne 
11449724Smccanne 	len = m->m_len;
11549724Smccanne 	while (k >= len) {
11649724Smccanne 		k -= len;
11749724Smccanne 		m = m->m_next;
11849724Smccanne 		if (m == 0)
11949724Smccanne 			goto bad;
12049724Smccanne 		len = m->m_len;
12149724Smccanne 	}
12249724Smccanne 	cp = mtod(m, u_char *) + k;
12349724Smccanne 	if (len - k >= 2) {
12449724Smccanne 		*err = 0;
12549724Smccanne 		return EXTRACT_SHORT(cp);
12649724Smccanne 	}
12749724Smccanne 	m0 = m->m_next;
12849724Smccanne 	if (m0 == 0)
12949724Smccanne 		goto bad;
13049724Smccanne 	*err = 0;
13149724Smccanne 	return (cp[k] << 8) | mtod(m0, u_char *)[0];
13249724Smccanne  bad:
13349724Smccanne 	*err = 1;
13449724Smccanne 	return 0;
13549724Smccanne }
13649200Smccanne #endif
13749200Smccanne 
13861339Sbostic #include <net/bpf.h>
13947585Smccanne /*
14048969Smccanne  * Execute the filter program starting at pc on the packet p
14148969Smccanne  * wirelen is the length of the original packet
14248969Smccanne  * buflen is the amount of data present
14347585Smccanne  */
14447585Smccanne u_int
bpf_filter(pc,p,wirelen,buflen)14547585Smccanne bpf_filter(pc, p, wirelen, buflen)
14647585Smccanne 	register struct bpf_insn *pc;
14747585Smccanne 	register u_char *p;
14847585Smccanne 	u_int wirelen;
14948969Smccanne 	register u_int buflen;
15047585Smccanne {
15153950Smccanne 	register u_long A, X;
15248969Smccanne 	register int k;
15347585Smccanne 	long mem[BPF_MEMWORDS];
15447585Smccanne 
15547585Smccanne 	if (pc == 0)
15647585Smccanne 		/*
15747585Smccanne 		 * No filter means accept all.
15847585Smccanne 		 */
15948969Smccanne 		return (u_int)-1;
16047585Smccanne #ifdef lint
16147585Smccanne 	A = 0;
16247585Smccanne 	X = 0;
16347585Smccanne #endif
16448969Smccanne 	--pc;
16547585Smccanne 	while (1) {
16648969Smccanne 		++pc;
16747585Smccanne 		switch (pc->code) {
16847585Smccanne 
16947585Smccanne 		default:
17047585Smccanne #ifdef KERNEL
17147585Smccanne 			return 0;
17247585Smccanne #else
17347585Smccanne 			abort();
17447585Smccanne #endif
17548969Smccanne 		case BPF_RET|BPF_K:
17647585Smccanne 			return (u_int)pc->k;
17747585Smccanne 
17848969Smccanne 		case BPF_RET|BPF_A:
17947585Smccanne 			return (u_int)A;
18047585Smccanne 
18148969Smccanne 		case BPF_LD|BPF_W|BPF_ABS:
18248969Smccanne 			k = pc->k;
18349200Smccanne 			if (k + sizeof(long) > buflen) {
18449200Smccanne #ifdef KERNEL
18549724Smccanne 				int merr;
18649200Smccanne 
18749200Smccanne 				if (buflen != 0)
18849200Smccanne 					return 0;
18949724Smccanne 				A = m_xword((struct mbuf *)p, k, &merr);
19049724Smccanne 				if (merr != 0)
19149724Smccanne 					return 0;
19249724Smccanne 				continue;
19349200Smccanne #else
19447585Smccanne 				return 0;
19549200Smccanne #endif
19649200Smccanne 			}
19753950Smccanne #ifdef BPF_ALIGN
19848969Smccanne 			if (((int)(p + k) & 3) != 0)
19948969Smccanne 				A = EXTRACT_LONG(&p[k]);
20048969Smccanne 			else
20148969Smccanne #endif
20253950Smccanne 				A = ntohl(*(long *)(p + k));
20349724Smccanne 			continue;
20447585Smccanne 
20548969Smccanne 		case BPF_LD|BPF_H|BPF_ABS:
20648969Smccanne 			k = pc->k;
20749200Smccanne 			if (k + sizeof(short) > buflen) {
20849200Smccanne #ifdef KERNEL
20949724Smccanne 				int merr;
21049200Smccanne 
21149200Smccanne 				if (buflen != 0)
21249200Smccanne 					return 0;
21349724Smccanne 				A = m_xhalf((struct mbuf *)p, k, &merr);
21449724Smccanne 				continue;
21549200Smccanne #else
21647585Smccanne 				return 0;
21749200Smccanne #endif
21849200Smccanne 			}
21948969Smccanne 			A = EXTRACT_SHORT(&p[k]);
22049724Smccanne 			continue;
22147585Smccanne 
22248969Smccanne 		case BPF_LD|BPF_B|BPF_ABS:
22348969Smccanne 			k = pc->k;
22449200Smccanne 			if (k >= buflen) {
22549200Smccanne #ifdef KERNEL
22649200Smccanne 				register struct mbuf *m;
22749200Smccanne 
22849200Smccanne 				if (buflen != 0)
22949200Smccanne 					return 0;
23049200Smccanne 				m = (struct mbuf *)p;
23149200Smccanne 				MINDEX(m, k);
23249724Smccanne 				A = mtod(m, u_char *)[k];
23349724Smccanne 				continue;
23449200Smccanne #else
23547585Smccanne 				return 0;
23649200Smccanne #endif
23749200Smccanne 			}
23848969Smccanne 			A = p[k];
23949724Smccanne 			continue;
24047585Smccanne 
24148969Smccanne 		case BPF_LD|BPF_W|BPF_LEN:
24247585Smccanne 			A = wirelen;
24349724Smccanne 			continue;
24447585Smccanne 
24548969Smccanne 		case BPF_LDX|BPF_W|BPF_LEN:
24648969Smccanne 			X = wirelen;
24749724Smccanne 			continue;
24848969Smccanne 
24948969Smccanne 		case BPF_LD|BPF_W|BPF_IND:
25048969Smccanne 			k = X + pc->k;
25149200Smccanne 			if (k + sizeof(long) > buflen) {
25249200Smccanne #ifdef KERNEL
25349724Smccanne 				int merr;
25449200Smccanne 
25549200Smccanne 				if (buflen != 0)
25649200Smccanne 					return 0;
25749724Smccanne 				A = m_xword((struct mbuf *)p, k, &merr);
25849724Smccanne 				if (merr != 0)
25949724Smccanne 					return 0;
26049724Smccanne 				continue;
26149200Smccanne #else
26247585Smccanne 				return 0;
26349200Smccanne #endif
26449200Smccanne 			}
26553950Smccanne #ifdef BPF_ALIGN
26648969Smccanne 			if (((int)(p + k) & 3) != 0)
26748969Smccanne 				A = EXTRACT_LONG(&p[k]);
26848969Smccanne 			else
26948969Smccanne #endif
27053950Smccanne 				A = ntohl(*(long *)(p + k));
27149724Smccanne 			continue;
27247585Smccanne 
27348969Smccanne 		case BPF_LD|BPF_H|BPF_IND:
27448969Smccanne 			k = X + pc->k;
27549200Smccanne 			if (k + sizeof(short) > buflen) {
27649200Smccanne #ifdef KERNEL
27749724Smccanne 				int merr;
27849200Smccanne 
27949200Smccanne 				if (buflen != 0)
28049200Smccanne 					return 0;
28149724Smccanne 				A = m_xhalf((struct mbuf *)p, k, &merr);
28249724Smccanne 				if (merr != 0)
28349724Smccanne 					return 0;
28449724Smccanne 				continue;
28549200Smccanne #else
28647585Smccanne 				return 0;
28749200Smccanne #endif
28849200Smccanne 			}
28948969Smccanne 			A = EXTRACT_SHORT(&p[k]);
29049724Smccanne 			continue;
29147585Smccanne 
29248969Smccanne 		case BPF_LD|BPF_B|BPF_IND:
29348969Smccanne 			k = X + pc->k;
29449200Smccanne 			if (k >= buflen) {
29549200Smccanne #ifdef KERNEL
29649200Smccanne 				register struct mbuf *m;
29749200Smccanne 
29849200Smccanne 				if (buflen != 0)
29949200Smccanne 					return 0;
30049200Smccanne 				m = (struct mbuf *)p;
30149200Smccanne 				MINDEX(m, k);
30249200Smccanne 				A = mtod(m, char *)[k];
30349724Smccanne 				continue;
30449200Smccanne #else
30547585Smccanne 				return 0;
30649200Smccanne #endif
30749200Smccanne 			}
30848969Smccanne 			A = p[k];
30949724Smccanne 			continue;
31047585Smccanne 
31149200Smccanne 		case BPF_LDX|BPF_MSH|BPF_B:
31249200Smccanne 			k = pc->k;
31349200Smccanne 			if (k >= buflen) {
31449200Smccanne #ifdef KERNEL
31549200Smccanne 				register struct mbuf *m;
31649200Smccanne 
31749200Smccanne 				if (buflen != 0)
31849200Smccanne 					return 0;
31949200Smccanne 				m = (struct mbuf *)p;
32049200Smccanne 				MINDEX(m, k);
32149200Smccanne 				X = (mtod(m, char *)[k] & 0xf) << 2;
32249724Smccanne 				continue;
32349200Smccanne #else
32449200Smccanne 				return 0;
32549200Smccanne #endif
32649200Smccanne 			}
32749200Smccanne 			X = (p[pc->k] & 0xf) << 2;
32849724Smccanne 			continue;
32949200Smccanne 
33048969Smccanne 		case BPF_LD|BPF_IMM:
33147585Smccanne 			A = pc->k;
33249724Smccanne 			continue;
33347585Smccanne 
33448969Smccanne 		case BPF_LDX|BPF_IMM:
33547585Smccanne 			X = pc->k;
33649724Smccanne 			continue;
33747585Smccanne 
33848969Smccanne 		case BPF_LD|BPF_MEM:
33948969Smccanne 			A = mem[pc->k];
34049724Smccanne 			continue;
34148969Smccanne 
34248969Smccanne 		case BPF_LDX|BPF_MEM:
34348969Smccanne 			X = mem[pc->k];
34449724Smccanne 			continue;
34547585Smccanne 
34648969Smccanne 		case BPF_ST:
34747585Smccanne 			mem[pc->k] = A;
34849724Smccanne 			continue;
34947585Smccanne 
35048969Smccanne 		case BPF_STX:
35147585Smccanne 			mem[pc->k] = X;
35249724Smccanne 			continue;
35347585Smccanne 
35448969Smccanne 		case BPF_JMP|BPF_JA:
35548969Smccanne 			pc += pc->k;
35649724Smccanne 			continue;
35747585Smccanne 
35848969Smccanne 		case BPF_JMP|BPF_JGT|BPF_K:
35948969Smccanne 			pc += (A > pc->k) ? pc->jt : pc->jf;
36049724Smccanne 			continue;
36147585Smccanne 
36248969Smccanne 		case BPF_JMP|BPF_JGE|BPF_K:
36348969Smccanne 			pc += (A >= pc->k) ? pc->jt : pc->jf;
36449724Smccanne 			continue;
36547585Smccanne 
36648969Smccanne 		case BPF_JMP|BPF_JEQ|BPF_K:
36748969Smccanne 			pc += (A == pc->k) ? pc->jt : pc->jf;
36849724Smccanne 			continue;
36947585Smccanne 
37048969Smccanne 		case BPF_JMP|BPF_JSET|BPF_K:
37148969Smccanne 			pc += (A & pc->k) ? pc->jt : pc->jf;
37249724Smccanne 			continue;
37347585Smccanne 
37448969Smccanne 		case BPF_JMP|BPF_JGT|BPF_X:
37548969Smccanne 			pc += (A > X) ? pc->jt : pc->jf;
37649724Smccanne 			continue;
37748969Smccanne 
37848969Smccanne 		case BPF_JMP|BPF_JGE|BPF_X:
37948969Smccanne 			pc += (A >= X) ? pc->jt : pc->jf;
38049724Smccanne 			continue;
38148969Smccanne 
38248969Smccanne 		case BPF_JMP|BPF_JEQ|BPF_X:
38348969Smccanne 			pc += (A == X) ? pc->jt : pc->jf;
38449724Smccanne 			continue;
38548969Smccanne 
38648969Smccanne 		case BPF_JMP|BPF_JSET|BPF_X:
38748969Smccanne 			pc += (A & X) ? pc->jt : pc->jf;
38849724Smccanne 			continue;
38948969Smccanne 
39048969Smccanne 		case BPF_ALU|BPF_ADD|BPF_X:
39147585Smccanne 			A += X;
39249724Smccanne 			continue;
39347585Smccanne 
39448969Smccanne 		case BPF_ALU|BPF_SUB|BPF_X:
39547585Smccanne 			A -= X;
39649724Smccanne 			continue;
39747585Smccanne 
39848969Smccanne 		case BPF_ALU|BPF_MUL|BPF_X:
39947585Smccanne 			A *= X;
40049724Smccanne 			continue;
40147585Smccanne 
40248969Smccanne 		case BPF_ALU|BPF_DIV|BPF_X:
40347585Smccanne 			if (X == 0)
40447585Smccanne 				return 0;
40547585Smccanne 			A /= X;
40649724Smccanne 			continue;
40747585Smccanne 
40848969Smccanne 		case BPF_ALU|BPF_AND|BPF_X:
40947585Smccanne 			A &= X;
41049724Smccanne 			continue;
41147585Smccanne 
41248969Smccanne 		case BPF_ALU|BPF_OR|BPF_X:
41347585Smccanne 			A |= X;
41449724Smccanne 			continue;
41547585Smccanne 
41648969Smccanne 		case BPF_ALU|BPF_LSH|BPF_X:
41747585Smccanne 			A <<= X;
41849724Smccanne 			continue;
41947585Smccanne 
42048969Smccanne 		case BPF_ALU|BPF_RSH|BPF_X:
42147585Smccanne 			A >>= X;
42249724Smccanne 			continue;
42347585Smccanne 
42448969Smccanne 		case BPF_ALU|BPF_ADD|BPF_K:
42547585Smccanne 			A += pc->k;
42649724Smccanne 			continue;
42747585Smccanne 
42848969Smccanne 		case BPF_ALU|BPF_SUB|BPF_K:
42947585Smccanne 			A -= pc->k;
43049724Smccanne 			continue;
43147585Smccanne 
43248969Smccanne 		case BPF_ALU|BPF_MUL|BPF_K:
43347585Smccanne 			A *= pc->k;
43449724Smccanne 			continue;
43547585Smccanne 
43648969Smccanne 		case BPF_ALU|BPF_DIV|BPF_K:
43747585Smccanne 			A /= pc->k;
43849724Smccanne 			continue;
43947585Smccanne 
44048969Smccanne 		case BPF_ALU|BPF_AND|BPF_K:
44147585Smccanne 			A &= pc->k;
44249724Smccanne 			continue;
44347585Smccanne 
44448969Smccanne 		case BPF_ALU|BPF_OR|BPF_K:
44547585Smccanne 			A |= pc->k;
44649724Smccanne 			continue;
44747585Smccanne 
44848969Smccanne 		case BPF_ALU|BPF_LSH|BPF_K:
44947585Smccanne 			A <<= pc->k;
45049724Smccanne 			continue;
45147585Smccanne 
45248969Smccanne 		case BPF_ALU|BPF_RSH|BPF_K:
45347585Smccanne 			A >>= pc->k;
45449724Smccanne 			continue;
45547585Smccanne 
45648969Smccanne 		case BPF_ALU|BPF_NEG:
45747585Smccanne 			A = -A;
45849724Smccanne 			continue;
45948969Smccanne 
46048969Smccanne 		case BPF_MISC|BPF_TAX:
46148969Smccanne 			X = A;
46249724Smccanne 			continue;
46348969Smccanne 
46448969Smccanne 		case BPF_MISC|BPF_TXA:
46548969Smccanne 			A = X;
46649724Smccanne 			continue;
46747585Smccanne 		}
46847585Smccanne 	}
46947585Smccanne }
47047585Smccanne 
47147585Smccanne #ifdef KERNEL
47247585Smccanne /*
47347585Smccanne  * Return true if the 'fcode' is a valid filter program.
47447585Smccanne  * The constraints are that each jump be forward and to a valid
47547585Smccanne  * code.  The code must terminate with either an accept or reject.
47647585Smccanne  * 'valid' is an array for use by the routine (it must be at least
47747585Smccanne  * 'len' bytes long).
47847585Smccanne  *
47947585Smccanne  * The kernel needs to be able to verify an application's filter code.
48047585Smccanne  * Otherwise, a bogus program could easily crash the system.
48147585Smccanne  */
48247585Smccanne int
bpf_validate(f,len)48348969Smccanne bpf_validate(f, len)
48448969Smccanne 	struct bpf_insn *f;
48547585Smccanne 	int len;
48647585Smccanne {
48748969Smccanne 	register int i;
48848969Smccanne 	register struct bpf_insn *p;
48947585Smccanne 
49048969Smccanne 	for (i = 0; i < len; ++i) {
49147585Smccanne 		/*
49247585Smccanne 		 * Check that that jumps are forward, and within
49347585Smccanne 		 * the code block.
49447585Smccanne 		 */
49548969Smccanne 		p = &f[i];
49648969Smccanne 		if (BPF_CLASS(p->code) == BPF_JMP) {
49748969Smccanne 			register int from = i + 1;
49848969Smccanne 
49948969Smccanne 			if (BPF_OP(p->code) == BPF_JA) {
50048969Smccanne 				if (from + p->k >= len)
50148969Smccanne 					return 0;
50248969Smccanne 			}
50348969Smccanne 			else if (from + p->jt >= len || from + p->jf >= len)
50448969Smccanne 				return 0;
50548969Smccanne 		}
50647585Smccanne 		/*
50747585Smccanne 		 * Check that memory operations use valid addresses.
50847585Smccanne 		 */
50948969Smccanne 		if ((BPF_CLASS(p->code) == BPF_ST ||
51048969Smccanne 		     (BPF_CLASS(p->code) == BPF_LD &&
51148969Smccanne 		      (p->code & 0xe0) == BPF_MEM)) &&
51248969Smccanne 		    (p->k >= BPF_MEMWORDS || p->k < 0))
51348969Smccanne 			return 0;
51448969Smccanne 		/*
51548969Smccanne 		 * Check for constant division by 0.
51648969Smccanne 		 */
51751428Smccanne 		if (p->code == (BPF_ALU|BPF_DIV|BPF_K) && p->k == 0)
51851428Smccanne 			return 0;
51947585Smccanne 	}
52048969Smccanne 	return BPF_CLASS(f[len - 1].code) == BPF_RET;
52147585Smccanne }
52247585Smccanne #endif
523