Commit message: Fix heap overflow (reported by Jurriaan Bremer)

When setting a new array item with yr_object_array_set_item() the array size is doubled if the index for the new item is larger than the already allocated ones. No further checks were made to ensure that the index fits into the array after doubling its capacity. If the array capacity was for example 64, and a new object is assigned to an index larger than 128 the overflow occurs. As yr_object_array_set_item() is usually invoked with indexes that increase monotonically by one, this bug never triggered before. But the new "dotnet" module has the potential to allow the exploitation of this bug by scanning a specially crafted .NET binary.
CVE: CVE-2017-11328
CWE: CWE-119
Vulnerability description: Heap buffer overflow in the yr_object_array_set_item() function in object.c in YARA 3.x allows a denial-of-service attack by scanning a crafted .NET file.

Project: yara
File: tests.c

define_function(fsum_2)
{
  double a = float_argument(1);
  double b = float_argument(2);

  return_float(a + b);
}

Project: yara
File: tests.c

define_function(fsum_3)
{
  double a = float_argument(1);
  double b = float_argument(2);
  double c = float_argument(3);

  return_float(a + b + c);
}

Project: yara
File: tests.c

define_function(isum_2)
{
  int64_t a = integer_argument(1);
  int64_t b = integer_argument(2);

  return_integer(a + b);
}

Project: yara
File: tests.c

define_function(isum_3)
{
  int64_t a = integer_argument(1);
  int64_t b = integer_argument(2);
  int64_t c = integer_argument(3);

  return_integer(a + b + c);
}

Project: yara
File: tests.c

define_function(empty)
{
  return_string("");
}

Project: yara
File: tests.c

define_function(match)
{
  return_integer(yr_re_match(regexp_argument(1), string_argument(2)));
}

Project: yara
File: tests.c

define_function(foobar)
{
  int64_t arg = integer_argument(1);

  switch (arg)
  {
    case 1:
      return_string("foo");
      break;
    case 2:
      return_string("bar");
      break;
  }

  return_string("oops")
}

Project: yara
File: tests.c

int module_finalize(
    YR_MODULE* module)
{
  return ERROR_SUCCESS;
}

Project: yara
File: tests.c

int module_initialize(
    YR_MODULE* module)
{
  return ERROR_SUCCESS;
}

Project: yara
File: tests.c

int module_unload(
    YR_OBJECT* module_object)
{
  return ERROR_SUCCESS;
}

Project: yara
File: object.c

YR_OBJECT* _yr_object_lookup(
    YR_OBJECT* object,
    int flags,
    const char* pattern,
    va_list args)
{
  YR_OBJECT* obj = object;

  const char* p = pattern;
  const char* key = NULL;

  char str[256];

  int i;
  int index = -1;

  while (obj != NULL)
  {
    i = 0;

    while(*p != '\0' && *p != '.' && *p != '[' && i < sizeof(str) - 1)
    {
      str[i++] = *p++;
    }

    str[i] = '\0';

    if (obj->type != OBJECT_TYPE_STRUCTURE)
      return NULL;

    obj = yr_object_lookup_field(obj, str);

    if (obj == NULL)
      return NULL;

    if (*p == '[')
    {
      p++;

      if (*p == '%')
      {
        p++;

        switch(*p++)
        {
          case 'i':
            index = va_arg(args, int);
            break;
          case 's':
            key = va_arg(args, const char*);
            break;

          default:
            return NULL;
        }
      }
      else if (*p >= '0' && *p <= '9')
      {
        index = (int) strtol(p, (char**) &p, 10);
      }
      else if (*p == '"')
      {
        i = 0;
        p++;              // skip the opening quotation mark

        while (*p != '"' && *p != '\0' && i < sizeof(str))
          str[i++] = *p++;

        str[i] = '\0';
        p++;              // skip the closing quotation mark
        key = str;
      }
      else
      {
        return NULL;
      }

      assert(*p == ']');
      p++;
      assert(*p == '.' || *p == '\0');

      switch(obj->type)
      {
        case OBJECT_TYPE_ARRAY:
          assert(index != -1);
          obj = yr_object_array_get_item(obj, flags, index);
          break;

        case OBJECT_TYPE_DICTIONARY:
          assert(key != NULL);
          obj = yr_object_dict_get_item(obj, flags, key);
          break;
      }
    }

    if (*p == '\0')
      break;

    p++;
  }

  return obj;
}

