YR_EXTERNAL_VARIABLE* yr_parser_lookup_external_variable( yyscan_t yyscanner, const char* identifier) { YR_EXTERNAL_VARIABLE* external; YR_COMPILER* compiler = yyget_extra(yyscanner); int i; external = (YR_EXTERNAL_VARIABLE*) yr_arena_base_address( compiler->externals_arena); for (i = 0; i < compiler->externals_count; i++) { if (strcmp(external->identifier, identifier) == 0) return external; external = yr_arena_next_address( compiler->externals_arena, external, sizeof(YR_EXTERNAL_VARIABLE)); } yr_compiler_set_error_extra_info(compiler, identifier); compiler->last_result = ERROR_UNDEFINED_IDENTIFIER; return NULL; }
int yr_parser_emit_pushes_for_strings( yyscan_t yyscanner, const char* identifier) { YR_COMPILER* compiler = yyget_extra(yyscanner); YR_STRING* string = compiler->current_rule->strings; const char* string_identifier; const char* target_identifier; int matching = 0; while(!STRING_IS_NULL(string)) { // Don't generate pushes for strings chained to another one, we are // only interested in non-chained strings or the head of the chain. if (string->chained_to == NULL) { string_identifier = string->identifier; target_identifier = identifier; while (*target_identifier != '\0' && *string_identifier != '\0' && *target_identifier == *string_identifier) { target_identifier++; string_identifier++; } if ((*target_identifier == '\0' && *string_identifier == '\0') || *target_identifier == '*') { yr_parser_emit_with_arg_reloc( yyscanner, OP_PUSH, PTR_TO_INT64(string), NULL, NULL); string->g_flags |= STRING_GFLAGS_REFERENCED; string->g_flags &= ~STRING_GFLAGS_FIXED_OFFSET; matching++; } } string = (YR_STRING*) yr_arena_next_address( compiler->strings_arena, string, sizeof(YR_STRING)); } if (matching == 0) { yr_compiler_set_error_extra_info(compiler, identifier); compiler->last_result = ERROR_UNDEFINED_STRING; } return compiler->last_result; }
YR_STRING* yr_parser_lookup_string( yyscan_t yyscanner, const char* identifier) { YR_STRING* string; YR_COMPILER* compiler = yyget_extra(yyscanner); string = compiler->current_rule_strings; while(!STRING_IS_NULL(string)) { // If some string $a gets fragmented into multiple chained // strings, all those fragments have the same $a identifier // but we are interested in the heading fragment, which is // that with chained_to == NULL if (strcmp(string->identifier, identifier) == 0 && string->chained_to == NULL) { return string; } string = yr_arena_next_address( compiler->strings_arena, string, sizeof(YR_STRING)); } yr_compiler_set_error_extra_info(compiler, identifier); compiler->last_result = ERROR_UNDEFINED_STRING; return NULL; }
YR_STRING* yr_parser_lookup_string( yyscan_t yyscanner, const char* identifier) { YR_STRING* string; YR_COMPILER* compiler = yyget_extra(yyscanner); string = compiler->current_rule_strings; while(!STRING_IS_NULL(string)) { if (strcmp(string->identifier, identifier) == 0) return string; string = yr_arena_next_address( compiler->strings_arena, string, sizeof(YR_STRING)); } yr_compiler_set_error_extra_info(compiler, identifier); compiler->last_result = ERROR_UNDEFINED_STRING; return NULL; }
int _yr_compiler_set_namespace( YR_COMPILER* compiler, const char* namespace_) { YR_NAMESPACE* ns; char* ns_name; int result; int i; int found; ns = (YR_NAMESPACE*) yr_arena_base_address(compiler->namespaces_arena); found = FALSE; for (i = 0; i < compiler->namespaces_count; i++) { if (strcmp(ns->name, namespace_) == 0) { found = TRUE; break; } ns = (YR_NAMESPACE*) yr_arena_next_address( compiler->namespaces_arena, ns, sizeof(YR_NAMESPACE)); } if (!found) { result = yr_arena_write_string( compiler->sz_arena, namespace_, &ns_name); if (result == ERROR_SUCCESS) result = yr_arena_allocate_struct( compiler->namespaces_arena, sizeof(YR_NAMESPACE), (void**) &ns, offsetof(YR_NAMESPACE, name), EOL); if (result != ERROR_SUCCESS) return result; ns->name = ns_name; for (i = 0; i < MAX_THREADS; i++) ns->t_flags[i] = 0; compiler->namespaces_count++; } compiler->current_namespace = ns; return ERROR_SUCCESS; }
int yr_parser_reduce_rule_declaration_phase_2( yyscan_t yyscanner, YR_RULE* rule) { uint32_t max_strings_per_rule; uint32_t strings_in_rule = 0; YR_COMPILER* compiler = yyget_extra(yyscanner); // Check for unreferenced (unused) strings. YR_STRING* string = rule->strings; yr_get_configuration( YR_CONFIG_MAX_STRINGS_PER_RULE, (void*) &max_strings_per_rule); while (!STRING_IS_NULL(string)) { // Only the heading fragment in a chain of strings (the one with // chained_to == NULL) must be referenced. All other fragments // are never marked as referenced. if (!STRING_IS_REFERENCED(string) && string->chained_to == NULL) { yr_compiler_set_error_extra_info(compiler, string->identifier); compiler->last_result = ERROR_UNREFERENCED_STRING; return compiler->last_result; } strings_in_rule++; if (strings_in_rule > max_strings_per_rule) { yr_compiler_set_error_extra_info(compiler, rule->identifier); compiler->last_result = ERROR_TOO_MANY_STRINGS; return compiler->last_result; } string = (YR_STRING*) yr_arena_next_address( compiler->strings_arena, string, sizeof(YR_STRING)); } compiler->last_result = yr_parser_emit_with_arg_reloc( yyscanner, OP_MATCH_RULE, rule, NULL, NULL); return compiler->last_result; }
void yr_parser_emit_pushes_for_strings( yyscan_t yyscanner, const char* identifier) { YR_COMPILER* compiler = yyget_extra(yyscanner); YR_STRING* string = compiler->current_rule_strings; const char* string_identifier; const char* target_identifier; while(!STRING_IS_NULL(string)) { string_identifier = string->identifier; target_identifier = identifier; while (*target_identifier != '\0' && *string_identifier != '\0' && *target_identifier == *string_identifier) { target_identifier++; string_identifier++; } if ((*target_identifier == '\0' && *string_identifier == '\0') || *target_identifier == '*') { yr_parser_emit_with_arg_reloc( yyscanner, PUSH, PTR_TO_UINT64(string), NULL); string->g_flags |= STRING_GFLAGS_REFERENCED; } string = yr_arena_next_address( compiler->strings_arena, string, sizeof(YR_STRING)); } }
int yr_parser_reduce_string_identifier( yyscan_t yyscanner, const char* identifier, int8_t instruction) { YR_STRING* string; YR_COMPILER* compiler = yyget_extra(yyscanner); if (strcmp(identifier, "$") == 0) { if (compiler->loop_depth > 0) { yr_parser_emit_with_arg( yyscanner, PUSH_M, LOOP_LOCAL_VARS * (compiler->loop_depth - 1), NULL); yr_parser_emit(yyscanner, instruction, NULL); if (instruction != SFOUND) { string = compiler->current_rule_strings; while(!STRING_IS_NULL(string)) { string->g_flags &= ~STRING_GFLAGS_SINGLE_MATCH; string = yr_arena_next_address( compiler->strings_arena, string, sizeof(YR_STRING)); } } } else { compiler->last_result = ERROR_MISPLACED_ANONYMOUS_STRING; } } else { string = yr_parser_lookup_string(yyscanner, identifier); if (string != NULL) { yr_parser_emit_with_arg_reloc( yyscanner, PUSH, PTR_TO_UINT64(string), NULL); if (instruction != SFOUND) string->g_flags &= ~STRING_GFLAGS_SINGLE_MATCH; yr_parser_emit(yyscanner, instruction, NULL); string->g_flags |= STRING_GFLAGS_REFERENCED; } } return compiler->last_result; }
int yr_parser_reduce_rule_declaration( yyscan_t yyscanner, int32_t flags, const char* identifier, char* tags, YR_STRING* strings, YR_META* metas) { YR_COMPILER* compiler = yyget_extra(yyscanner); YR_RULE* rule; YR_STRING* string; if (yr_hash_table_lookup( compiler->rules_table, identifier, compiler->current_namespace->name) != NULL) { // A rule with the same identifier already exists, return the // appropriate error. yr_compiler_set_error_extra_info(compiler, identifier); compiler->last_result = ERROR_DUPLICATE_RULE_IDENTIFIER; return compiler->last_result; } // Check for unreferenced (unused) strings. string = compiler->current_rule_strings; while(!STRING_IS_NULL(string)) { // Only the heading fragment in a chain of strings (the one with // chained_to == NULL) must be referenced. All other fragments // are never marked as referenced. if (!STRING_IS_REFERENCED(string) && string->chained_to == NULL) { yr_compiler_set_error_extra_info(compiler, string->identifier); compiler->last_result = ERROR_UNREFERENCED_STRING; break; } string = yr_arena_next_address( compiler->strings_arena, string, sizeof(YR_STRING)); } if (compiler->last_result != ERROR_SUCCESS) return compiler->last_result; compiler->last_result = yr_arena_allocate_struct( compiler->rules_arena, sizeof(YR_RULE), (void**) &rule, offsetof(YR_RULE, identifier), offsetof(YR_RULE, tags), offsetof(YR_RULE, strings), offsetof(YR_RULE, metas), offsetof(YR_RULE, ns), EOL); if (compiler->last_result != ERROR_SUCCESS) return compiler->last_result; compiler->last_result = yr_arena_write_string( compiler->sz_arena, identifier, &rule->identifier); if (compiler->last_result != ERROR_SUCCESS) return compiler->last_result; compiler->last_result = yr_parser_emit_with_arg_reloc( yyscanner, RULE_POP, PTR_TO_UINT64(rule), NULL); if (compiler->last_result != ERROR_SUCCESS) return compiler->last_result; rule->g_flags = flags | compiler->current_rule_flags; rule->tags = tags; rule->strings = strings; rule->metas = metas; rule->ns = compiler->current_namespace; compiler->current_rule_flags = 0; compiler->current_rule_strings = NULL; yr_hash_table_add( compiler->rules_table, identifier, compiler->current_namespace->name, (void*) rule); return compiler->last_result; }
int yr_parser_reduce_string_identifier( yyscan_t yyscanner, const char* identifier, uint8_t instruction, uint64_t at_offset) { YR_STRING* string; YR_COMPILER* compiler = yyget_extra(yyscanner); if (strcmp(identifier, "$") == 0) // is an anonymous string ? { if (compiler->loop_for_of_mem_offset >= 0) // inside a loop ? { yr_parser_emit_with_arg( yyscanner, OP_PUSH_M, compiler->loop_for_of_mem_offset, NULL, NULL); yr_parser_emit(yyscanner, instruction, NULL); string = compiler->current_rule->strings; while(!STRING_IS_NULL(string)) { if (instruction != OP_FOUND) string->g_flags &= ~STRING_GFLAGS_SINGLE_MATCH; if (instruction == OP_FOUND_AT) { // Avoid overwriting any previous fixed offset if (string->fixed_offset == UNDEFINED) string->fixed_offset = at_offset; // If a previous fixed offset was different, disable // the STRING_GFLAGS_FIXED_OFFSET flag because we only // have room to store a single fixed offset value if (string->fixed_offset != at_offset) string->g_flags &= ~STRING_GFLAGS_FIXED_OFFSET; } else { string->g_flags &= ~STRING_GFLAGS_FIXED_OFFSET; } string = (YR_STRING*) yr_arena_next_address( compiler->strings_arena, string, sizeof(YR_STRING)); } } else { // Anonymous strings not allowed outside of a loop compiler->last_result = ERROR_MISPLACED_ANONYMOUS_STRING; } } else { string = yr_parser_lookup_string(yyscanner, identifier); if (string != NULL) { yr_parser_emit_with_arg_reloc( yyscanner, OP_PUSH, PTR_TO_INT64(string), NULL, NULL); if (instruction != OP_FOUND) string->g_flags &= ~STRING_GFLAGS_SINGLE_MATCH; if (instruction == OP_FOUND_AT) { // Avoid overwriting any previous fixed offset if (string->fixed_offset == UNDEFINED) string->fixed_offset = at_offset; // If a previous fixed offset was different, disable // the STRING_GFLAGS_FIXED_OFFSET flag because we only // have room to store a single fixed offset value if (string->fixed_offset == UNDEFINED || string->fixed_offset != at_offset) { string->g_flags &= ~STRING_GFLAGS_FIXED_OFFSET; } } else { string->g_flags &= ~STRING_GFLAGS_FIXED_OFFSET; } yr_parser_emit(yyscanner, instruction, NULL); string->g_flags |= STRING_GFLAGS_REFERENCED; } } return compiler->last_result; }
int yr_parser_reduce_rule_declaration_phase_2( yyscan_t yyscanner, YR_RULE* rule) { uint32_t max_strings_per_rule; uint32_t strings_in_rule = 0; uint8_t* nop_inst_addr = NULL; int result; YR_FIXUP *fixup; YR_STRING* string; YR_COMPILER* compiler = yyget_extra(yyscanner); yr_get_configuration( YR_CONFIG_MAX_STRINGS_PER_RULE, (void*) &max_strings_per_rule); // Show warning if the rule is generating too many atoms. The warning is // shown if the number of atoms is greater than 20 times the maximum number // of strings allowed for a rule, as 20 is minimum number of atoms generated // for a string using *nocase*, *ascii* and *wide* modifiers simultaneosly. if (rule->num_atoms > YR_ATOMS_PER_RULE_WARNING_THRESHOLD) { yywarning( yyscanner, "rule %s is slowing down scanning", rule->identifier); } // Check for unreferenced (unused) strings. string = rule->strings; while (!STRING_IS_NULL(string)) { // Only the heading fragment in a chain of strings (the one with // chained_to == NULL) must be referenced. All other fragments // are never marked as referenced. if (!STRING_IS_REFERENCED(string) && string->chained_to == NULL) { yr_compiler_set_error_extra_info(compiler, string->identifier); return ERROR_UNREFERENCED_STRING; } strings_in_rule++; if (strings_in_rule > max_strings_per_rule) { yr_compiler_set_error_extra_info(compiler, rule->identifier); return ERROR_TOO_MANY_STRINGS; } string = (YR_STRING*) yr_arena_next_address( compiler->strings_arena, string, sizeof(YR_STRING)); } result = yr_parser_emit_with_arg_reloc( yyscanner, OP_MATCH_RULE, rule, NULL, NULL); // Generate a do-nothing instruction (NOP) in order to get its address // and use it as the destination for the OP_INIT_RULE skip jump. We can not // simply use the address of the OP_MATCH_RULE instruction +1 because we // can't be sure that the instruction following the OP_MATCH_RULE is going to // be in the same arena page. As we don't have a reliable way of getting the // address of the next instruction we generate the OP_NOP. if (result == ERROR_SUCCESS) result = yr_parser_emit(yyscanner, OP_NOP, &nop_inst_addr); fixup = compiler->fixup_stack_head; *(void**)(fixup->address) = (void*) nop_inst_addr; compiler->fixup_stack_head = fixup->next; yr_free(fixup); return result; }