1/**
2 * \file
3 * \brief Implements a virtual machine for executing compiled intermediate language byte code
4 *
5 */
6/*
7 * Copyright (c) 2009, 2010, ETH Zurich.
8 * All rights reserved.
9 *
10 * This file is distributed under the terms in the attached LICENSE file.
11 * If you do not find this file, copies can be found by writing to:
12 * ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group.
13 */
14
15#include <sys/endian.h>
16#include <bfdmuxvm/vm.h>
17#include <bfdmuxtools/bfdmux.h>
18
19#include <barrelfish/barrelfish.h>
20#include <arpa/inet.h>
21
22/*
23 * Take compiled filter and run data through it.
24 * Result gets stored in the filterresult_t*
25 *
26 */
27/**
28 * \brief Performs recursive execution of a subtree of the filter code
29 * @param filter_code Points to the begining of the filter code
30 * @param filter_len Specifies the length of the filter code in bytes
31 * @param packet_data Points to the packet data to run the filter on
32 * @param packet_len Specifies the length of the packet data in bytes
33 * @param[out] result_value Return value of the subtree execution
34 * @param[in] result_offset Initially specifies the offset of the next byte to be executed in the filter code
35 * @param[out] result_offset Specifies the next code byte to be executed, after the entire subtree code was executed
36 * @return ERR_OK on success, other error values on failure; see header file for error types.
37 */
38
39err_t
40calc(uint8_t * filter_code, int filter_len, uint8_t * packet_data,
41	 int packet_len, uint64_t * result_value, size_t * result_offset);
42err_t
43calc(uint8_t * filter_code, int filter_len, uint8_t * packet_data,
44	 int packet_len, uint64_t * result_value, size_t * result_offset)
45{
46	uint64_t        res;
47	size_t          start = *result_offset;
48	if (start > filter_len){
49	    return ERR_UNKNOWN;
50        }
51
52	op_t            op = filter_code[*result_offset];
53	err_t           err;
54	switch (op) {
55		/*
56		 * ---------------------
57		 */
58		/*
59		 * Single argument calls
60		 */
61		/*
62		 * ---------------------
63		 */
64
65
66		// Immediates
67	case OP_INT8:
68		*result_value = *(uint8_t *) (filter_code + start + 1);
69		*result_offset += 1;
70		return ERR_OK;
71	case OP_INT16:
72		*result_value = *(uint16_t *) (filter_code + start + 1);
73		*result_offset += 2;
74		return ERR_OK;
75	case OP_INT32:
76		*result_value = *(uint32_t *) (filter_code + start + 1);
77		*result_offset += 4;
78		return ERR_OK;
79	case OP_INT64:
80		*result_value = *(uint64_t *) (filter_code + start + 1);
81		*result_offset += 8;
82		return ERR_OK;
83
84		/*
85		 * -----------------------------------------------------------------------------------
86		 */
87		/*
88		 * Special two argument calls (maybe we can break after evaluating
89		 * the first argument)
90		 */
91		/*
92		 * -----------------------------------------------------------------------------------
93		 */
94
95		// Logical
96		//
97		// case OP_AND and OP_OR could be merged toghether
98	case OP_AND:				// Has a 32bit argument describing the
99		// whole treesize
100		*result_offset += 5;
101		if ((err =
102			 calc(filter_code, filter_len, packet_data, packet_len,
103				  result_value, result_offset)) < 0)
104			return err;
105		// Return false if first tree returned false
106		if (!(*result_value)) {
107			uint64_t       *subtreesize =
108				(uint64_t *) ((filter_code) + start + 1);
109			*result_offset = start + 4 + *subtreesize;
110			// False is already in result->value
111			return ERR_OK;
112		}
113		// Fetch 2nd argument
114		*result_offset += 1;
115		if ((err =
116			 calc(filter_code, filter_len, packet_data, packet_len,
117				  result_value, result_offset)) < 0)
118			return err;
119
120		// if (result->value) return true; // Result is already in
121		// result->value
122		// else return false;
123		return ERR_OK;
124
125	case OP_OR:				// Has a 32bit argument describing the
126		// whole treesize
127		*result_offset += 5;
128		if ((err =
129			 calc(filter_code, filter_len, packet_data, packet_len,
130				  result_value, result_offset)) < 0)
131			return err;
132		// Return true if first subtree returned true
133		if (*result_value) {
134			uint64_t       *subtreesize =
135				(uint64_t *) ((filter_code) + start + 1);
136			*result_offset = start + 4 + *subtreesize;
137			// True is already in result->value
138			return ERR_OK;
139		}
140		// Fetch 2nd argument
141		*result_offset += 1;
142		if ((err =
143			 calc(filter_code, filter_len, packet_data, packet_len,
144				  result_value, result_offset)) < 0)
145			return err;
146
147		// if (result->value) return true; // Result is already in
148		// result->value
149		// else return false;
150		return ERR_OK;
151
152
153
154
155	default:
156		/*
157		 * -------------------
158		 */
159		/*
160		 * One argument calls
161		 */
162		/*
163		 * -------------------
164		 */
165		*result_offset += 1;
166		if ((err =
167			 calc(filter_code, filter_len, packet_data, packet_len,
168				  result_value, result_offset)) < 0)
169			return err;
170
171		switch (op) {			/* We need only the first argument */
172		case OP_NOT:
173			if (*result_value) {
174				*result_value = 0;
175			} else {
176				*result_value = 1;
177			}
178			return ERR_OK;
179		case OP_LOAD8:
180			// Packet access
181			if ((*result_value) >= packet_len)
182				return ERR_BAD_ACCESS;	// Access not withing packet
183			*result_value = *(uint8_t *) (packet_data + (*result_value));
184			return ERR_OK;
185		case OP_LOAD16:
186			// Packet access
187			if ((*result_value) + 1 >= packet_len)
188				return ERR_BAD_ACCESS;	// Access not withing packet
189			(*result_value) =
190				ntohs(*(uint16_t *) (packet_data + (*result_value)));
191			return ERR_OK;
192		case OP_LOAD32:
193			// Packet access
194			if ((*result_value) + 3 >= packet_len)
195				return ERR_BAD_ACCESS;	// Access not withing packet
196			*result_value =
197			      ntohl(*(uint32_t *) (packet_data + (*result_value)));
198			return ERR_OK;
199		case OP_LOAD64:
200			// Packet access
201			if ((*result_value + 7) >= packet_len)
202				return ERR_BAD_ACCESS;	// Access not withing packet
203			// If we are on a littleendian machine, translate from network
204			//
205			//
206			// order (bigendian) to hostorder
207		        res =
208				*(uint64_t *) (packet_data + (*result_value));
209			short           word = 0x0001;
210			char           *byte = (char *) &word;
211			if (byte[0])		// Little endian
212				res = be64toh(res);
213			(*result_value) = res;
214			return ERR_OK;
215		}
216
217		/*
218		 * -------------------
219		 */
220		/*
221		 * two argument calls
222		 */
223		/*
224		 * -------------------
225		 */
226
227		/*
228		 * We also need the second argument
229		 */
230		// Fetch 2nd argument
231		res = *result_value;
232		*result_offset += 1;
233		if ((err =
234			 calc(filter_code, filter_len, packet_data, packet_len,
235				  result_value, result_offset)) < 0)
236			return err;
237
238		switch (op) {
239			// Comparision
240		case OP_EQUAL:
241			if (res == (*result_value))
242				*result_value = 1;
243			else
244				*result_value = 0;
245			break;
246		case OP_UNEQUAL:
247			if (res != *result_value)
248				*result_value = 1;
249			else
250				*result_value = 0;
251			break;
252		case OP_SGREATER:
253			if ((signed) res > (signed) (*result_value))
254				*result_value = 1;
255			else
256				*result_value = 0;
257			break;
258		case OP_SLESS:
259			if ((signed) res < (signed) (*result_value))
260				*result_value = 1;
261			else
262				*result_value = 0;
263			break;
264		case OP_UGREATER:
265			if ((unsigned) res > (unsigned) (*result_value))
266				*result_value = 1;
267			else
268				*result_value = 0;
269			break;
270		case OP_ULESS:
271			if ((unsigned) res < (unsigned) (*result_value))
272				*result_value = 1;
273			else
274				*result_value = 0;
275			break;
276		case OP_SGREATEREQUAL:
277			if ((signed) res >= (signed) (*result_value))
278				*result_value = 1;
279			else
280				*result_value = 0;
281			break;
282		case OP_SLESSEQUAL:
283			if ((signed) res <= (signed) (*result_value))
284				*result_value = 1;
285			else
286				*result_value = 0;
287			break;
288		case OP_UGREATEREQUAL:
289			if ((unsigned) res >= (unsigned) (*result_value))
290				*result_value = 1;
291			else
292				*result_value = 0;
293			break;
294		case OP_ULESSEQUAL:
295			if ((unsigned) res <= (unsigned) (*result_value))
296				*result_value = 1;
297			else
298				*result_value = 0;
299			break;
300
301			// Arithmetic
302		case OP_ADD:
303			(*result_value) += res;
304			break;
305		case OP_SUB:
306			(*result_value) = res - (*result_value);
307			break;
308		case OP_MULT:
309			(*result_value) *= res;
310			break;
311		case OP_IDIV:
312			(*result_value) = res / (*result_value);
313			break;
314		case OP_MOD:
315			(*result_value) = res % (*result_value);
316			break;
317
318			// Bitwise
319		case OP_BAND:
320			(*result_value) &= res;
321			break;
322		case OP_BOR:
323			(*result_value) |= res;
324			break;
325		case OP_BXOR:
326			(*result_value) ^= res;
327			break;
328			// case OP_BNOT: // This case gets handled on top (one
329			// argument call)
330
331			// Error
332		default:
333			return ERR_BAD_OP;
334		}
335		return ERR_OK;
336		/*
337		 * End of default case
338		 */
339	}
340}
341
342/**
343 * \brief Executes the specified filter on the given packet.
344 * @param filter_code Points to the filters byte code
345 * @param filter_len Length of the byte code
346 * @param packet_data Points to the packet data to run the filter on
347 * @param packet_len Length of packet data in bytes
348 * @param[out] error_out Error information upon failure during execution
349 * @return true, if the filter executed successfully and the result was not zero. false otherwise.
350 */
351bool
352execute_filter(uint8_t * filter_code, int filter_len,
353			   uint8_t * packet_data, int packet_len, int *error_out)
354{
355	err_t           err;
356	uint64_t        result_value;
357	size_t          result_offset;
358	result_value = 0;
359	result_offset = 0;
360	err =
361		calc(filter_code, filter_len, packet_data, packet_len,
362			 &result_value, &result_offset);
363	if (error_out) {
364		*error_out = err;
365	}
366	if (err < 0 || !(result_value)) {
367		return false;
368	} else {
369		return true;
370	}
371}
372