Project: yara
File: object.c

YR_OBJECT* yr_object_array_get_item(
    YR_OBJECT* object,
    int flags,
    int index)
{
  YR_OBJECT* result = NULL;
  YR_OBJECT_ARRAY* array;

  assert(object->type == OBJECT_TYPE_ARRAY);

  if (index < 0)
    return NULL;

  array = object_as_array(object);

  if (array->items != NULL && array->items->count > index)
      result = array->items->objects[index];

  if (result == NULL && flags & OBJECT_CREATE)
  {
    yr_object_copy(array->prototype_item, &result);

    if (result != NULL)
      yr_object_array_set_item(object, result, index);
  }

  return result;
}

Project: yara
File: object.c

int yr_object_copy(
    YR_OBJECT* object,
    YR_OBJECT** object_copy)
{
  YR_OBJECT* copy;
  YR_OBJECT* o;

  YR_STRUCTURE_MEMBER* structure_member;

  int i;

  *object_copy = NULL;

  FAIL_ON_ERROR(yr_object_create(
      object->type,
      object->identifier,
      NULL,
      &copy));

  switch(object->type)
  {
    case OBJECT_TYPE_INTEGER:
      copy->value.i = object->value.i;
      break;

    case OBJECT_TYPE_FLOAT:
      copy->value.d = object->value.d;
      break;

    case OBJECT_TYPE_STRING:

      if (object->value.ss != NULL)
        copy->value.ss = sized_string_dup(object->value.ss);
      else
        copy->value.ss = NULL;

      break;

    case OBJECT_TYPE_FUNCTION:

      FAIL_ON_ERROR_WITH_CLEANUP(
          yr_object_copy(
              object_as_function(object)->return_obj,
              &object_as_function(copy)->return_obj),
          yr_object_destroy(copy));

      for (i = 0; i < MAX_OVERLOADED_FUNCTIONS; i++)
        object_as_function(copy)->prototypes[i] = \
            object_as_function(object)->prototypes[i];

      break;

    case OBJECT_TYPE_STRUCTURE:

      structure_member = object_as_structure(object)->members;

      while (structure_member != NULL)
      {
        FAIL_ON_ERROR_WITH_CLEANUP(
            yr_object_copy(structure_member->object, &o),
            yr_object_destroy(copy));

        FAIL_ON_ERROR_WITH_CLEANUP(
            yr_object_structure_set_member(copy, o),
            yr_free(o);
            yr_object_destroy(copy));

        structure_member = structure_member->next;
      }

      break;

    case OBJECT_TYPE_ARRAY:

      FAIL_ON_ERROR_WITH_CLEANUP(
          yr_object_copy(object_as_array(object)->prototype_item, &o),
          yr_object_destroy(copy));

      object_as_array(copy)->prototype_item = o;

      break;

    case OBJECT_TYPE_DICTIONARY:

      FAIL_ON_ERROR_WITH_CLEANUP(
          yr_object_copy(object_as_dictionary(object)->prototype_item, &o),
          yr_object_destroy(copy));

      object_as_dictionary(copy)->prototype_item = o;

      break;

    default:
      assert(FALSE);

  }

  *object_copy = copy;

  return ERROR_SUCCESS;
}

Project: yara
File: object.c

