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