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