int yr_object_create(
    int8_t type,
    const char* identifier,
    YR_OBJECT* parent,
    YR_OBJECT** object)
{
  YR_OBJECT* obj;
  int i;
  size_t object_size = 0;

  assert(parent != NULL || object != NULL);

  switch (type)
  {
    case OBJECT_TYPE_STRUCTURE:
      object_size = sizeof(YR_OBJECT_STRUCTURE);
      break;
    case OBJECT_TYPE_ARRAY:
      object_size = sizeof(YR_OBJECT_ARRAY);
      break;
    case OBJECT_TYPE_DICTIONARY:
      object_size = sizeof(YR_OBJECT_DICTIONARY);
      break;
    case OBJECT_TYPE_INTEGER:
      object_size = sizeof(YR_OBJECT);
      break;
    case OBJECT_TYPE_FLOAT:
      object_size = sizeof(YR_OBJECT);
      break;
    case OBJECT_TYPE_STRING:
      object_size = sizeof(YR_OBJECT);
      break;
    case OBJECT_TYPE_FUNCTION:
      object_size = sizeof(YR_OBJECT_FUNCTION);
      break;
    default:
      assert(FALSE);
  }

  obj = (YR_OBJECT*) yr_malloc(object_size);

  if (obj == NULL)
    return ERROR_INSUFFICIENT_MEMORY;

  obj->type = type;
  obj->identifier = yr_strdup(identifier);
  obj->parent = parent;
  obj->data = NULL;

  switch(type)
  {
    case OBJECT_TYPE_INTEGER:
      obj->value.i = UNDEFINED;
      break;
    case OBJECT_TYPE_FLOAT:
      obj->value.d = NAN;
      break;
    case OBJECT_TYPE_STRING:
      obj->value.ss = NULL;
      break;
    case OBJECT_TYPE_STRUCTURE:
      object_as_structure(obj)->members = NULL;
      break;
    case OBJECT_TYPE_ARRAY:
      object_as_array(obj)->items = NULL;
      object_as_array(obj)->prototype_item = NULL;
      break;
    case OBJECT_TYPE_DICTIONARY:
      object_as_dictionary(obj)->items = NULL;
      object_as_dictionary(obj)->prototype_item = NULL;
      break;
    case OBJECT_TYPE_FUNCTION:
      object_as_function(obj)->return_obj = NULL;
      for (i = 0; i < MAX_OVERLOADED_FUNCTIONS; i++)
      {
        object_as_function(obj)->prototypes[i].arguments_fmt = NULL;
        object_as_function(obj)->prototypes[i].code = NULL;
      }
      break;
  }

  if (obj->identifier == NULL)
  {
    yr_free(obj);
    return ERROR_INSUFFICIENT_MEMORY;
  }

  if (parent != NULL)
  {
    assert(parent->type == OBJECT_TYPE_STRUCTURE ||
           parent->type == OBJECT_TYPE_ARRAY ||
           parent->type == OBJECT_TYPE_DICTIONARY ||
           parent->type == OBJECT_TYPE_FUNCTION);

    switch(parent->type)
    {
      case OBJECT_TYPE_STRUCTURE:
        FAIL_ON_ERROR_WITH_CLEANUP(
            yr_object_structure_set_member(parent, obj),
            {
              yr_free((void*) obj->identifier);
              yr_free(obj);
            });
        break;

      case OBJECT_TYPE_ARRAY:
        object_as_array(parent)->prototype_item = obj;
        break;

      case OBJECT_TYPE_DICTIONARY:
        object_as_dictionary(parent)->prototype_item = obj;
        break;

      case OBJECT_TYPE_FUNCTION:
        object_as_function(parent)->return_obj = obj;
        break;
    }
  }

  if (object != NULL)
    *object = obj;

  return ERROR_SUCCESS;
}

Project: yara
File: object.c

YR_OBJECT* yr_object_dict_get_item(
    YR_OBJECT* object,
    int flags,
    const char* key)
{
  int i;

  YR_OBJECT* result = NULL;
  YR_OBJECT_DICTIONARY* dict;

  assert(object->type == OBJECT_TYPE_DICTIONARY);

  dict = object_as_dictionary(object);

  if (dict->items != NULL)
  {
    for (i = 0; i < dict->items->used; i++)
    {
      if (strcmp(dict->items->objects[i].key, key) == 0)
        result = dict->items->objects[i].obj;
    }
  }

  if (result == NULL && flags & OBJECT_CREATE)
  {
    yr_object_copy(dict->prototype_item, &result);

    if (result != NULL)
      yr_object_dict_set_item(object, result, key);
  }

  return result;
}

