d1bff53587350b429553fdf0221e3012c8631d7e
[obnox/wireshark/wip.git] / wiretap / bpf-engine.c
1 /* bpf-engine.c
2  * ------------
3  * The BPF engine used for offline ("display") filters in wiretap.
4  * The code is taken from the Linux Socket Filter, and only slightly
5  * modified for use in wiretap.
6  *
7  * Gilbert Ramirez <gram@verdict.uthscsa.edu>
8  */
9
10 /*
11  * Linux Socket Filter - Kernel level socket filtering
12  *
13  * Author:
14  *     Jay Schulist <Jay.Schulist@spacs.k12.wi.us>
15  *
16  * Based on the design of:
17  *     - The Berkeley Packet Filter
18  *
19  * This program is free software; you can redistribute it and/or
20  * modify it under the terms of the GNU General Public License
21  * as published by the Free Software Foundation; either version
22  * 2 of the License, or (at your option) any later version.
23  */
24
25 #include <glib.h>
26 #include "wtap.h"
27 #include "bpf-engine.h"
28
29
30 /*
31  * Decode and apply filter instructions to the skb->data.
32  * Return length to keep, 0 for none. skb is the data we are
33  * filtering, filter is the array of filter instructions, and
34  * len is the number of filter blocks in the array.
35  */
36  
37 int bpf_run_filter(unsigned char *data, int len, struct bpf_instruction *filter, int flen)
38 {
39         struct bpf_instruction *fentry; /* We walk down these */
40         guint32 A = 0;                  /* Accumulator */
41         guint32 X = 0;                  /* Index Register */
42         guint32 mem[BPF_MEMWORDS];      /* Scratch Memory Store */
43         int k;
44         int pc;
45         int *t;
46
47         /*
48          * Process array of filter instructions.
49          */
50
51         for(pc = 0; pc < flen; pc++)
52         {
53                 fentry = &filter[pc];
54                 if(fentry->code & BPF_X)
55                         t=&X;
56                 else
57                         t=&fentry->k;
58                         
59                 switch(fentry->code)
60                 {
61                         case BPF_ALU|BPF_ADD|BPF_X:
62                         case BPF_ALU|BPF_ADD|BPF_K:
63                                 A += *t;
64                                 continue;
65
66                         case BPF_ALU|BPF_SUB|BPF_X:
67                         case BPF_ALU|BPF_SUB|BPF_K:
68                                 A -= *t;
69                                 continue;
70
71                         case BPF_ALU|BPF_MUL|BPF_X:
72                         case BPF_ALU|BPF_MUL|BPF_K:
73                                 A *= *t;
74                                 continue;
75
76                         case BPF_ALU|BPF_DIV|BPF_X:
77                         case BPF_ALU|BPF_DIV|BPF_K:
78                                 if(*t == 0)
79                                         return (0);
80                                 A /= *t;
81                                 continue;
82
83                         case BPF_ALU|BPF_AND|BPF_X:
84                         case BPF_ALU|BPF_AND|BPF_K:
85                                 A &= *t;
86                                 continue;
87
88                         case BPF_ALU|BPF_OR|BPF_X:
89                         case BPF_ALU|BPF_OR|BPF_K:
90                                 A |= *t;
91                                 continue;
92
93                         case BPF_ALU|BPF_LSH|BPF_X:
94                         case BPF_ALU|BPF_LSH|BPF_K:
95                                 A <<= *t;
96                                 continue;
97
98                         case BPF_ALU|BPF_RSH|BPF_X:
99                         case BPF_ALU|BPF_RSH|BPF_K:
100                                 A >>= *t;
101                                 continue;
102
103                         case BPF_ALU|BPF_NEG:
104                                 A = -A;
105                                 continue;
106
107                         case BPF_JMP|BPF_JA:
108                                 pc += fentry->k;
109                                 continue;
110
111                         case BPF_JMP|BPF_JGT|BPF_K:
112                                 pc += (A > fentry->k) ? fentry->jt : fentry->jf;
113                                 continue;
114
115                         case BPF_JMP|BPF_JGE|BPF_K:
116                                 pc += (A >= fentry->k) ? fentry->jt : fentry->jf;
117                                 continue;
118
119                         case BPF_JMP|BPF_JEQ|BPF_K:
120                                 pc += (A == fentry->k) ? fentry->jt : fentry->jf;
121                                 continue;
122
123                         case BPF_JMP|BPF_JSET|BPF_K:
124                                 pc += (A & fentry->k) ? fentry->jt : fentry->jf;
125                                 continue;
126
127                         case BPF_JMP|BPF_JGT|BPF_X:
128                                 pc += (A > X) ? fentry->jt : fentry->jf;
129                                 continue;
130
131                         case BPF_JMP|BPF_JGE|BPF_X:
132                                 pc += (A >= X) ? fentry->jt : fentry->jf;
133                                 continue;
134
135                         case BPF_JMP|BPF_JEQ|BPF_X:
136                                 pc += (A == X) ? fentry->jt : fentry->jf;
137                                 continue;
138
139                         case BPF_JMP|BPF_JSET|BPF_X:
140                                 pc += (A & X) ? fentry->jt : fentry->jf;
141                                 continue;
142                         case BPF_LD|BPF_W|BPF_ABS:
143                                 k = fentry->k;
144                                 if(k + sizeof(long) > len)
145                                         return (0);
146                                 A = pntohl(&data[k]);
147                                 continue;
148
149                         case BPF_LD|BPF_H|BPF_ABS:
150                                 k = fentry->k;
151                                 if(k + sizeof(short) > len)
152                                         return (0);
153                                 A = pntohs(&data[k]);
154                                 continue;
155
156                         case BPF_LD|BPF_B|BPF_ABS:
157                                 k = fentry->k;
158                                 if(k >= len)
159                                         return (0);
160                                 A = data[k];
161                                 continue;
162
163                         case BPF_LD|BPF_W|BPF_LEN:
164                                 A = len;
165                                 continue;
166
167                         case BPF_LDX|BPF_W|BPF_LEN:
168                                 X = len;
169                                 continue;
170
171                       case BPF_LD|BPF_W|BPF_IND:
172                                 k = X + fentry->k;
173                                 if(k + sizeof(guint32) > len)
174                                         return (0);
175                                 A = pntohl(&data[k]);
176                                 continue;
177
178                        case BPF_LD|BPF_H|BPF_IND:
179                                 k = X + fentry->k;
180                                 if(k + sizeof(guint16) > len)
181                                         return (0);
182                                 A = pntohs(&data[k]);
183                                 continue;
184
185                        case BPF_LD|BPF_B|BPF_IND:
186                                 k = X + fentry->k;
187                                 if(k >= len)
188                                         return (0);
189                                 A = data[k];
190                                 continue;
191
192                         case BPF_LDX|BPF_B|BPF_MSH:
193                                 /*
194                                  *      Hack for BPF to handle TOS etc
195                                  */
196                                 k = fentry->k;
197                                 if(k >= len)
198                                         return (0);
199                                 X = (data[fentry->k] & 0xf) << 2;
200                                 continue;
201
202                         case BPF_LD|BPF_IMM:
203                                 A = fentry->k;
204                                 continue;
205
206                         case BPF_LDX|BPF_IMM:
207                                 X = fentry->k;
208                                 continue;
209
210                        case BPF_LD|BPF_MEM:
211                                 A = mem[fentry->k];
212                                 continue;
213
214                         case BPF_LDX|BPF_MEM:
215                                 X = mem[fentry->k];
216                                 continue;
217
218                         case BPF_MISC|BPF_TAX:
219                                 X = A;
220                                 continue;
221
222                         case BPF_MISC|BPF_TXA:
223                                 A = X;
224                                 continue;
225
226                         case BPF_RET|BPF_K:
227                                 return ((unsigned int)fentry->k);
228
229                         case BPF_RET|BPF_A:
230                                 return ((unsigned int)A);
231
232                         case BPF_ST:
233                                 mem[fentry->k] = A;
234                                 continue;
235
236                         case BPF_STX:
237                                 mem[fentry->k] = X;
238                                 continue;
239
240
241
242                         default:
243                                 /* Invalid instruction counts as RET */
244                                 return (0);
245                 }
246         }
247
248         g_error("Filter ruleset ran off the end.\n");
249         return (0);
250 }
251
252 /*
253  * Check the user's filter code. If we let some ugly
254  * filter code slip through kaboom!
255  */
256
257 int bpf_chk_filter(struct bpf_instruction *filter, int flen)
258 {
259         struct bpf_instruction *ftest;
260         int pc;
261
262        /*
263         * Check the filter code now.
264         */
265         for(pc = 0; pc < flen; pc++)
266         {
267                 /*
268                  *      All jumps are forward as they are not signed
269                  */
270                  
271                 ftest = &filter[pc];
272                 if(BPF_CLASS(ftest->code) == BPF_JMP)
273                 {       
274                         /*
275                          *      But they mustn't jump off the end.
276                          */
277                         if(BPF_OP(ftest->code) == BPF_JA)
278                         {
279                                 if(pc + ftest->k + 1>= (unsigned)flen)
280                                         return (-1);
281                         }
282                         else
283                         {
284                                 /*
285                                  *      For conditionals both must be safe
286                                  */
287                                 if(pc + ftest->jt +1 >= flen || pc + ftest->jf +1 >= flen)
288                                         return (-1);
289                         }
290                 }
291
292                 /*
293                  *      Check that memory operations use valid addresses.
294                  */
295                  
296                 if(ftest->k <0 || ftest->k >= BPF_MEMWORDS)
297                 {
298                         /*
299                          *      But it might not be a memory operation...
300                          */
301                          
302                         if (BPF_CLASS(ftest->code) == BPF_ST)
303                                 return -1;
304                         if((BPF_CLASS(ftest->code) == BPF_LD) && 
305                                 (BPF_MODE(ftest->code) == BPF_MEM))
306                                         return (-1);
307                 }
308         }
309
310         /*
311          *      The program must end with a return. We don't care where they
312          *      jumped within the script (its always forwards) but in the
313          *      end they _will_ hit this.
314          */
315          
316         return (BPF_CLASS(filter[flen - 1].code) == BPF_RET)?0:-1;
317 }
318