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