Project: yara
File: object.c

int yr_object_dict_set_item(
    YR_OBJECT* object,
    YR_OBJECT* item,
    const char* key)
{
  YR_OBJECT_DICTIONARY* dict;

  int i;
  int count;

  assert(object->type == OBJECT_TYPE_DICTIONARY);

  dict = object_as_dictionary(object);

  if (dict->items == NULL)
  {
    count = 64;

    dict->items = (YR_DICTIONARY_ITEMS*) yr_malloc(
        sizeof(YR_DICTIONARY_ITEMS) + count * sizeof(dict->items->objects[0]));

    if (dict->items == NULL)
      return ERROR_INSUFFICIENT_MEMORY;

    memset(dict->items->objects, 0, count * sizeof(dict->items->objects[0]));

    dict->items->free = count;
    dict->items->used = 0;
  }
  else if (dict->items->free == 0)
  {
    count = dict->items->used * 2;
    dict->items = (YR_DICTIONARY_ITEMS*) yr_realloc(
        dict->items,
        sizeof(YR_DICTIONARY_ITEMS) + count * sizeof(dict->items->objects[0]));

    if (dict->items == NULL)
      return ERROR_INSUFFICIENT_MEMORY;

    for (i = dict->items->used; i < count; i++)
    {
      dict->items->objects[i].key = NULL;
      dict->items->objects[i].obj = NULL;
    }

    dict->items->free = dict->items->used;
  }

  item->parent = object;

  dict->items->objects[dict->items->used].key = yr_strdup(key);
  dict->items->objects[dict->items->used].obj = item;

  dict->items->used++;
  dict->items->free--;

  return ERROR_SUCCESS;
}

Project: yara
File: object.c

int yr_object_from_external_variable(
    YR_EXTERNAL_VARIABLE* external,
    YR_OBJECT** object)
{
  YR_OBJECT* obj;
  int result;
  uint8_t obj_type = 0;

  switch(external->type)
  {
    case EXTERNAL_VARIABLE_TYPE_INTEGER:
    case EXTERNAL_VARIABLE_TYPE_BOOLEAN:
      obj_type = OBJECT_TYPE_INTEGER;
      break;

    case EXTERNAL_VARIABLE_TYPE_FLOAT:
      obj_type = OBJECT_TYPE_FLOAT;
      break;

    case EXTERNAL_VARIABLE_TYPE_STRING:
    case EXTERNAL_VARIABLE_TYPE_MALLOC_STRING:
      obj_type = OBJECT_TYPE_STRING;
      break;

    default:
      assert(FALSE);
  }

  result = yr_object_create(
      obj_type,
      external->identifier,
      NULL,
      &obj);

  if (result == ERROR_SUCCESS)
  {
    switch(external->type)
    {
      case EXTERNAL_VARIABLE_TYPE_INTEGER:
      case EXTERNAL_VARIABLE_TYPE_BOOLEAN:
        yr_object_set_integer(external->value.i, obj, NULL);
        break;

      case EXTERNAL_VARIABLE_TYPE_FLOAT:
        yr_object_set_float(external->value.f, obj, NULL);
        break;

      case EXTERNAL_VARIABLE_TYPE_STRING:
      case EXTERNAL_VARIABLE_TYPE_MALLOC_STRING:
        yr_object_set_string(
            external->value.s, strlen(external->value.s), obj, NULL);
        break;
    }

    *object = obj;
  }

  return result;
}

Project: yara

