1 /*
2 Copyright (c) 2013. The YARA Authors. All Rights Reserved.
3 
4 Redistribution and use in source and binary forms, with or without modification,
5 are permitted provided that the following conditions are met:
6 
7 1. Redistributions of source code must retain the above copyright notice, this
8 list of conditions and the following disclaimer.
9 
10 2. Redistributions in binary form must reproduce the above copyright notice,
11 this list of conditions and the following disclaimer in the documentation and/or
12 other materials provided with the distribution.
13 
14 3. Neither the name of the copyright holder nor the names of its contributors
15 may be used to endorse or promote products derived from this software without
16 specific prior written permission.
17 
18 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
22 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
25 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29 
30 #include <limits.h>
31 #include <stddef.h>
32 #include <string.h>
33 #include <yara/ahocorasick.h>
34 #include <yara/arena.h>
35 #include <yara/base64.h>
36 #include <yara/error.h>
37 #include <yara/exec.h>
38 #include <yara/integers.h>
39 #include <yara/mem.h>
40 #include <yara/modules.h>
41 #include <yara/object.h>
42 #include <yara/parser.h>
43 #include <yara/re.h>
44 #include <yara/strutils.h>
45 #include <yara/utils.h>
46 
47 #define todigit(x) \
48   ((x) >= 'A' && (x) <= 'F') ? ((uint8_t)(x - 'A' + 10)) : ((uint8_t)(x - '0'))
49 
yr_parser_emit(yyscan_t yyscanner,uint8_t instruction,YR_ARENA_REF * instruction_ref)50 int yr_parser_emit(
51     yyscan_t yyscanner,
52     uint8_t instruction,
53     YR_ARENA_REF* instruction_ref)
54 {
55   return yr_arena_write_data(
56       yyget_extra(yyscanner)->arena,
57       YR_CODE_SECTION,
58       &instruction,
59       sizeof(uint8_t),
60       instruction_ref);
61 }
62 
yr_parser_emit_with_arg_double(yyscan_t yyscanner,uint8_t instruction,double argument,YR_ARENA_REF * instruction_ref,YR_ARENA_REF * argument_ref)63 int yr_parser_emit_with_arg_double(
64     yyscan_t yyscanner,
65     uint8_t instruction,
66     double argument,
67     YR_ARENA_REF* instruction_ref,
68     YR_ARENA_REF* argument_ref)
69 {
70   int result = yr_arena_write_data(
71       yyget_extra(yyscanner)->arena,
72       YR_CODE_SECTION,
73       &instruction,
74       sizeof(uint8_t),
75       instruction_ref);
76 
77   if (result == ERROR_SUCCESS)
78     result = yr_arena_write_data(
79         yyget_extra(yyscanner)->arena,
80         YR_CODE_SECTION,
81         &argument,
82         sizeof(double),
83         argument_ref);
84 
85   return result;
86 }
87 
yr_parser_emit_with_arg_int32(yyscan_t yyscanner,uint8_t instruction,int32_t argument,YR_ARENA_REF * instruction_ref,YR_ARENA_REF * argument_ref)88 int yr_parser_emit_with_arg_int32(
89     yyscan_t yyscanner,
90     uint8_t instruction,
91     int32_t argument,
92     YR_ARENA_REF* instruction_ref,
93     YR_ARENA_REF* argument_ref)
94 {
95   int result = yr_arena_write_data(
96       yyget_extra(yyscanner)->arena,
97       YR_CODE_SECTION,
98       &instruction,
99       sizeof(uint8_t),
100       instruction_ref);
101 
102   if (result == ERROR_SUCCESS)
103     result = yr_arena_write_data(
104         yyget_extra(yyscanner)->arena,
105         YR_CODE_SECTION,
106         &argument,
107         sizeof(int32_t),
108         argument_ref);
109 
110   return result;
111 }
112 
yr_parser_emit_with_arg(yyscan_t yyscanner,uint8_t instruction,int64_t argument,YR_ARENA_REF * instruction_ref,YR_ARENA_REF * argument_ref)113 int yr_parser_emit_with_arg(
114     yyscan_t yyscanner,
115     uint8_t instruction,
116     int64_t argument,
117     YR_ARENA_REF* instruction_ref,
118     YR_ARENA_REF* argument_ref)
119 {
120   int result = yr_arena_write_data(
121       yyget_extra(yyscanner)->arena,
122       YR_CODE_SECTION,
123       &instruction,
124       sizeof(uint8_t),
125       instruction_ref);
126 
127   if (result == ERROR_SUCCESS)
128     result = yr_arena_write_data(
129         yyget_extra(yyscanner)->arena,
130         YR_CODE_SECTION,
131         &argument,
132         sizeof(int64_t),
133         argument_ref);
134 
135   return result;
136 }
137 
yr_parser_emit_with_arg_reloc(yyscan_t yyscanner,uint8_t instruction,void * argument,YR_ARENA_REF * instruction_ref,YR_ARENA_REF * argument_ref)138 int yr_parser_emit_with_arg_reloc(
139     yyscan_t yyscanner,
140     uint8_t instruction,
141     void* argument,
142     YR_ARENA_REF* instruction_ref,
143     YR_ARENA_REF* argument_ref)
144 {
145   YR_ARENA_REF ref = YR_ARENA_NULL_REF;
146 
147   DECLARE_REFERENCE(void*, ptr) arg;
148 
149   memset(&arg, 0, sizeof(arg));
150   arg.ptr = argument;
151 
152   int result = yr_arena_write_data(
153       yyget_extra(yyscanner)->arena,
154       YR_CODE_SECTION,
155       &instruction,
156       sizeof(uint8_t),
157       instruction_ref);
158 
159   if (result == ERROR_SUCCESS)
160     result = yr_arena_write_data(
161         yyget_extra(yyscanner)->arena,
162         YR_CODE_SECTION,
163         &arg,
164         sizeof(arg),
165         &ref);
166 
167   if (result == ERROR_SUCCESS)
168     result = yr_arena_make_ptr_relocatable(
169         yyget_extra(yyscanner)->arena, YR_CODE_SECTION, ref.offset, EOL);
170 
171   if (argument_ref != NULL)
172     *argument_ref = ref;
173 
174   return result;
175 }
176 
yr_parser_emit_pushes_for_strings(yyscan_t yyscanner,const char * identifier)177 int yr_parser_emit_pushes_for_strings(
178     yyscan_t yyscanner,
179     const char* identifier)
180 {
181   YR_COMPILER* compiler = yyget_extra(yyscanner);
182 
183   YR_RULE* current_rule = _yr_compiler_get_rule_by_idx(
184       compiler, compiler->current_rule_idx);
185 
186   YR_STRING* string;
187 
188   const char* string_identifier;
189   const char* target_identifier;
190 
191   int matching = 0;
192 
193   yr_rule_strings_foreach(current_rule, string)
194   {
195     // Don't generate pushes for strings chained to another one, we are
196     // only interested in non-chained strings or the head of the chain.
197 
198     if (string->chained_to == NULL)
199     {
200       string_identifier = string->identifier;
201       target_identifier = identifier;
202 
203       while (*target_identifier != '\0' && *string_identifier != '\0' &&
204              *target_identifier == *string_identifier)
205       {
206         target_identifier++;
207         string_identifier++;
208       }
209 
210       if ((*target_identifier == '\0' && *string_identifier == '\0') ||
211           *target_identifier == '*')
212       {
213         yr_parser_emit_with_arg_reloc(yyscanner, OP_PUSH, string, NULL, NULL);
214 
215         string->flags |= STRING_FLAGS_REFERENCED;
216         string->flags &= ~STRING_FLAGS_FIXED_OFFSET;
217         matching++;
218       }
219     }
220   }
221 
222   if (matching == 0)
223   {
224     yr_compiler_set_error_extra_info(
225         compiler, identifier) return ERROR_UNDEFINED_STRING;
226   }
227 
228   return ERROR_SUCCESS;
229 }
230 
yr_parser_emit_push_const(yyscan_t yyscanner,uint64_t argument)231 int yr_parser_emit_push_const(yyscan_t yyscanner, uint64_t argument)
232 {
233   uint64_t u = (uint64_t) argument;
234   uint8_t buf[9];
235   int bufsz = 1;
236   if (u == YR_UNDEFINED)
237   {
238     buf[0] = OP_PUSH_U;
239   }
240   else if (u <= 0xff)
241   {
242     buf[0] = OP_PUSH_8;
243     bufsz += sizeof(uint8_t);
244     buf[1] = (uint8_t) argument;
245   }
246   else if (u <= 0xffff)
247   {
248     buf[0] = OP_PUSH_16;
249     bufsz += sizeof(uint16_t);
250     *((uint16_t*) (buf + 1)) = (uint16_t) argument;
251   }
252   else if (u <= 0xffffffff)
253   {
254     buf[0] = OP_PUSH_32;
255     bufsz += sizeof(uint32_t);
256     *((uint32_t*) (buf + 1)) = (uint32_t) argument;
257   }
258   else
259   {
260     buf[0] = OP_PUSH;
261     bufsz += sizeof(uint64_t);
262     *((uint64_t*) (buf + 1)) = (uint64_t) argument;
263   }
264   return yr_arena_write_data(
265       yyget_extra(yyscanner)->arena, YR_CODE_SECTION, buf, bufsz, NULL);
266 }
267 
yr_parser_check_types(YR_COMPILER * compiler,YR_OBJECT_FUNCTION * function,const char * actual_args_fmt)268 int yr_parser_check_types(
269     YR_COMPILER* compiler,
270     YR_OBJECT_FUNCTION* function,
271     const char* actual_args_fmt)
272 {
273   int i;
274 
275   for (i = 0; i < YR_MAX_OVERLOADED_FUNCTIONS; i++)
276   {
277     if (function->prototypes[i].arguments_fmt == NULL)
278       break;
279 
280     if (strcmp(function->prototypes[i].arguments_fmt, actual_args_fmt) == 0)
281       return ERROR_SUCCESS;
282   }
283 
284   yr_compiler_set_error_extra_info(compiler, function->identifier)
285 
286       return ERROR_WRONG_ARGUMENTS;
287 }
288 
yr_parser_lookup_string(yyscan_t yyscanner,const char * identifier,YR_STRING ** string)289 int yr_parser_lookup_string(
290     yyscan_t yyscanner,
291     const char* identifier,
292     YR_STRING** string)
293 {
294   YR_COMPILER* compiler = yyget_extra(yyscanner);
295 
296   YR_RULE* current_rule = _yr_compiler_get_rule_by_idx(
297       compiler, compiler->current_rule_idx);
298 
299   yr_rule_strings_foreach(current_rule, *string)
300   {
301     // If some string $a gets fragmented into multiple chained
302     // strings, all those fragments have the same $a identifier
303     // but we are interested in the heading fragment, which is
304     // that with chained_to == NULL
305 
306     if ((*string)->chained_to == NULL &&
307         strcmp((*string)->identifier, identifier) == 0)
308     {
309       return ERROR_SUCCESS;
310     }
311   }
312 
313   yr_compiler_set_error_extra_info(compiler, identifier)
314 
315       * string = NULL;
316 
317   return ERROR_UNDEFINED_STRING;
318 }
319 
320 ////////////////////////////////////////////////////////////////////////////////
321 // Searches for a variable with the given identifier in the scope of the current
322 // "for" loop. In case of nested "for" loops the identifier is searched starting
323 // at the top-level loop and going down thorough the nested loops until the
324 // current one. This is ok because inner loops can not re-define an identifier
325 // already defined by an outer loop.
326 //
327 // If the variable is found, the return value is the position that the variable
328 // occupies among all the currently defined variables. If the variable doesn't
329 // exist the return value is -1.
330 //
331 // The function can receive a pointer to a YR_EXPRESSION that will populated
332 // with information about the variable if found. This pointer can be NULL if
333 // the caller is not interested in getting that information.
334 //
yr_parser_lookup_loop_variable(yyscan_t yyscanner,const char * identifier,YR_EXPRESSION * expr)335 int yr_parser_lookup_loop_variable(
336     yyscan_t yyscanner,
337     const char* identifier,
338     YR_EXPRESSION* expr)
339 {
340   YR_COMPILER* compiler = yyget_extra(yyscanner);
341   int i, j;
342   int var_offset = 0;
343 
344   for (i = 0; i <= compiler->loop_index; i++)
345   {
346     var_offset += compiler->loop[i].vars_internal_count;
347 
348     for (j = 0; j < compiler->loop[i].vars_count; j++)
349     {
350       if (compiler->loop[i].vars[j].identifier.ptr != NULL &&
351           strcmp(identifier, compiler->loop[i].vars[j].identifier.ptr) == 0)
352       {
353         if (expr != NULL)
354           *expr = compiler->loop[i].vars[j];
355 
356         return var_offset + j;
357       }
358     }
359 
360     var_offset += compiler->loop[i].vars_count;
361   }
362 
363   return -1;
364 }
365 
_yr_parser_write_string(const char * identifier,YR_MODIFIER modifier,YR_COMPILER * compiler,SIZED_STRING * str,RE_AST * re_ast,YR_ARENA_REF * string_ref,int * min_atom_quality,int * num_atom)366 static int _yr_parser_write_string(
367     const char* identifier,
368     YR_MODIFIER modifier,
369     YR_COMPILER* compiler,
370     SIZED_STRING* str,
371     RE_AST* re_ast,
372     YR_ARENA_REF* string_ref,
373     int* min_atom_quality,
374     int* num_atom)
375 {
376   SIZED_STRING* literal_string;
377   YR_ATOM_LIST_ITEM* atom;
378   YR_ATOM_LIST_ITEM* atom_list = NULL;
379 
380   int c, result;
381   int max_string_len;
382   bool free_literal = false;
383 
384   FAIL_ON_ERROR(yr_arena_allocate_struct(
385       compiler->arena,
386       YR_STRINGS_TABLE,
387       sizeof(YR_STRING),
388       string_ref,
389       offsetof(YR_STRING, identifier),
390       offsetof(YR_STRING, string),
391       offsetof(YR_STRING, chained_to),
392       EOL));
393 
394   YR_STRING* string = (YR_STRING*) yr_arena_ref_to_ptr(
395       compiler->arena, string_ref);
396 
397   YR_ARENA_REF ref;
398 
399   FAIL_ON_ERROR(_yr_compiler_store_string(compiler, identifier, &ref));
400 
401   string->identifier = (const char*) yr_arena_ref_to_ptr(compiler->arena, &ref);
402 
403   if (modifier.flags & STRING_FLAGS_HEXADECIMAL ||
404       modifier.flags & STRING_FLAGS_REGEXP ||
405       modifier.flags & STRING_FLAGS_BASE64 ||
406       modifier.flags & STRING_FLAGS_BASE64_WIDE)
407   {
408     literal_string = yr_re_ast_extract_literal(re_ast);
409 
410     if (literal_string != NULL)
411     {
412       modifier.flags |= STRING_FLAGS_LITERAL;
413       free_literal = true;
414     }
415     else
416     {
417       // Non-literal strings can't be marked as fixed offset because once we
418       // find a string atom in the scanned data we don't know the offset where
419       // the string should start, as the non-literal strings can contain
420       // variable-length portions.
421 
422       modifier.flags &= ~STRING_FLAGS_FIXED_OFFSET;
423     }
424   }
425   else
426   {
427     literal_string = str;
428     modifier.flags |= STRING_FLAGS_LITERAL;
429   }
430 
431   string->flags = modifier.flags;
432   string->rule_idx = compiler->current_rule_idx;
433   string->idx = compiler->current_string_idx;
434   string->fixed_offset = YR_UNDEFINED;
435   string->chained_to = NULL;
436   string->string = NULL;
437 
438   if (modifier.flags & STRING_FLAGS_LITERAL)
439   {
440     result = _yr_compiler_store_data(
441         compiler,
442         literal_string->c_string,
443         literal_string->length + 1,  // +1 to include terminating NULL
444         &ref);
445 
446     string->length = (uint32_t) literal_string->length;
447     string->string = (uint8_t*) yr_arena_ref_to_ptr(compiler->arena, &ref);
448 
449     if (result == ERROR_SUCCESS)
450     {
451       result = yr_atoms_extract_from_string(
452           &compiler->atoms_config,
453           (uint8_t*) literal_string->c_string,
454           (int32_t) literal_string->length,
455           modifier,
456           &atom_list,
457           min_atom_quality);
458     }
459   }
460   else
461   {
462     // Emit forwards code
463     result = yr_re_ast_emit_code(re_ast, compiler->arena, false);
464 
465     // Emit backwards code
466     if (result == ERROR_SUCCESS)
467       result = yr_re_ast_emit_code(re_ast, compiler->arena, true);
468 
469     if (result == ERROR_SUCCESS)
470       result = yr_atoms_extract_from_re(
471           &compiler->atoms_config,
472           re_ast,
473           modifier,
474           &atom_list,
475           min_atom_quality);
476   }
477 
478   if (result == ERROR_SUCCESS)
479   {
480     // Add the string to Aho-Corasick automaton.
481     result = yr_ac_add_string(
482         compiler->automaton,
483         string,
484         compiler->current_string_idx,
485         atom_list,
486         compiler->arena);
487   }
488 
489   if (modifier.flags & STRING_FLAGS_LITERAL)
490   {
491     if (modifier.flags & STRING_FLAGS_WIDE)
492       max_string_len = string->length * 2;
493     else
494       max_string_len = string->length;
495 
496     if (max_string_len <= YR_MAX_ATOM_LENGTH)
497       string->flags |= STRING_FLAGS_FITS_IN_ATOM;
498   }
499 
500   atom = atom_list;
501   c = 0;
502 
503   while (atom != NULL)
504   {
505     atom = atom->next;
506     c++;
507   }
508 
509   (*num_atom) += c;
510 
511   compiler->current_string_idx++;
512 
513   if (free_literal)
514     yr_free(literal_string);
515 
516   if (atom_list != NULL)
517     yr_atoms_list_destroy(atom_list);
518 
519   return result;
520 }
521 
yr_parser_reduce_string_declaration(yyscan_t yyscanner,YR_MODIFIER modifier,const char * identifier,SIZED_STRING * str,YR_ARENA_REF * string_ref)522 int yr_parser_reduce_string_declaration(
523     yyscan_t yyscanner,
524     YR_MODIFIER modifier,
525     const char* identifier,
526     SIZED_STRING* str,
527     YR_ARENA_REF* string_ref)
528 {
529   int result = ERROR_SUCCESS;
530   int min_atom_quality = YR_MAX_ATOM_QUALITY;
531   int atom_quality;
532 
533   char message[512];
534 
535   int32_t min_gap = 0;
536   int32_t max_gap = 0;
537 
538   YR_COMPILER* compiler = yyget_extra(yyscanner);
539 
540   RE_AST* re_ast = NULL;
541   RE_AST* remainder_re_ast = NULL;
542   RE_ERROR re_error;
543 
544   YR_RULE* current_rule = _yr_compiler_get_rule_by_idx(
545       compiler, compiler->current_rule_idx);
546 
547   // Determine if a string with the same identifier was already defined
548   // by searching for the identifier in strings_table.
549   uint32_t string_idx = yr_hash_table_lookup_uint32(
550       compiler->strings_table, identifier, NULL);
551 
552   // The string was already defined, return an error.
553   if (string_idx != UINT32_MAX)
554   {
555     result = ERROR_DUPLICATED_STRING_IDENTIFIER;
556     yr_compiler_set_error_extra_info(compiler, identifier) goto _exit;
557   }
558 
559   // Empty strings are not allowed.
560   if (str->length == 0)
561   {
562     result = ERROR_EMPTY_STRING;
563     yr_compiler_set_error_extra_info(compiler, identifier) goto _exit;
564   }
565 
566   // If string identifier is $ this is an anonymous string, if not add the
567   // identifier to strings_table.
568   if (strcmp(identifier, "$") == 0)
569   {
570     modifier.flags |= STRING_FLAGS_ANONYMOUS;
571   }
572   else
573   {
574     result = yr_hash_table_add_uint32(
575         compiler->strings_table,
576         identifier,
577         NULL,
578         compiler->current_string_idx);
579 
580     if (result != ERROR_SUCCESS)
581       goto _exit;
582   }
583 
584   if (str->flags & SIZED_STRING_FLAGS_NO_CASE)
585     modifier.flags |= STRING_FLAGS_NO_CASE;
586 
587   if (str->flags & SIZED_STRING_FLAGS_DOT_ALL)
588     modifier.flags |= STRING_FLAGS_DOT_ALL;
589 
590   // Hex strings are always handled as DOT_ALL regexps.
591   if (modifier.flags & STRING_FLAGS_HEXADECIMAL)
592     modifier.flags |= STRING_FLAGS_DOT_ALL;
593 
594   // xor and nocase together is not implemented.
595   if (modifier.flags & STRING_FLAGS_XOR &&
596       modifier.flags & STRING_FLAGS_NO_CASE)
597   {
598     result = ERROR_INVALID_MODIFIER;
599     yr_compiler_set_error_extra_info(
600         compiler, "invalid modifier combination: xor nocase") goto _exit;
601   }
602 
603   // base64 and nocase together is not implemented.
604   if (modifier.flags & STRING_FLAGS_NO_CASE &&
605       (modifier.flags & STRING_FLAGS_BASE64 ||
606        modifier.flags & STRING_FLAGS_BASE64_WIDE))
607   {
608     result = ERROR_INVALID_MODIFIER;
609     yr_compiler_set_error_extra_info(
610         compiler,
611         modifier.flags & STRING_FLAGS_BASE64
612             ? "invalid modifier combination: base64 nocase"
613             : "invalid modifier combination: base64wide nocase") goto _exit;
614   }
615 
616   // base64 and fullword together is not implemented.
617   if (modifier.flags & STRING_FLAGS_FULL_WORD &&
618       (modifier.flags & STRING_FLAGS_BASE64 ||
619        modifier.flags & STRING_FLAGS_BASE64_WIDE))
620   {
621     result = ERROR_INVALID_MODIFIER;
622     yr_compiler_set_error_extra_info(
623         compiler,
624         modifier.flags & STRING_FLAGS_BASE64
625             ? "invalid modifier combination: base64 fullword"
626             : "invalid modifier combination: base64wide fullword") goto _exit;
627   }
628 
629   // base64 and xor together is not implemented.
630   if (modifier.flags & STRING_FLAGS_XOR &&
631       (modifier.flags & STRING_FLAGS_BASE64 ||
632        modifier.flags & STRING_FLAGS_BASE64_WIDE))
633   {
634     result = ERROR_INVALID_MODIFIER;
635     yr_compiler_set_error_extra_info(
636         compiler,
637         modifier.flags & STRING_FLAGS_BASE64
638             ? "invalid modifier combination: base64 xor"
639             : "invalid modifier combination: base64wide xor") goto _exit;
640   }
641 
642   if (!(modifier.flags & STRING_FLAGS_WIDE) &&
643       !(modifier.flags & STRING_FLAGS_XOR) &&
644       !(modifier.flags & STRING_FLAGS_BASE64 ||
645         modifier.flags & STRING_FLAGS_BASE64_WIDE))
646   {
647     modifier.flags |= STRING_FLAGS_ASCII;
648   }
649 
650   // The STRING_FLAGS_SINGLE_MATCH flag indicates that finding
651   // a single match for the string is enough. This is true in
652   // most cases, except when the string count (#) and string offset (@)
653   // operators are used. All strings are marked STRING_FLAGS_SINGLE_MATCH
654   // initially, and unmarked later if required.
655   modifier.flags |= STRING_FLAGS_SINGLE_MATCH;
656 
657   // The STRING_FLAGS_FIXED_OFFSET indicates that the string doesn't
658   // need to be searched all over the file because the user is using the
659   // "at" operator. The string must be searched at a fixed offset in the
660   // file. All strings are marked STRING_FLAGS_FIXED_OFFSET initially,
661   // and unmarked later if required.
662   modifier.flags |= STRING_FLAGS_FIXED_OFFSET;
663 
664   if (modifier.flags & STRING_FLAGS_HEXADECIMAL ||
665       modifier.flags & STRING_FLAGS_REGEXP ||
666       modifier.flags & STRING_FLAGS_BASE64 ||
667       modifier.flags & STRING_FLAGS_BASE64_WIDE)
668   {
669     if (modifier.flags & STRING_FLAGS_HEXADECIMAL)
670       result = yr_re_parse_hex(str->c_string, &re_ast, &re_error);
671     else if (modifier.flags & STRING_FLAGS_REGEXP)
672       result = yr_re_parse(str->c_string, &re_ast, &re_error);
673     else
674       result = yr_base64_ast_from_string(str, modifier, &re_ast, &re_error);
675 
676     if (result != ERROR_SUCCESS)
677     {
678       snprintf(
679           message,
680           sizeof(message),
681           "invalid %s \"%s\": %s",
682           (modifier.flags & STRING_FLAGS_HEXADECIMAL) ? "hex string"
683                                                       : "regular expression",
684           identifier,
685           re_error.message);
686 
687       yr_compiler_set_error_extra_info(compiler, message)
688 
689           goto _exit;
690     }
691 
692     if (re_ast->flags & RE_FLAGS_FAST_REGEXP)
693       modifier.flags |= STRING_FLAGS_FAST_REGEXP;
694 
695     if (re_ast->flags & RE_FLAGS_GREEDY)
696       modifier.flags |= STRING_FLAGS_GREEDY_REGEXP;
697 
698     // Regular expressions in the strings section can't mix greedy and ungreedy
699     // quantifiers like .* and .*?. That's because these regular expressions can
700     // be matched forwards and/or backwards depending on the atom found, and we
701     // need the regexp to be all-greedy or all-ungreedy to be able to properly
702     // calculate the length of the match.
703 
704     if ((re_ast->flags & RE_FLAGS_GREEDY) &&
705         (re_ast->flags & RE_FLAGS_UNGREEDY))
706     {
707       result = ERROR_INVALID_REGULAR_EXPRESSION;
708 
709       yr_compiler_set_error_extra_info(
710           compiler,
711           "greedy and ungreedy quantifiers can't be mixed in a regular "
712           "expression")
713 
714           goto _exit;
715     }
716 
717     if (yr_re_ast_has_unbounded_quantifier_for_dot(re_ast))
718     {
719       yywarning(
720           yyscanner,
721           "%s contains .*, .+ or .{x,} consider using .{,N}, .{1,N} or {x,N} "
722           "with a reasonable value for N",
723           identifier);
724     }
725 
726     if (compiler->re_ast_callback != NULL)
727     {
728       compiler->re_ast_callback(
729           current_rule, identifier, re_ast, compiler->re_ast_clbk_user_data);
730     }
731 
732     *string_ref = YR_ARENA_NULL_REF;
733 
734     while (re_ast != NULL)
735     {
736       YR_ARENA_REF ref;
737 
738       uint32_t prev_string_idx = compiler->current_string_idx - 1;
739 
740       int32_t prev_min_gap = min_gap;
741       int32_t prev_max_gap = max_gap;
742 
743       result = yr_re_ast_split_at_chaining_point(
744           re_ast, &remainder_re_ast, &min_gap, &max_gap);
745 
746       if (result != ERROR_SUCCESS)
747         goto _exit;
748 
749       result = _yr_parser_write_string(
750           identifier,
751           modifier,
752           compiler,
753           NULL,
754           re_ast,
755           &ref,
756           &atom_quality,
757           &current_rule->num_atoms);
758 
759       if (result != ERROR_SUCCESS)
760         goto _exit;
761 
762       if (atom_quality < min_atom_quality)
763         min_atom_quality = atom_quality;
764 
765       if (YR_ARENA_IS_NULL_REF(*string_ref))
766       {
767         // This is the first string in the chain, the string reference returned
768         // by this function must point to this string.
769         *string_ref = ref;
770       }
771       else
772       {
773         // This is not the first string in the chain, set the appropriate flags
774         // and fill the chained_to, chain_gap_min and chain_gap_max fields.
775         YR_STRING* prev_string = (YR_STRING*) yr_arena_get_ptr(
776             compiler->arena,
777             YR_STRINGS_TABLE,
778             prev_string_idx * sizeof(YR_STRING));
779 
780         YR_STRING* new_string = (YR_STRING*) yr_arena_ref_to_ptr(
781             compiler->arena, &ref);
782 
783         new_string->chained_to = prev_string;
784         new_string->chain_gap_min = prev_min_gap;
785         new_string->chain_gap_max = prev_max_gap;
786 
787         // A string chained to another one can't have a fixed offset, only the
788         // head of the string chain can have a fixed offset.
789         new_string->flags &= ~STRING_FLAGS_FIXED_OFFSET;
790 
791         // There is a previous string, but that string wasn't marked as part of
792         // a chain because we can't do that until knowing there will be another
793         // string, let's flag it now the we know.
794         prev_string->flags |= STRING_FLAGS_CHAIN_PART;
795 
796         // There is a previous string, so this string is part of a chain, but
797         // there will be no more strings because there are no more AST to split,
798         // which means that this is the chain's tail.
799         if (remainder_re_ast == NULL)
800           new_string->flags |= STRING_FLAGS_CHAIN_PART |
801                                STRING_FLAGS_CHAIN_TAIL;
802       }
803 
804       yr_re_ast_destroy(re_ast);
805       re_ast = remainder_re_ast;
806     }
807   }
808   else  // not a STRING_FLAGS_HEXADECIMAL or STRING_FLAGS_REGEXP or
809         // STRING_FLAGS_BASE64 or STRING_FLAGS_BASE64_WIDE
810   {
811     result = _yr_parser_write_string(
812         identifier,
813         modifier,
814         compiler,
815         str,
816         NULL,
817         string_ref,
818         &min_atom_quality,
819         &current_rule->num_atoms);
820 
821     if (result != ERROR_SUCCESS)
822       goto _exit;
823   }
824 
825   if (min_atom_quality < compiler->atoms_config.quality_warning_threshold)
826   {
827     yywarning(yyscanner, "string \"%s\" may slow down scanning", identifier);
828   }
829 
830 _exit:
831 
832   if (re_ast != NULL)
833     yr_re_ast_destroy(re_ast);
834 
835   if (remainder_re_ast != NULL)
836     yr_re_ast_destroy(remainder_re_ast);
837 
838   return result;
839 }
840 
yr_parser_reduce_rule_declaration_phase_1(yyscan_t yyscanner,int32_t flags,const char * identifier,YR_ARENA_REF * rule_ref)841 int yr_parser_reduce_rule_declaration_phase_1(
842     yyscan_t yyscanner,
843     int32_t flags,
844     const char* identifier,
845     YR_ARENA_REF* rule_ref)
846 {
847   YR_FIXUP* fixup;
848   YR_COMPILER* compiler = yyget_extra(yyscanner);
849 
850   YR_NAMESPACE* ns = (YR_NAMESPACE*) yr_arena_get_ptr(
851       compiler->arena,
852       YR_NAMESPACES_TABLE,
853       compiler->current_namespace_idx * sizeof(struct YR_NAMESPACE));
854 
855   if (yr_hash_table_lookup_uint32(
856           compiler->rules_table, identifier, ns->name) != UINT32_MAX ||
857       yr_hash_table_lookup(compiler->objects_table, identifier, NULL) != NULL)
858   {
859     // A rule or variable with the same identifier already exists, return the
860     // appropriate error.
861 
862     yr_compiler_set_error_extra_info(
863         compiler, identifier) return ERROR_DUPLICATED_IDENTIFIER;
864   }
865 
866   FAIL_ON_ERROR(yr_arena_allocate_struct(
867       compiler->arena,
868       YR_RULES_TABLE,
869       sizeof(YR_RULE),
870       rule_ref,
871       offsetof(YR_RULE, identifier),
872       offsetof(YR_RULE, tags),
873       offsetof(YR_RULE, strings),
874       offsetof(YR_RULE, metas),
875       offsetof(YR_RULE, ns),
876       EOL));
877 
878   YR_RULE* rule = (YR_RULE*) yr_arena_ref_to_ptr(compiler->arena, rule_ref);
879 
880   YR_ARENA_REF ref;
881 
882   FAIL_ON_ERROR(_yr_compiler_store_string(compiler, identifier, &ref));
883 
884   rule->identifier = (const char*) yr_arena_ref_to_ptr(compiler->arena, &ref);
885   rule->flags = flags;
886   rule->ns = ns;
887   rule->num_atoms = 0;
888 
889   YR_ARENA_REF jmp_offset_ref;
890 
891   // We are starting to parse a new rule, set current_rule_idx accordingly.
892   compiler->current_rule_idx = compiler->next_rule_idx;
893   compiler->next_rule_idx++;
894 
895   // The OP_INIT_RULE instruction behaves like a jump. When the rule is disabled
896   // it skips over the rule's code and go straight to the next rule's code. The
897   // jmp_offset_ref variable points to the jump's offset. The offset is set to 0
898   // as we don't know the jump target yet. When we finish generating the rule's
899   // code in yr_parser_reduce_rule_declaration_phase_2 the jump offset is set to
900   // its final value.
901 
902   FAIL_ON_ERROR(yr_parser_emit_with_arg_int32(
903       yyscanner, OP_INIT_RULE, 0, NULL, &jmp_offset_ref));
904 
905   FAIL_ON_ERROR(yr_arena_write_data(
906       compiler->arena,
907       YR_CODE_SECTION,
908       &compiler->current_rule_idx,
909       sizeof(compiler->current_rule_idx),
910       NULL));
911 
912   // Create a fixup entry for the jump and push it in the stack
913   fixup = (YR_FIXUP*) yr_malloc(sizeof(YR_FIXUP));
914 
915   if (fixup == NULL)
916     return ERROR_INSUFFICIENT_MEMORY;
917 
918   fixup->ref = jmp_offset_ref;
919   fixup->next = compiler->fixup_stack_head;
920   compiler->fixup_stack_head = fixup;
921 
922   // Clean strings_table as we are starting to parse a new rule.
923   yr_hash_table_clean(compiler->strings_table, NULL);
924 
925   FAIL_ON_ERROR(yr_hash_table_add_uint32(
926       compiler->rules_table, identifier, ns->name, compiler->current_rule_idx));
927 
928   return ERROR_SUCCESS;
929 }
930 
yr_parser_reduce_rule_declaration_phase_2(yyscan_t yyscanner,YR_ARENA_REF * rule_ref)931 int yr_parser_reduce_rule_declaration_phase_2(
932     yyscan_t yyscanner,
933     YR_ARENA_REF* rule_ref)
934 {
935   uint32_t max_strings_per_rule;
936   uint32_t strings_in_rule = 0;
937 
938   YR_FIXUP* fixup;
939   YR_STRING* string;
940   YR_COMPILER* compiler = yyget_extra(yyscanner);
941 
942   yr_get_configuration(
943       YR_CONFIG_MAX_STRINGS_PER_RULE, (void*) &max_strings_per_rule);
944 
945   YR_RULE* rule = (YR_RULE*) yr_arena_ref_to_ptr(compiler->arena, rule_ref);
946 
947   // Show warning if the rule is generating too many atoms. The warning is
948   // shown if the number of atoms is greater than 20 times the maximum number
949   // of strings allowed for a rule, as 20 is minimum number of atoms generated
950   // for a string using *nocase*, *ascii* and *wide* modifiers simultaneously.
951 
952   if (rule->num_atoms > YR_ATOMS_PER_RULE_WARNING_THRESHOLD)
953   {
954     yywarning(yyscanner, "rule is slowing down scanning");
955   }
956 
957   yr_rule_strings_foreach(rule, string)
958   {
959     // Only the heading fragment in a chain of strings (the one with
960     // chained_to == NULL) must be referenced. All other fragments
961     // are never marked as referenced.
962 
963     if (!STRING_IS_REFERENCED(string) && string->chained_to == NULL)
964     {
965       yr_compiler_set_error_extra_info(
966           compiler, string->identifier) return ERROR_UNREFERENCED_STRING;
967     }
968 
969     strings_in_rule++;
970 
971     if (strings_in_rule > max_strings_per_rule)
972     {
973       yr_compiler_set_error_extra_info(
974           compiler, rule->identifier) return ERROR_TOO_MANY_STRINGS;
975     }
976   }
977 
978   FAIL_ON_ERROR(yr_parser_emit_with_arg(
979       yyscanner, OP_MATCH_RULE, compiler->current_rule_idx, NULL, NULL));
980 
981   fixup = compiler->fixup_stack_head;
982 
983   int32_t* jmp_offset_addr = (int32_t*) yr_arena_ref_to_ptr(
984       compiler->arena, &fixup->ref);
985 
986   int32_t jmp_offset = yr_arena_get_current_offset(
987                            compiler->arena, YR_CODE_SECTION) -
988                        fixup->ref.offset + 1;
989 
990   *jmp_offset_addr = jmp_offset;
991 
992   // Remove fixup from the stack.
993   compiler->fixup_stack_head = fixup->next;
994   yr_free(fixup);
995 
996   // We have finished parsing the current rule set current_rule_idx to
997   // UINT32_MAX indicating that we are not currently parsing a rule.
998   compiler->current_rule_idx = UINT32_MAX;
999 
1000   return ERROR_SUCCESS;
1001 }
1002 
yr_parser_reduce_string_identifier(yyscan_t yyscanner,const char * identifier,uint8_t instruction,uint64_t at_offset)1003 int yr_parser_reduce_string_identifier(
1004     yyscan_t yyscanner,
1005     const char* identifier,
1006     uint8_t instruction,
1007     uint64_t at_offset)
1008 {
1009   YR_STRING* string;
1010   YR_COMPILER* compiler = yyget_extra(yyscanner);
1011 
1012   if (strcmp(identifier, "$") == 0)  // is an anonymous string ?
1013   {
1014     if (compiler->loop_for_of_var_index >= 0)  // inside a loop ?
1015     {
1016       yr_parser_emit_with_arg(
1017           yyscanner, OP_PUSH_M, compiler->loop_for_of_var_index, NULL, NULL);
1018 
1019       yr_parser_emit(yyscanner, instruction, NULL);
1020 
1021       YR_RULE* current_rule = _yr_compiler_get_rule_by_idx(
1022           compiler, compiler->current_rule_idx);
1023 
1024       yr_rule_strings_foreach(current_rule, string)
1025       {
1026         if (instruction != OP_FOUND)
1027           string->flags &= ~STRING_FLAGS_SINGLE_MATCH;
1028 
1029         if (instruction == OP_FOUND_AT)
1030         {
1031           // Avoid overwriting any previous fixed offset
1032           if (string->fixed_offset == YR_UNDEFINED)
1033             string->fixed_offset = at_offset;
1034 
1035           // If a previous fixed offset was different, disable
1036           // the STRING_GFLAGS_FIXED_OFFSET flag because we only
1037           // have room to store a single fixed offset value
1038           if (string->fixed_offset != at_offset)
1039             string->flags &= ~STRING_FLAGS_FIXED_OFFSET;
1040         }
1041         else
1042         {
1043           string->flags &= ~STRING_FLAGS_FIXED_OFFSET;
1044         }
1045       }
1046     }
1047     else
1048     {
1049       // Anonymous strings not allowed outside of a loop
1050       return ERROR_MISPLACED_ANONYMOUS_STRING;
1051     }
1052   }
1053   else
1054   {
1055     FAIL_ON_ERROR(yr_parser_lookup_string(yyscanner, identifier, &string));
1056 
1057     FAIL_ON_ERROR(
1058         yr_parser_emit_with_arg_reloc(yyscanner, OP_PUSH, string, NULL, NULL));
1059 
1060     if (instruction != OP_FOUND)
1061       string->flags &= ~STRING_FLAGS_SINGLE_MATCH;
1062 
1063     if (instruction == OP_FOUND_AT)
1064     {
1065       // Avoid overwriting any previous fixed offset
1066 
1067       if (string->fixed_offset == YR_UNDEFINED)
1068         string->fixed_offset = at_offset;
1069 
1070       // If a previous fixed offset was different, disable
1071       // the STRING_GFLAGS_FIXED_OFFSET flag because we only
1072       // have room to store a single fixed offset value
1073 
1074       if (string->fixed_offset == YR_UNDEFINED ||
1075           string->fixed_offset != at_offset)
1076       {
1077         string->flags &= ~STRING_FLAGS_FIXED_OFFSET;
1078       }
1079     }
1080     else
1081     {
1082       string->flags &= ~STRING_FLAGS_FIXED_OFFSET;
1083     }
1084 
1085     FAIL_ON_ERROR(yr_parser_emit(yyscanner, instruction, NULL));
1086 
1087     string->flags |= STRING_FLAGS_REFERENCED;
1088   }
1089 
1090   return ERROR_SUCCESS;
1091 }
1092 
yr_parser_reduce_meta_declaration(yyscan_t yyscanner,int32_t type,const char * identifier,const char * string,int64_t integer,YR_ARENA_REF * meta_ref)1093 int yr_parser_reduce_meta_declaration(
1094     yyscan_t yyscanner,
1095     int32_t type,
1096     const char* identifier,
1097     const char* string,
1098     int64_t integer,
1099     YR_ARENA_REF* meta_ref)
1100 {
1101   YR_ARENA_REF ref;
1102   YR_COMPILER* compiler = yyget_extra(yyscanner);
1103 
1104   FAIL_ON_ERROR(yr_arena_allocate_struct(
1105       compiler->arena,
1106       YR_METAS_TABLE,
1107       sizeof(YR_META),
1108       meta_ref,
1109       offsetof(YR_META, identifier),
1110       offsetof(YR_META, string),
1111       EOL));
1112 
1113   YR_META* meta = (YR_META*) yr_arena_ref_to_ptr(compiler->arena, meta_ref);
1114 
1115   meta->type = type;
1116   meta->integer = integer;
1117 
1118   FAIL_ON_ERROR(_yr_compiler_store_string(compiler, identifier, &ref));
1119 
1120   meta->identifier = (const char*) yr_arena_ref_to_ptr(compiler->arena, &ref);
1121 
1122   if (string != NULL)
1123   {
1124     FAIL_ON_ERROR(_yr_compiler_store_string(compiler, string, &ref));
1125 
1126     meta->string = (const char*) yr_arena_ref_to_ptr(compiler->arena, &ref);
1127   }
1128   else
1129   {
1130     meta->string = NULL;
1131   }
1132 
1133   compiler->current_meta_idx++;
1134 
1135   return ERROR_SUCCESS;
1136 }
1137 
_yr_parser_valid_module_name(SIZED_STRING * module_name)1138 static int _yr_parser_valid_module_name(SIZED_STRING* module_name)
1139 {
1140   if (module_name->length == 0)
1141     return false;
1142 
1143   if (strlen(module_name->c_string) != module_name->length)
1144     return false;
1145 
1146   return true;
1147 }
1148 
yr_parser_reduce_import(yyscan_t yyscanner,SIZED_STRING * module_name)1149 int yr_parser_reduce_import(yyscan_t yyscanner, SIZED_STRING* module_name)
1150 {
1151   int result;
1152 
1153   YR_ARENA_REF ref;
1154   YR_COMPILER* compiler = yyget_extra(yyscanner);
1155   YR_OBJECT* module_structure;
1156 
1157   if (!_yr_parser_valid_module_name(module_name))
1158   {
1159     yr_compiler_set_error_extra_info(compiler, module_name->c_string);
1160 
1161     return ERROR_INVALID_MODULE_NAME;
1162   }
1163 
1164   YR_NAMESPACE* ns = (YR_NAMESPACE*) yr_arena_get_ptr(
1165       compiler->arena,
1166       YR_NAMESPACES_TABLE,
1167       compiler->current_namespace_idx * sizeof(struct YR_NAMESPACE));
1168 
1169   module_structure = (YR_OBJECT*) yr_hash_table_lookup(
1170       compiler->objects_table, module_name->c_string, ns->name);
1171 
1172   // if module already imported, do nothing
1173 
1174   if (module_structure != NULL)
1175     return ERROR_SUCCESS;
1176 
1177   FAIL_ON_ERROR(yr_object_create(
1178       OBJECT_TYPE_STRUCTURE, module_name->c_string, NULL, &module_structure));
1179 
1180   FAIL_ON_ERROR(yr_hash_table_add(
1181       compiler->objects_table,
1182       module_name->c_string,
1183       ns->name,
1184       module_structure));
1185 
1186   result = yr_modules_do_declarations(module_name->c_string, module_structure);
1187 
1188   if (result == ERROR_UNKNOWN_MODULE)
1189     yr_compiler_set_error_extra_info(compiler, module_name->c_string);
1190 
1191   if (result != ERROR_SUCCESS)
1192     return result;
1193 
1194   FAIL_ON_ERROR(
1195       _yr_compiler_store_string(compiler, module_name->c_string, &ref));
1196 
1197   FAIL_ON_ERROR(yr_parser_emit_with_arg_reloc(
1198       yyscanner,
1199       OP_IMPORT,
1200       yr_arena_ref_to_ptr(compiler->arena, &ref),
1201       NULL,
1202       NULL));
1203 
1204   return ERROR_SUCCESS;
1205 }
1206 
_yr_parser_operator_to_opcode(const char * op,int expression_type)1207 static int _yr_parser_operator_to_opcode(const char* op, int expression_type)
1208 {
1209   int opcode = 0;
1210 
1211   switch (expression_type)
1212   {
1213   case EXPRESSION_TYPE_INTEGER:
1214     opcode = OP_INT_BEGIN;
1215     break;
1216   case EXPRESSION_TYPE_FLOAT:
1217     opcode = OP_DBL_BEGIN;
1218     break;
1219   case EXPRESSION_TYPE_STRING:
1220     opcode = OP_STR_BEGIN;
1221     break;
1222   default:
1223     assert(false);
1224   }
1225 
1226   if (op[0] == '<')
1227   {
1228     if (op[1] == '=')
1229       opcode += _OP_LE;
1230     else
1231       opcode += _OP_LT;
1232   }
1233   else if (op[0] == '>')
1234   {
1235     if (op[1] == '=')
1236       opcode += _OP_GE;
1237     else
1238       opcode += _OP_GT;
1239   }
1240   else if (op[1] == '=')
1241   {
1242     if (op[0] == '=')
1243       opcode += _OP_EQ;
1244     else
1245       opcode += _OP_NEQ;
1246   }
1247   else if (op[0] == '+')
1248   {
1249     opcode += _OP_ADD;
1250   }
1251   else if (op[0] == '-')
1252   {
1253     opcode += _OP_SUB;
1254   }
1255   else if (op[0] == '*')
1256   {
1257     opcode += _OP_MUL;
1258   }
1259   else if (op[0] == '\\')
1260   {
1261     opcode += _OP_DIV;
1262   }
1263 
1264   if (IS_INT_OP(opcode) || IS_DBL_OP(opcode) || IS_STR_OP(opcode))
1265   {
1266     return opcode;
1267   }
1268 
1269   return OP_ERROR;
1270 }
1271 
yr_parser_reduce_operation(yyscan_t yyscanner,const char * op,YR_EXPRESSION left_operand,YR_EXPRESSION right_operand)1272 int yr_parser_reduce_operation(
1273     yyscan_t yyscanner,
1274     const char* op,
1275     YR_EXPRESSION left_operand,
1276     YR_EXPRESSION right_operand)
1277 {
1278   int expression_type;
1279 
1280   YR_COMPILER* compiler = yyget_extra(yyscanner);
1281 
1282   if ((left_operand.type == EXPRESSION_TYPE_INTEGER ||
1283        left_operand.type == EXPRESSION_TYPE_FLOAT) &&
1284       (right_operand.type == EXPRESSION_TYPE_INTEGER ||
1285        right_operand.type == EXPRESSION_TYPE_FLOAT))
1286   {
1287     if (left_operand.type != right_operand.type)
1288     {
1289       // One operand is double and the other is integer,
1290       // cast the integer to double
1291 
1292       FAIL_ON_ERROR(yr_parser_emit_with_arg(
1293           yyscanner,
1294           OP_INT_TO_DBL,
1295           (left_operand.type == EXPRESSION_TYPE_INTEGER) ? 2 : 1,
1296           NULL,
1297           NULL));
1298     }
1299 
1300     expression_type = EXPRESSION_TYPE_FLOAT;
1301 
1302     if (left_operand.type == EXPRESSION_TYPE_INTEGER &&
1303         right_operand.type == EXPRESSION_TYPE_INTEGER)
1304     {
1305       expression_type = EXPRESSION_TYPE_INTEGER;
1306     }
1307 
1308     FAIL_ON_ERROR(yr_parser_emit(
1309         yyscanner, _yr_parser_operator_to_opcode(op, expression_type), NULL));
1310   }
1311   else if (
1312       left_operand.type == EXPRESSION_TYPE_STRING &&
1313       right_operand.type == EXPRESSION_TYPE_STRING)
1314   {
1315     int opcode = _yr_parser_operator_to_opcode(op, EXPRESSION_TYPE_STRING);
1316 
1317     if (opcode != OP_ERROR)
1318     {
1319       FAIL_ON_ERROR(yr_parser_emit(yyscanner, opcode, NULL));
1320     }
1321     else
1322     {
1323       yr_compiler_set_error_extra_info_fmt(
1324           compiler, "strings don't support \"%s\" operation", op);
1325 
1326       return ERROR_WRONG_TYPE;
1327     }
1328   }
1329   else
1330   {
1331     yr_compiler_set_error_extra_info(compiler, "type mismatch");
1332 
1333     return ERROR_WRONG_TYPE;
1334   }
1335 
1336   return ERROR_SUCCESS;
1337 }
1338