1145519Sdarrenr/*	$FreeBSD$	*/
2145510Sdarrenr
3145510Sdarrenr/*-
4145510Sdarrenr * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997
5145510Sdarrenr *	The Regents of the University of California.  All rights reserved.
6145510Sdarrenr *
7145510Sdarrenr * This code is derived from the Stanford/CMU enet packet filter,
8145510Sdarrenr * (net/enet.c) distributed as part of 4.3BSD, and code contributed
9145510Sdarrenr * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence
10145510Sdarrenr * Berkeley Laboratory.
11145510Sdarrenr *
12145510Sdarrenr * Redistribution and use in source and binary forms, with or without
13145510Sdarrenr * modification, are permitted provided that the following conditions
14145510Sdarrenr * are met:
15145510Sdarrenr * 1. Redistributions of source code must retain the above copyright
16145510Sdarrenr *    notice, this list of conditions and the following disclaimer.
17145510Sdarrenr * 2. Redistributions in binary form must reproduce the above copyright
18145510Sdarrenr *    notice, this list of conditions and the following disclaimer in the
19145510Sdarrenr *    documentation and/or other materials provided with the distribution.
20145510Sdarrenr * 3. All advertising materials mentioning features or use of this software
21145510Sdarrenr *    must display the following acknowledgement:
22145510Sdarrenr *	This product includes software developed by the University of
23145510Sdarrenr *	California, Berkeley and its contributors.
24145510Sdarrenr * 4. Neither the name of the University nor the names of its contributors
25145510Sdarrenr *    may be used to endorse or promote products derived from this software
26145510Sdarrenr *    without specific prior written permission.
27145510Sdarrenr *
28145510Sdarrenr * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29145510Sdarrenr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30145510Sdarrenr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31145510Sdarrenr * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32145510Sdarrenr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33145510Sdarrenr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34145510Sdarrenr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35145510Sdarrenr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36145510Sdarrenr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37145510Sdarrenr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38145510Sdarrenr * SUCH DAMAGE.
39145510Sdarrenr *
40145510Sdarrenr *	@(#)bpf.c	7.5 (Berkeley) 7/15/91
41145510Sdarrenr */
42145510Sdarrenr
43145510Sdarrenr#if !(defined(lint) || defined(KERNEL) || defined(_KERNEL))
44145510Sdarrenrstatic const char rcsid[] =
45170268Sdarrenr    "@(#) $Header: /devel/CVS/IP-Filter/bpf_filter.c,v 2.2.2.3 2006/10/03 11:25:56 darrenr Exp $ (LBL)";
46145510Sdarrenr#endif
47145510Sdarrenr
48145510Sdarrenr#include <sys/param.h>
49145510Sdarrenr#include <sys/types.h>
50145510Sdarrenr#include <sys/time.h>
51145510Sdarrenr#include <sys/socket.h>
52145510Sdarrenr
53145510Sdarrenr#include <netinet/in.h>
54145510Sdarrenr#include <net/if.h>
55145510Sdarrenr
56145554Sdarrenr#include "netinet/ip_compat.h"
57145510Sdarrenr#include "bpf-ipf.h"
58145510Sdarrenr
59145510Sdarrenr
60145510Sdarrenr#if (defined(__hpux) || SOLARIS) && (defined(_KERNEL) || defined(KERNEL))
61145510Sdarrenr# include <sys/sysmacros.h>
62145510Sdarrenr# include <sys/stream.h>
63145510Sdarrenr#endif
64145510Sdarrenr
65145510Sdarrenr#include "pcap-ipf.h"
66145510Sdarrenr
67145510Sdarrenr#if !defined(KERNEL) && !defined(_KERNEL)
68145510Sdarrenr#include <stdlib.h>
69145510Sdarrenr#endif
70145510Sdarrenr
71145510Sdarrenr#define int32 bpf_int32
72145510Sdarrenr#define u_int32 bpf_u_int32
73145510Sdarrenr
74145510Sdarrenrstatic int m_xword __P((mb_t *, int, int *));
75145510Sdarrenrstatic int m_xhalf __P((mb_t *, int, int *));
76145510Sdarrenr
77145510Sdarrenr#ifndef LBL_ALIGN
78145510Sdarrenr/*
79145510Sdarrenr * XXX - IA-64?  If not, this probably won't work on Win64 IA-64
80145510Sdarrenr * systems, unless LBL_ALIGN is defined elsewhere for them.
81145510Sdarrenr * XXX - SuperH?  If not, this probably won't work on WinCE SuperH
82145510Sdarrenr * systems, unless LBL_ALIGN is defined elsewhere for them.
83145510Sdarrenr */
84145510Sdarrenr#if defined(sparc) || defined(__sparc__) || defined(mips) || \
85145510Sdarrenr    defined(ibm032) || defined(__alpha) || defined(__hpux) || \
86145510Sdarrenr    defined(__arm__)
87145510Sdarrenr#define LBL_ALIGN
88145510Sdarrenr#endif
89145510Sdarrenr#endif
90145510Sdarrenr
91145510Sdarrenr#ifndef LBL_ALIGN
92145510Sdarrenr
93145510Sdarrenr#define EXTRACT_SHORT(p)	((u_short)ntohs(*(u_short *)p))
94145510Sdarrenr#define EXTRACT_LONG(p)		(ntohl(*(u_int32 *)p))
95145510Sdarrenr#else
96145510Sdarrenr#define EXTRACT_SHORT(p)\
97145510Sdarrenr	((u_short)\
98145510Sdarrenr		((u_short)*((u_char *)p+0)<<8|\
99145510Sdarrenr		 (u_short)*((u_char *)p+1)<<0))
100145510Sdarrenr#define EXTRACT_LONG(p)\
101145510Sdarrenr		((u_int32)*((u_char *)p+0)<<24|\
102145510Sdarrenr		 (u_int32)*((u_char *)p+1)<<16|\
103145510Sdarrenr		 (u_int32)*((u_char *)p+2)<<8|\
104145510Sdarrenr		 (u_int32)*((u_char *)p+3)<<0)
105145510Sdarrenr#endif
106145510Sdarrenr
107145510Sdarrenr#define MINDEX(len, _m, _k) \
108145510Sdarrenr{ \
109145510Sdarrenr	len = M_LEN(m); \
110145510Sdarrenr	while ((_k) >= len) { \
111145510Sdarrenr		(_k) -= len; \
112145510Sdarrenr		(_m) = (_m)->m_next; \
113145510Sdarrenr		if ((_m) == 0) \
114145510Sdarrenr			return 0; \
115145510Sdarrenr		len = M_LEN(m); \
116145510Sdarrenr	} \
117145510Sdarrenr}
118145510Sdarrenr
119145510Sdarrenrstatic int
120145510Sdarrenrm_xword(m, k, err)
121145510Sdarrenr	register mb_t *m;
122145510Sdarrenr	register int k, *err;
123145510Sdarrenr{
124145510Sdarrenr	register int len;
125145510Sdarrenr	register u_char *cp, *np;
126145510Sdarrenr	register mb_t *m0;
127145510Sdarrenr
128145510Sdarrenr	MINDEX(len, m, k);
129145510Sdarrenr	cp = MTOD(m, u_char *) + k;
130145510Sdarrenr	if (len - k >= 4) {
131145510Sdarrenr		*err = 0;
132145510Sdarrenr		return EXTRACT_LONG(cp);
133145510Sdarrenr	}
134145510Sdarrenr	m0 = m->m_next;
135145510Sdarrenr	if (m0 == 0 || M_LEN(m0) + len - k < 4)
136145510Sdarrenr		goto bad;
137145510Sdarrenr	*err = 0;
138145510Sdarrenr	np = MTOD(m0, u_char *);
139145510Sdarrenr	switch (len - k) {
140145510Sdarrenr
141145510Sdarrenr	case 1:
142145510Sdarrenr		return (cp[0] << 24) | (np[0] << 16) | (np[1] << 8) | np[2];
143145510Sdarrenr
144145510Sdarrenr	case 2:
145145510Sdarrenr		return (cp[0] << 24) | (cp[1] << 16) | (np[0] << 8) | np[1];
146145510Sdarrenr
147145510Sdarrenr	default:
148145510Sdarrenr		return (cp[0] << 24) | (cp[1] << 16) | (cp[2] << 8) | np[0];
149145510Sdarrenr	}
150145510Sdarrenr    bad:
151145510Sdarrenr	*err = 1;
152145510Sdarrenr	return 0;
153145510Sdarrenr}
154145510Sdarrenr
155145510Sdarrenrstatic int
156145510Sdarrenrm_xhalf(m, k, err)
157145510Sdarrenr	register mb_t *m;
158145510Sdarrenr	register int k, *err;
159145510Sdarrenr{
160145510Sdarrenr	register int len;
161145510Sdarrenr	register u_char *cp;
162145510Sdarrenr	register mb_t *m0;
163145510Sdarrenr
164145510Sdarrenr	MINDEX(len, m, k);
165145510Sdarrenr	cp = MTOD(m, u_char *) + k;
166145510Sdarrenr	if (len - k >= 2) {
167145510Sdarrenr		*err = 0;
168145510Sdarrenr		return EXTRACT_SHORT(cp);
169145510Sdarrenr	}
170145510Sdarrenr	m0 = m->m_next;
171145510Sdarrenr	if (m0 == 0)
172145510Sdarrenr		goto bad;
173145510Sdarrenr	*err = 0;
174145510Sdarrenr	return (cp[0] << 8) | MTOD(m0, u_char *)[0];
175145510Sdarrenr bad:
176145510Sdarrenr	*err = 1;
177145510Sdarrenr	return 0;
178145510Sdarrenr}
179145510Sdarrenr
180145510Sdarrenr/*
181145510Sdarrenr * Execute the filter program starting at pc on the packet p
182145510Sdarrenr * wirelen is the length of the original packet
183145510Sdarrenr * buflen is the amount of data present
184145510Sdarrenr * For the kernel, p is assumed to be a pointer to an mbuf if buflen is 0,
185145510Sdarrenr * in all other cases, p is a pointer to a buffer and buflen is its size.
186145510Sdarrenr */
187145510Sdarrenru_int
188145510Sdarrenrbpf_filter(pc, p, wirelen, buflen)
189145510Sdarrenr	register struct bpf_insn *pc;
190145510Sdarrenr	register u_char *p;
191145510Sdarrenr	u_int wirelen;
192145510Sdarrenr	register u_int buflen;
193145510Sdarrenr{
194145510Sdarrenr	register u_int32 A, X;
195145510Sdarrenr	register int k;
196145510Sdarrenr	int32 mem[BPF_MEMWORDS];
197145510Sdarrenr	mb_t *m, *n;
198170268Sdarrenr	int merr = 0;	/* XXX: GCC */
199170268Sdarrenr	int len;
200145510Sdarrenr
201145510Sdarrenr	if (buflen == 0) {
202145510Sdarrenr		m = (mb_t *)p;
203145510Sdarrenr		p = MTOD(m, u_char *);
204145510Sdarrenr		buflen = M_LEN(m);
205145510Sdarrenr	} else
206145510Sdarrenr		m = NULL;
207145510Sdarrenr
208145510Sdarrenr	if (pc == 0)
209145510Sdarrenr		/*
210145510Sdarrenr		 * No filter means accept all.
211145510Sdarrenr		 */
212145510Sdarrenr		return (u_int)-1;
213145510Sdarrenr	A = 0;
214145510Sdarrenr	X = 0;
215145510Sdarrenr	--pc;
216145510Sdarrenr	while (1) {
217145510Sdarrenr		++pc;
218145510Sdarrenr		switch (pc->code) {
219145510Sdarrenr
220145510Sdarrenr		default:
221145510Sdarrenr			return 0;
222145510Sdarrenr		case BPF_RET|BPF_K:
223145510Sdarrenr			return (u_int)pc->k;
224145510Sdarrenr
225145510Sdarrenr		case BPF_RET|BPF_A:
226145510Sdarrenr			return (u_int)A;
227145510Sdarrenr
228145510Sdarrenr		case BPF_LD|BPF_W|BPF_ABS:
229145510Sdarrenr			k = pc->k;
230145510Sdarrenr			if (k + sizeof(int32) > buflen) {
231145510Sdarrenr				if (m == NULL)
232145510Sdarrenr					return 0;
233145510Sdarrenr				A = m_xword(m, k, &merr);
234145510Sdarrenr				if (merr != 0)
235145510Sdarrenr					return 0;
236145510Sdarrenr				continue;
237145510Sdarrenr			}
238145510Sdarrenr			A = EXTRACT_LONG(&p[k]);
239145510Sdarrenr			continue;
240145510Sdarrenr
241145510Sdarrenr		case BPF_LD|BPF_H|BPF_ABS:
242145510Sdarrenr			k = pc->k;
243145510Sdarrenr			if (k + sizeof(short) > buflen) {
244145510Sdarrenr				if (m == NULL)
245145510Sdarrenr					return 0;
246145510Sdarrenr				A = m_xhalf(m, k, &merr);
247145510Sdarrenr				if (merr != 0)
248145510Sdarrenr					return 0;
249145510Sdarrenr				continue;
250145510Sdarrenr			}
251145510Sdarrenr			A = EXTRACT_SHORT(&p[k]);
252145510Sdarrenr			continue;
253145510Sdarrenr
254145510Sdarrenr		case BPF_LD|BPF_B|BPF_ABS:
255145510Sdarrenr			k = pc->k;
256145510Sdarrenr			if (k >= buflen) {
257145510Sdarrenr				if (m == NULL)
258145510Sdarrenr					return 0;
259145510Sdarrenr				n = m;
260145510Sdarrenr				MINDEX(len, n, k);
261145510Sdarrenr				A = MTOD(n, u_char *)[k];
262145510Sdarrenr				continue;
263145510Sdarrenr			}
264145510Sdarrenr			A = p[k];
265145510Sdarrenr			continue;
266145510Sdarrenr
267145510Sdarrenr		case BPF_LD|BPF_W|BPF_LEN:
268145510Sdarrenr			A = wirelen;
269145510Sdarrenr			continue;
270145510Sdarrenr
271145510Sdarrenr		case BPF_LDX|BPF_W|BPF_LEN:
272145510Sdarrenr			X = wirelen;
273145510Sdarrenr			continue;
274145510Sdarrenr
275145510Sdarrenr		case BPF_LD|BPF_W|BPF_IND:
276145510Sdarrenr			k = X + pc->k;
277145510Sdarrenr			if (k + sizeof(int32) > buflen) {
278145510Sdarrenr				if (m == NULL)
279145510Sdarrenr					return 0;
280145510Sdarrenr				A = m_xword(m, k, &merr);
281145510Sdarrenr				if (merr != 0)
282145510Sdarrenr					return 0;
283145510Sdarrenr				continue;
284145510Sdarrenr			}
285145510Sdarrenr			A = EXTRACT_LONG(&p[k]);
286145510Sdarrenr			continue;
287145510Sdarrenr
288145510Sdarrenr		case BPF_LD|BPF_H|BPF_IND:
289145510Sdarrenr			k = X + pc->k;
290145510Sdarrenr			if (k + sizeof(short) > buflen) {
291145510Sdarrenr				if (m == NULL)
292145510Sdarrenr					return 0;
293145510Sdarrenr				A = m_xhalf(m, k, &merr);
294145510Sdarrenr				if (merr != 0)
295145510Sdarrenr					return 0;
296145510Sdarrenr				continue;
297145510Sdarrenr			}
298145510Sdarrenr			A = EXTRACT_SHORT(&p[k]);
299145510Sdarrenr			continue;
300145510Sdarrenr
301145510Sdarrenr		case BPF_LD|BPF_B|BPF_IND:
302145510Sdarrenr			k = X + pc->k;
303145510Sdarrenr			if (k >= buflen) {
304145510Sdarrenr				if (m == NULL)
305145510Sdarrenr					return 0;
306145510Sdarrenr				n = m;
307145510Sdarrenr				MINDEX(len, n, k);
308145510Sdarrenr				A = MTOD(n, u_char *)[k];
309145510Sdarrenr				continue;
310145510Sdarrenr			}
311145510Sdarrenr			A = p[k];
312145510Sdarrenr			continue;
313145510Sdarrenr
314145510Sdarrenr		case BPF_LDX|BPF_MSH|BPF_B:
315145510Sdarrenr			k = pc->k;
316145510Sdarrenr			if (k >= buflen) {
317145510Sdarrenr				if (m == NULL)
318145510Sdarrenr					return 0;
319145510Sdarrenr				n = m;
320145510Sdarrenr				MINDEX(len, n, k);
321145510Sdarrenr				X = (MTOD(n, char *)[k] & 0xf) << 2;
322145510Sdarrenr				continue;
323145510Sdarrenr			}
324145510Sdarrenr			X = (p[pc->k] & 0xf) << 2;
325145510Sdarrenr			continue;
326145510Sdarrenr
327145510Sdarrenr		case BPF_LD|BPF_IMM:
328145510Sdarrenr			A = pc->k;
329145510Sdarrenr			continue;
330145510Sdarrenr
331145510Sdarrenr		case BPF_LDX|BPF_IMM:
332145510Sdarrenr			X = pc->k;
333145510Sdarrenr			continue;
334145510Sdarrenr
335145510Sdarrenr		case BPF_LD|BPF_MEM:
336145510Sdarrenr			A = mem[pc->k];
337145510Sdarrenr			continue;
338145510Sdarrenr
339145510Sdarrenr		case BPF_LDX|BPF_MEM:
340145510Sdarrenr			X = mem[pc->k];
341145510Sdarrenr			continue;
342145510Sdarrenr
343145510Sdarrenr		case BPF_ST:
344145510Sdarrenr			mem[pc->k] = A;
345145510Sdarrenr			continue;
346145510Sdarrenr
347145510Sdarrenr		case BPF_STX:
348145510Sdarrenr			mem[pc->k] = X;
349145510Sdarrenr			continue;
350145510Sdarrenr
351145510Sdarrenr		case BPF_JMP|BPF_JA:
352145510Sdarrenr			pc += pc->k;
353145510Sdarrenr			continue;
354145510Sdarrenr
355145510Sdarrenr		case BPF_JMP|BPF_JGT|BPF_K:
356145510Sdarrenr			pc += (A > pc->k) ? pc->jt : pc->jf;
357145510Sdarrenr			continue;
358145510Sdarrenr
359145510Sdarrenr		case BPF_JMP|BPF_JGE|BPF_K:
360145510Sdarrenr			pc += (A >= pc->k) ? pc->jt : pc->jf;
361145510Sdarrenr			continue;
362145510Sdarrenr
363145510Sdarrenr		case BPF_JMP|BPF_JEQ|BPF_K:
364145510Sdarrenr			pc += (A == pc->k) ? pc->jt : pc->jf;
365145510Sdarrenr			continue;
366145510Sdarrenr
367145510Sdarrenr		case BPF_JMP|BPF_JSET|BPF_K:
368145510Sdarrenr			pc += (A & pc->k) ? pc->jt : pc->jf;
369145510Sdarrenr			continue;
370145510Sdarrenr
371145510Sdarrenr		case BPF_JMP|BPF_JGT|BPF_X:
372145510Sdarrenr			pc += (A > X) ? pc->jt : pc->jf;
373145510Sdarrenr			continue;
374145510Sdarrenr
375145510Sdarrenr		case BPF_JMP|BPF_JGE|BPF_X:
376145510Sdarrenr			pc += (A >= X) ? pc->jt : pc->jf;
377145510Sdarrenr			continue;
378145510Sdarrenr
379145510Sdarrenr		case BPF_JMP|BPF_JEQ|BPF_X:
380145510Sdarrenr			pc += (A == X) ? pc->jt : pc->jf;
381145510Sdarrenr			continue;
382145510Sdarrenr
383145510Sdarrenr		case BPF_JMP|BPF_JSET|BPF_X:
384145510Sdarrenr			pc += (A & X) ? pc->jt : pc->jf;
385145510Sdarrenr			continue;
386145510Sdarrenr
387145510Sdarrenr		case BPF_ALU|BPF_ADD|BPF_X:
388145510Sdarrenr			A += X;
389145510Sdarrenr			continue;
390145510Sdarrenr
391145510Sdarrenr		case BPF_ALU|BPF_SUB|BPF_X:
392145510Sdarrenr			A -= X;
393145510Sdarrenr			continue;
394145510Sdarrenr
395145510Sdarrenr		case BPF_ALU|BPF_MUL|BPF_X:
396145510Sdarrenr			A *= X;
397145510Sdarrenr			continue;
398145510Sdarrenr
399145510Sdarrenr		case BPF_ALU|BPF_DIV|BPF_X:
400145510Sdarrenr			if (X == 0)
401145510Sdarrenr				return 0;
402145510Sdarrenr			A /= X;
403145510Sdarrenr			continue;
404145510Sdarrenr
405145510Sdarrenr		case BPF_ALU|BPF_AND|BPF_X:
406145510Sdarrenr			A &= X;
407145510Sdarrenr			continue;
408145510Sdarrenr
409145510Sdarrenr		case BPF_ALU|BPF_OR|BPF_X:
410145510Sdarrenr			A |= X;
411145510Sdarrenr			continue;
412145510Sdarrenr
413145510Sdarrenr		case BPF_ALU|BPF_LSH|BPF_X:
414145510Sdarrenr			A <<= X;
415145510Sdarrenr			continue;
416145510Sdarrenr
417145510Sdarrenr		case BPF_ALU|BPF_RSH|BPF_X:
418145510Sdarrenr			A >>= X;
419145510Sdarrenr			continue;
420145510Sdarrenr
421145510Sdarrenr		case BPF_ALU|BPF_ADD|BPF_K:
422145510Sdarrenr			A += pc->k;
423145510Sdarrenr			continue;
424145510Sdarrenr
425145510Sdarrenr		case BPF_ALU|BPF_SUB|BPF_K:
426145510Sdarrenr			A -= pc->k;
427145510Sdarrenr			continue;
428145510Sdarrenr
429145510Sdarrenr		case BPF_ALU|BPF_MUL|BPF_K:
430145510Sdarrenr			A *= pc->k;
431145510Sdarrenr			continue;
432145510Sdarrenr
433145510Sdarrenr		case BPF_ALU|BPF_DIV|BPF_K:
434145510Sdarrenr			A /= pc->k;
435145510Sdarrenr			continue;
436145510Sdarrenr
437145510Sdarrenr		case BPF_ALU|BPF_AND|BPF_K:
438145510Sdarrenr			A &= pc->k;
439145510Sdarrenr			continue;
440145510Sdarrenr
441145510Sdarrenr		case BPF_ALU|BPF_OR|BPF_K:
442145510Sdarrenr			A |= pc->k;
443145510Sdarrenr			continue;
444145510Sdarrenr
445145510Sdarrenr		case BPF_ALU|BPF_LSH|BPF_K:
446145510Sdarrenr			A <<= pc->k;
447145510Sdarrenr			continue;
448145510Sdarrenr
449145510Sdarrenr		case BPF_ALU|BPF_RSH|BPF_K:
450145510Sdarrenr			A >>= pc->k;
451145510Sdarrenr			continue;
452145510Sdarrenr
453145510Sdarrenr		case BPF_ALU|BPF_NEG:
454145510Sdarrenr			A = -A;
455145510Sdarrenr			continue;
456145510Sdarrenr
457145510Sdarrenr		case BPF_MISC|BPF_TAX:
458145510Sdarrenr			X = A;
459145510Sdarrenr			continue;
460145510Sdarrenr
461145510Sdarrenr		case BPF_MISC|BPF_TXA:
462145510Sdarrenr			A = X;
463145510Sdarrenr			continue;
464145510Sdarrenr		}
465145510Sdarrenr	}
466145510Sdarrenr}
467145510Sdarrenr
468145510Sdarrenr
469145510Sdarrenr/*
470145510Sdarrenr * Return true if the 'fcode' is a valid filter program.
471145510Sdarrenr * The constraints are that each jump be forward and to a valid
472161357Sguido * code, that memory accesses are within valid ranges (to the
473161357Sguido * extent that this can be checked statically; loads of packet
474161357Sguido * data have to be, and are, also checked at run time), and that
475161357Sguido * the code terminates with either an accept or reject.
476145510Sdarrenr *
477145510Sdarrenr * The kernel needs to be able to verify an application's filter code.
478145510Sdarrenr * Otherwise, a bogus program could easily crash the system.
479145510Sdarrenr */
480145510Sdarrenrint
481145510Sdarrenrbpf_validate(f, len)
482145510Sdarrenr	struct bpf_insn *f;
483145510Sdarrenr	int len;
484145510Sdarrenr{
485161357Sguido	u_int i, from;
486161357Sguido	const struct bpf_insn *p;
487145510Sdarrenr
488161357Sguido	if (len == 0)
489161357Sguido		return 1;
490161357Sguido
491161357Sguido	if (len < 1 || len > BPF_MAXINSNS)
492161357Sguido		return 0;
493161357Sguido
494145510Sdarrenr	for (i = 0; i < len; ++i) {
495161357Sguido		p = &f[i];
496161357Sguido		switch (BPF_CLASS(p->code)) {
497145510Sdarrenr		/*
498161357Sguido		 * Check that memory operations use valid addresses.
499145510Sdarrenr		 */
500161357Sguido		case BPF_LD:
501161357Sguido		case BPF_LDX:
502161357Sguido			switch (BPF_MODE(p->code)) {
503161357Sguido			case BPF_IMM:
504161357Sguido				break;
505161357Sguido			case BPF_ABS:
506161357Sguido			case BPF_IND:
507161357Sguido			case BPF_MSH:
508161357Sguido				/*
509161357Sguido				 * More strict check with actual packet length
510161357Sguido				 * is done runtime.
511161357Sguido				 */
512161357Sguido#if 0
513161357Sguido				if (p->k >= bpf_maxbufsize)
514145510Sdarrenr					return 0;
515161357Sguido#endif
516161357Sguido				break;
517161357Sguido			case BPF_MEM:
518161357Sguido				if (p->k >= BPF_MEMWORDS)
519161357Sguido					return 0;
520161357Sguido				break;
521161357Sguido			case BPF_LEN:
522161357Sguido				break;
523161357Sguido			default:
524161357Sguido				return 0;
525145510Sdarrenr			}
526161357Sguido			break;
527161357Sguido		case BPF_ST:
528161357Sguido		case BPF_STX:
529161357Sguido			if (p->k >= BPF_MEMWORDS)
530145510Sdarrenr				return 0;
531161357Sguido			break;
532161357Sguido		case BPF_ALU:
533161357Sguido			switch (BPF_OP(p->code)) {
534161357Sguido			case BPF_ADD:
535161357Sguido			case BPF_SUB:
536161357Sguido			case BPF_OR:
537161357Sguido			case BPF_AND:
538161357Sguido			case BPF_LSH:
539161357Sguido			case BPF_RSH:
540161357Sguido			case BPF_NEG:
541161357Sguido				break;
542161357Sguido			case BPF_DIV:
543161357Sguido				/*
544161357Sguido				 * Check for constant division by 0.
545161357Sguido				 */
546161357Sguido				if (BPF_RVAL(p->code) == BPF_K && p->k == 0)
547161357Sguido					return 0;
548161357Sguido			default:
549161357Sguido				return 0;
550161357Sguido			}
551161357Sguido			break;
552161357Sguido		case BPF_JMP:
553161357Sguido			/*
554161357Sguido			 * Check that jumps are within the code block,
555161357Sguido			 * and that unconditional branches don't go
556161357Sguido			 * backwards as a result of an overflow.
557161357Sguido			 * Unconditional branches have a 32-bit offset,
558161357Sguido			 * so they could overflow; we check to make
559161357Sguido			 * sure they don't.  Conditional branches have
560161357Sguido			 * an 8-bit offset, and the from address is <=
561161357Sguido			 * BPF_MAXINSNS, and we assume that BPF_MAXINSNS
562161357Sguido			 * is sufficiently small that adding 255 to it
563161357Sguido			 * won't overflow.
564161357Sguido			 *
565161357Sguido			 * We know that len is <= BPF_MAXINSNS, and we
566161357Sguido			 * assume that BPF_MAXINSNS is < the maximum size
567161357Sguido			 * of a u_int, so that i + 1 doesn't overflow.
568161357Sguido			 */
569161357Sguido			from = i + 1;
570161357Sguido			switch (BPF_OP(p->code)) {
571161357Sguido			case BPF_JA:
572161357Sguido				if (from + p->k < from || from + p->k >= len)
573161357Sguido					return 0;
574161357Sguido				break;
575161357Sguido			case BPF_JEQ:
576161357Sguido			case BPF_JGT:
577161357Sguido			case BPF_JGE:
578161357Sguido			case BPF_JSET:
579161357Sguido				if (from + p->jt >= len || from + p->jf >= len)
580161357Sguido					return 0;
581161357Sguido				break;
582161357Sguido			default:
583161357Sguido				return 0;
584161357Sguido			}
585161357Sguido			break;
586161357Sguido		case BPF_RET:
587161357Sguido			break;
588161357Sguido		case BPF_MISC:
589161357Sguido			break;
590161357Sguido		default:
591161357Sguido			return 0;
592145510Sdarrenr		}
593145510Sdarrenr	}
594145510Sdarrenr	return BPF_CLASS(f[len - 1].code) == BPF_RET;
595145510Sdarrenr}
596