int yr_object_function_create(
    const char* identifier,
    const char* arguments_fmt,
    const char* return_fmt,
    YR_MODULE_FUNC code,
    YR_OBJECT* parent,
    YR_OBJECT** function)
{
  YR_OBJECT* return_obj;
  YR_OBJECT* o = NULL;
  YR_OBJECT_FUNCTION* f = NULL;

  int8_t return_type;
  int i;

  switch (*return_fmt)
  {
    case 'i':
      return_type = OBJECT_TYPE_INTEGER;
      break;
    case 's':
      return_type = OBJECT_TYPE_STRING;
      break;
    case 'f':
      return_type = OBJECT_TYPE_FLOAT;
      break;
    default:
      return ERROR_INVALID_FORMAT;
  }

  if (parent != NULL)
  {

    assert(parent->type == OBJECT_TYPE_STRUCTURE);


    f = object_as_function(yr_object_lookup_field(parent, identifier));


    if (f != NULL && return_type != f->return_obj->type)
      return ERROR_WRONG_RETURN_TYPE;
  }

  if (f == NULL) // Function doesn't exist yet
  {
    FAIL_ON_ERROR(
        yr_object_create(
            OBJECT_TYPE_FUNCTION,
            identifier,
            parent,
            &o));

    FAIL_ON_ERROR_WITH_CLEANUP(
        yr_object_create(
            return_type,
            "result",
            o,
            &return_obj),
        yr_object_destroy(o));

    f = object_as_function(o);
  }

  for (i = 0; i < MAX_OVERLOADED_FUNCTIONS; i++)
  {
    if (f->prototypes[i].arguments_fmt == NULL)
    {
      f->prototypes[i].arguments_fmt = arguments_fmt;
      f->prototypes[i].code = code;

      break;
    }
  }

  if (function != NULL)
    *function = (YR_OBJECT*) f;

  return ERROR_SUCCESS;
}

Project: yara
File: object.c

double yr_object_get_float(
    YR_OBJECT* object,
    const char* field,
    ...)
{
  YR_OBJECT* double_obj;

  va_list args;
  va_start(args, field);

  if (field != NULL)
    double_obj = _yr_object_lookup(object, 0, field, args);
  else
    double_obj = object;

  va_end(args);

  if (double_obj == NULL)
    return NAN;

  assertf(double_obj->type == OBJECT_TYPE_FLOAT,
          "type of \"%s\" is not double\n", field);

  return double_obj->value.d;
}

Project: yara
File: object.c

int64_t yr_object_get_integer(
    YR_OBJECT* object,
    const char* field,
    ...)
{
  YR_OBJECT* integer_obj;

  va_list args;
  va_start(args, field);

  if (field != NULL)
    integer_obj = _yr_object_lookup(object, 0, field, args);
  else
    integer_obj = object;

  va_end(args);

  if (integer_obj == NULL)
    return UNDEFINED;

  assertf(integer_obj->type == OBJECT_TYPE_INTEGER,
          "type of \"%s\" is not integer\n", field);

  return integer_obj->value.i;
}

Project: yara
File: object.c

YR_OBJECT* yr_object_get_root(
    YR_OBJECT* object)
{
  YR_OBJECT* o = object;

  while (o->parent != NULL)
    o = o->parent;

  return o;
}

Project: yara
File: object.c

SIZED_STRING* yr_object_get_string(
    YR_OBJECT* object,
    const char* field,
    ...)
{
  YR_OBJECT* string_obj;

  va_list args;
  va_start(args, field);

  if (field != NULL)
    string_obj = _yr_object_lookup(object, 0, field, args);
  else
    string_obj = object;

  va_end(args);

  if (string_obj == NULL)
    return NULL;

  assertf(string_obj->type == OBJECT_TYPE_STRING,
          "type of \"%s\" is not string\n", field);

  return string_obj->value.ss;
}

Project: yara
File: object.c

int yr_object_has_undefined_value(
    YR_OBJECT* object,
    const char* field,
    ...)
{
  YR_OBJECT* field_obj;

  va_list args;
  va_start(args, field);

  if (field != NULL)
    field_obj = _yr_object_lookup(object, 0, field, args);
  else
    field_obj = object;

  va_end(args);

  if (field_obj == NULL)
    return TRUE;

  switch(field_obj->type)
  {
    case OBJECT_TYPE_FLOAT:
      return isnan(field_obj->value.d);
    case OBJECT_TYPE_STRING:
      return field_obj->value.ss == NULL;
    case OBJECT_TYPE_INTEGER:
      return field_obj->value.i == UNDEFINED;
  }

  return FALSE;
}

Project: yara
File: object.c

YR_OBJECT* yr_object_lookup(
    YR_OBJECT* object,
    int flags,
    const char* pattern,
    ...)
{
  YR_OBJECT* result;

  va_list args;
  va_start(args, pattern);

  result = _yr_object_lookup(object, flags, pattern, args);

  va_end(args);

  return result;

}

Project: yara
File: object.c

YR_OBJECT* yr_object_lookup_field(
    YR_OBJECT* object,
    const char* field_name)
{
  YR_STRUCTURE_MEMBER* member;

  assert(object != NULL);
  assert(object->type == OBJECT_TYPE_STRUCTURE);

  member = object_as_structure(object)->members;

  while (member != NULL)
  {
    if (strcmp(member->object->identifier, field_name) == 0)
      return member->object;

    member = member->next;
  }

  return NULL;
}

Project: yara
File: object.c

YR_API void yr_object_print_data(
    YR_OBJECT* object,
    int indent,
    int print_identifier)
{
  YR_DICTIONARY_ITEMS* dict_items;
  YR_ARRAY_ITEMS* array_items;
  YR_STRUCTURE_MEMBER* member;

  char indent_spaces[32];
  int i;

  indent = yr_min(indent, sizeof(indent_spaces) - 1);

  memset(indent_spaces, '\t', indent);
  indent_spaces[indent] = '\0';

  if (print_identifier && object->type != OBJECT_TYPE_FUNCTION)
    printf("%s%s", indent_spaces, object->identifier);

  switch(object->type)
  {
    case OBJECT_TYPE_INTEGER:

      if (object->value.i != UNDEFINED)
        printf(" = %" PRIu64, object->value.i);
      else
        printf(" = UNDEFINED");

      break;

    case OBJECT_TYPE_STRING:

      if (object->value.ss != NULL)
      {
        size_t l;
        printf(" = \"");

        for (l = 0; l < object->value.ss->length; l++)
        {
          char c = object->value.ss->c_string[l];

          if (isprint((unsigned char) c))
            printf("%c", c);
          else
            printf("\\x%02x", (unsigned char) c);
        }

        printf("\"");
      }
      else
      {
        printf(" = UNDEFINED");
      }

      break;

    case OBJECT_TYPE_STRUCTURE:

      member = object_as_structure(object)->members;

      while (member != NULL)
      {
        if (member->object->type != OBJECT_TYPE_FUNCTION)
        {
          printf("\n");
          yr_object_print_data(member->object, indent + 1, 1);
        }
        member = member->next;
      }

      break;

    case OBJECT_TYPE_ARRAY:

      array_items = object_as_array(object)->items;

      if (array_items != NULL)
      {
        for (i = 0; i < array_items->count; i++)
        {
          if (array_items->objects[i] != NULL)
          {
            printf("\n%s\t[%d]", indent_spaces, i);
            yr_object_print_data(array_items->objects[i], indent + 1, 0);
          }
        }
      }

      break;

    case OBJECT_TYPE_DICTIONARY:

      dict_items = object_as_dictionary(object)->items;

      if (dict_items != NULL)
      {
        for (i = 0; i < dict_items->used; i++)
        {
          printf("\n%s\t%s", indent_spaces, dict_items->objects[i].key);
          yr_object_print_data(dict_items->objects[i].obj, indent + 1, 0);
        }
      }

      break;
  }
}

Project: yara
File: object.c

int yr_object_set_float(
    double value,
    YR_OBJECT* object,
    const char* field,
    ...)
{
  YR_OBJECT* double_obj;

  va_list args;
  va_start(args, field);

  if (field != NULL)
    double_obj = _yr_object_lookup(object, OBJECT_CREATE, field, args);
  else
    double_obj = object;

  va_end(args);

  assert(double_obj != NULL);
  assert(double_obj->type == OBJECT_TYPE_FLOAT);

  double_obj->value.d = value;

  return ERROR_SUCCESS;
}

Project: yara
File: object.c

int yr_object_set_string(
    const char* value,
    size_t len,
    YR_OBJECT* object,
    const char* field,
    ...)
{
  YR_OBJECT* string_obj;

  va_list args;
  va_start(args, field);

  if (field != NULL)
    string_obj = _yr_object_lookup(object, OBJECT_CREATE, field, args);
  else
    string_obj = object;

  va_end(args);

  assert(string_obj != NULL);
  assert(string_obj->type == OBJECT_TYPE_STRING);

  if (string_obj->value.ss != NULL)
    yr_free(string_obj->value.ss);

  if (value != NULL)
  {
    string_obj->value.ss = (SIZED_STRING*) yr_malloc(
        len + sizeof(SIZED_STRING));

    if (string_obj->value.ss == NULL)
      return ERROR_INSUFFICIENT_MEMORY;

    string_obj->value.ss->length = (uint32_t) len;
    string_obj->value.ss->flags = 0;

    memcpy(string_obj->value.ss->c_string, value, len);
    string_obj->value.ss->c_string[len] = '\0';
  }
  else
  {
    string_obj->value.ss = NULL;
  }

  return ERROR_SUCCESS;
}

Project: yara

int yr_object_structure_set_member(
    YR_OBJECT* object,
    YR_OBJECT* member)
{
  YR_STRUCTURE_MEMBER* sm;

  assert(object->type == OBJECT_TYPE_STRUCTURE);


  if (yr_object_lookup_field(object,  member->identifier) != NULL)
    return ERROR_DUPLICATED_STRUCTURE_MEMBER;

  sm = (YR_STRUCTURE_MEMBER*) yr_malloc(sizeof(YR_STRUCTURE_MEMBER));

  if (sm == NULL)
    return ERROR_INSUFFICIENT_MEMORY;

  member->parent = object;
  sm->object = member;
  sm->next = object_as_structure(object)->members;

  object_as_structure(object)->members = sm;

  return ERROR_SUCCESS;
}

Project: yara

int main(int argc, char** argv)
{
  yr_initialize();

  test_boolean_operators();
  test_comparison_operators();
  test_arithmetic_operators();
  test_bitwise_operators();
  test_matches_operator();
  test_syntax();
  test_anonymous_strings();
  test_strings();
  test_wildcard_strings();
  test_hex_strings();
  test_count();
  test_at();
  test_in();
  test_offset();
  test_length();
  test_of();
  test_for();
  test_re();
  test_filesize();
  test_comments();
  test_modules();
  test_integer_functions();
  test_entrypoint();
  test_global_rules();

  #if defined(HASH_MODULE)
  test_hash_module();
  #endif

  test_file_descriptor();

  yr_finalize();

  return 0;
}

Project: yara
File: test-rules.c

static void test_anonymous_strings()
{
  assert_true_rule(
      "rule test { strings: $ = \"a\" $ = \"b\" condition: all of them }",
      "ab");
}

Project: yara
File: test-rules.c

static void test_at()
{
  assert_true_rule(
      "rule test { \
        strings: $a = \"ssi\" \
        condition: $a at 2 and $a at 5 }",
      "mississippi");

  assert_true_rule(
      "rule test { \
        strings: $a = \"mis\" \
        condition: $a at ~0xFF & 0xFF }",
      "mississippi");

  assert_true_rule_blob(
      "rule test { \
        strings: $a = { 00 00 00 00 ?? 74 65 78 74 } \
        condition: $a at 308}",
      PE32_FILE);
}

Project: yara
File: test-rules.c

static void test_bitwise_operators()
{
  assert_true_rule(
      "rule test { condition: 0x55 | 0xAA == 0xFF }",
      NULL);

  assert_true_rule(
      "rule test { condition: ~0xAA ^ 0x5A & 0xFF == (~0xAA) ^ (0x5A & 0xFF) }",
      NULL);

  assert_true_rule(
      "rule test { condition: ~0x55 & 0xFF == 0xAA }",
      NULL);

  assert_true_rule(
      "rule test { condition: 8 >> 2 == 2 }",
      NULL);

  assert_true_rule(
      "rule test { condition: 1 << 3 == 8 }",
      NULL);

  assert_true_rule(
      "rule test { condition: 1 | 3 ^ 3 == 1 | (3 ^ 3) }",
      NULL);

  assert_false_rule(
      "rule test { condition: ~0xAA ^ 0x5A & 0xFF == 0x0F }",
      NULL);

  assert_false_rule(
      "rule test { condition: 1 | 3 ^ 3 == (1 | 3) ^ 3}",
      NULL);

}

Project: yara
File: test-rules.c

static void test_boolean_operators()
{
  assert_true_rule(
      "rule test { condition: true }", NULL);

  assert_true_rule(
      "rule test { condition: true or false }", NULL);

  assert_true_rule(
      "rule test { condition: true and true }", NULL);

  assert_true_rule(
      "rule test { condition: 0x1 and 0x2}", NULL);

  assert_false_rule(
      "rule test { condition: false }", NULL);

  assert_false_rule(
      "rule test { condition: true and false }", NULL);

  assert_false_rule(
      "rule test { condition: false or false }", NULL);
}

Project: yara

static void test_comments()
{
  assert_true_rule(
      "rule test {\n\
         condition:\n\
             /*** this is a comment ***/\n\
             /* /* /*\n\
                 this is a comment\n\
             */\n\
             true\n\
      }",
      NULL);
}

Project: yara
File: test-rules.c

static void test_count()
{
  assert_true_rule(
      "rule test { strings: $a = \"ssi\" condition: #a == 2 }",
      "mississippi");
}

Project: yara
File: test-rules.c

static void test_filesize()
{
  char rule[80];

  snprintf(
      rule,
      sizeof(rule),
      "rule test { condition: filesize == %zd }",
      sizeof(PE32_FILE));

  assert_true_rule_blob(
      rule,
      PE32_FILE);
}

Project: yara
File: test-rules.c

static void test_global_rules()
{
  assert_true_rule(
      "global private rule global_rule { \
        condition: \
          true \
      } \
      rule test { \
        condition: true \
      }",
      NULL);

  assert_false_rule(
      "global private rule global_rule { \
        condition: \
          false \
      } \
      rule test { \
        condition: true \
      }",
      NULL);
}

Project: yara

static void test_hash_module()
{
  uint8_t blob[] = {0x61, 0x62, 0x63, 0x64, 0x65};

  assert_true_rule_blob(
      "import \"hash\" \
       rule test { \
        condition: \
          hash.md5(0, filesize) == \
            \"ab56b4d92b40713acc5af89985d4b786\" \
            and \
          hash.md5(1, filesize) == \
            \"e02cfbe5502b64aa5ae9f2d0d69eaa8d\" \
            and \
          hash.sha1(0, filesize) == \
            \"03de6c570bfe24bfc328ccd7ca46b76eadaf4334\" \
            and \
          hash.sha1(1, filesize) == \
            \"a302d65ae4d9e768a1538d53605f203fd8e2d6e2\" \
            and \
          hash.sha256(0, filesize) == \
            \"36bbe50ed96841d10443bcb670d6554f0a34b761be67ec9c4a8ad2c0c44ca42c\" \
            and \
          hash.sha256(1, filesize) == \
            \"aaaaf2863e043b9df604158ad5c16ff1adaf3fd7e9fcea5dcb322b6762b3b59a\" \
      }",
      blob);


  assert_true_rule_blob(
      "import \"hash\" \
       rule test { \
        condition: \
          hash.md5(0, filesize) == \
            \"ab56b4d92b40713acc5af89985d4b786\" \
            and \
          hash.md5(1, filesize) == \
            \"e02cfbe5502b64aa5ae9f2d0d69eaa8d\" \
            and \
          hash.md5(0, filesize) == \
            \"ab56b4d92b40713acc5af89985d4b786\" \
            and \
          hash.md5(1, filesize) == \
            \"e02cfbe5502b64aa5ae9f2d0d69eaa8d\" \
      }",
      blob);
}