Coverage Report

Created: 2026-05-30 06:36

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/yara/libyara/scanner.c
Line
Count
Source
1
/*
2
Copyright (c) 2018. 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 <stdlib.h>
31
#include <yara/ahocorasick.h>
32
#include <yara/error.h>
33
#include <yara/exec.h>
34
#include <yara/exefiles.h>
35
#include <yara/libyara.h>
36
#include <yara/mem.h>
37
#include <yara/object.h>
38
#include <yara/proc.h>
39
#include <yara/scanner.h>
40
#include <yara/strutils.h>
41
#include <yara/types.h>
42
43
#include "exception.h"
44
45
static int _yr_scanner_scan_mem_block(
46
    YR_SCANNER* scanner,
47
    const uint8_t* block_data,
48
    YR_MEMORY_BLOCK* block)
49
16.4k
{
50
16.4k
  YR_DEBUG_FPRINTF(
51
16.4k
      2,
52
16.4k
      stderr,
53
16.4k
      "+ %s(block_data=%p block->base=0x%" PRIx64 " block->size=%zu) {\n",
54
16.4k
      __FUNCTION__,
55
16.4k
      block_data,
56
16.4k
      block->base,
57
16.4k
      block->size);
58
59
16.4k
  int result = ERROR_SUCCESS;
60
61
16.4k
  YR_RULES* rules = scanner->rules;
62
16.4k
  YR_AC_TRANSITION* transition_table = rules->ac_transition_table;
63
16.4k
  uint32_t* match_table = rules->ac_match_table;
64
65
16.4k
  YR_AC_MATCH* match;
66
16.4k
  YR_AC_TRANSITION transition;
67
68
16.4k
  size_t i = 0;
69
16.4k
  uint32_t state = YR_AC_ROOT_STATE;
70
16.4k
  uint16_t index;
71
16.4k
  YR_STRING* report_string = NULL;
72
16.4k
  YR_RULE* rule = NULL;
73
74
250M
  while (i < block->size)
75
250M
  {
76
250M
    if (i % 4096 == 0 && scanner->timeout > 0)
77
0
    {
78
0
      if (yr_stopwatch_elapsed_ns(&scanner->stopwatch) > scanner->timeout)
79
0
      {
80
0
        result = ERROR_SCAN_TIMEOUT;
81
0
        goto _exit;
82
0
      }
83
0
    }
84
85
#if 2 == YR_DEBUG_VERBOSITY
86
    if (0 != state)
87
      YR_DEBUG_FPRINTF(
88
          2,
89
          stderr,
90
          "- match_table[state=%u]=%'u i=%'ld "
91
          "block_data=%p block->base=0x%" PRIx64 " // %s()\n",
92
          state,
93
          match_table[state],
94
          i,
95
          block_data,
96
          block->base,
97
          __FUNCTION__);
98
#endif
99
100
250M
    if (match_table[state] != 0)
101
0
    {
102
      // If the entry corresponding to state N in the match table is zero, it
103
      // means that there's no match associated to the state. If it's non-zero,
104
      // its value is the 1-based index within ac_match_pool where the first
105
      // match resides.
106
107
0
      match = &rules->ac_match_pool[match_table[state] - 1];
108
109
0
      if (scanner->matches->count >= YR_SLOW_STRING_MATCHES)
110
0
      {
111
0
        report_string = match->string;
112
0
        rule = report_string
113
0
                   ? &scanner->rules->rules_table[report_string->rule_idx]
114
0
                   : NULL;
115
0
      }
116
117
0
      while (match != NULL)
118
0
      {
119
0
        if (match->backtrack <= i)
120
0
        {
121
0
          GOTO_EXIT_ON_ERROR(yr_scan_verify_match(
122
0
              scanner,
123
0
              match,
124
0
              block_data,
125
0
              block->size,
126
0
              block->base,
127
0
              i - match->backtrack));
128
0
        }
129
130
0
        match = match->next;
131
0
      }
132
0
    }
133
134
250M
    index = block_data[i++] + 1;
135
250M
    transition = transition_table[state + index];
136
137
250M
    while (YR_AC_INVALID_TRANSITION(transition, index))
138
250M
    {
139
250M
      if (state != YR_AC_ROOT_STATE)
140
0
      {
141
0
        state = YR_AC_NEXT_STATE(transition_table[state]);
142
0
        transition = transition_table[state + index];
143
0
      }
144
250M
      else
145
250M
      {
146
250M
        transition = 0;
147
250M
        break;
148
250M
      }
149
250M
    }
150
151
250M
    state = YR_AC_NEXT_STATE(transition);
152
250M
  }
153
154
16.4k
  if (match_table[state] != 0)
155
0
  {
156
0
    match = &rules->ac_match_pool[match_table[state] - 1];
157
158
0
    while (match != NULL)
159
0
    {
160
0
      if (match->backtrack <= i)
161
0
      {
162
0
        GOTO_EXIT_ON_ERROR(yr_scan_verify_match(
163
0
            scanner,
164
0
            match,
165
0
            block_data,
166
0
            block->size,
167
0
            block->base,
168
0
            i - match->backtrack));
169
0
      }
170
171
0
      match = match->next;
172
0
    }
173
0
  }
174
175
16.4k
  if (rule != NULL && scanner->matches->count >= YR_SLOW_STRING_MATCHES &&
176
0
      scanner->matches->count < YR_MAX_STRING_MATCHES)
177
0
  {
178
0
    if (rule != NULL && report_string != NULL)
179
0
    {
180
0
      result = scanner->callback(
181
0
          scanner,
182
0
          CALLBACK_MSG_TOO_SLOW_SCANNING,
183
0
          (void*) report_string,
184
0
          scanner->user_data);
185
0
      if (result != CALLBACK_CONTINUE)
186
0
      {
187
0
        result = ERROR_TOO_SLOW_SCANNING;
188
0
        goto _exit;
189
0
      }
190
0
    }
191
0
  }
192
193
16.4k
_exit:
194
195
16.4k
  YR_DEBUG_FPRINTF(
196
16.4k
      2,
197
16.4k
      stderr,
198
16.4k
      "} = %d AKA %s // %s()\n",
199
16.4k
      result,
200
16.4k
      yr_debug_error_as_string(result),
201
16.4k
      __FUNCTION__);
202
203
16.4k
  return result;
204
16.4k
}
205
206
static void _yr_scanner_clean_matches(YR_SCANNER* scanner)
207
16.4k
{
208
16.4k
  YR_DEBUG_FPRINTF(2, stderr, "- %s() {} \n", __FUNCTION__);
209
210
16.4k
  memset(
211
16.4k
      scanner->rule_matches_flags,
212
16.4k
      0,
213
16.4k
      sizeof(YR_BITMASK) * YR_BITMASK_SIZE(scanner->rules->num_rules));
214
215
16.4k
  memset(
216
16.4k
      scanner->required_eval,
217
16.4k
      0,
218
16.4k
      sizeof(YR_BITMASK) * YR_BITMASK_SIZE(scanner->rules->num_rules));
219
220
16.4k
  memset(
221
16.4k
      scanner->ns_unsatisfied_flags,
222
16.4k
      0,
223
16.4k
      sizeof(YR_BITMASK) * YR_BITMASK_SIZE(scanner->rules->num_namespaces));
224
225
16.4k
  memset(
226
16.4k
      scanner->strings_temp_disabled,
227
16.4k
      0,
228
16.4k
      sizeof(YR_BITMASK) * YR_BITMASK_SIZE(scanner->rules->num_strings));
229
230
16.4k
  memset(scanner->matches, 0, sizeof(YR_MATCHES) * scanner->rules->num_strings);
231
232
16.4k
  memset(
233
16.4k
      scanner->unconfirmed_matches,
234
16.4k
      0,
235
16.4k
      sizeof(YR_MATCHES) * scanner->rules->num_strings);
236
16.4k
}
237
238
YR_API int yr_scanner_create(YR_RULES* rules, YR_SCANNER** scanner)
239
16.4k
{
240
16.4k
  YR_DEBUG_FPRINTF(2, stderr, "- %s() {} \n", __FUNCTION__);
241
242
16.4k
  YR_EXTERNAL_VARIABLE* external;
243
16.4k
  YR_SCANNER* new_scanner;
244
245
16.4k
  new_scanner = (YR_SCANNER*) yr_calloc(1, sizeof(YR_SCANNER));
246
247
16.4k
  if (new_scanner == NULL)
248
0
    return ERROR_INSUFFICIENT_MEMORY;
249
250
16.4k
  FAIL_ON_ERROR_WITH_CLEANUP(
251
16.4k
      yr_hash_table_create(64, &new_scanner->objects_table),
252
16.4k
      yr_free(new_scanner));
253
254
16.4k
  new_scanner->rules = rules;
255
16.4k
  new_scanner->entry_point = YR_UNDEFINED;
256
16.4k
  new_scanner->file_size = YR_UNDEFINED;
257
16.4k
  new_scanner->canary = rand();
258
259
  // By default report both matching and non-matching rules.
260
16.4k
  new_scanner->flags = SCAN_FLAGS_REPORT_RULES_MATCHING |
261
16.4k
                       SCAN_FLAGS_REPORT_RULES_NOT_MATCHING;
262
263
16.4k
  new_scanner->rule_matches_flags = (YR_BITMASK*) yr_calloc(
264
16.4k
      sizeof(YR_BITMASK), YR_BITMASK_SIZE(rules->num_rules));
265
266
16.4k
  new_scanner->required_eval = (YR_BITMASK*) yr_calloc(
267
16.4k
      sizeof(YR_BITMASK), YR_BITMASK_SIZE(rules->num_rules));
268
269
16.4k
  new_scanner->ns_unsatisfied_flags = (YR_BITMASK*) yr_calloc(
270
16.4k
      sizeof(YR_BITMASK), YR_BITMASK_SIZE(rules->num_namespaces));
271
272
16.4k
  new_scanner->strings_temp_disabled = (YR_BITMASK*) yr_calloc(
273
16.4k
      sizeof(YR_BITMASK), YR_BITMASK_SIZE(rules->num_strings));
274
275
16.4k
  new_scanner->matches = (YR_MATCHES*) yr_calloc(
276
16.4k
      rules->num_strings, sizeof(YR_MATCHES));
277
278
16.4k
  new_scanner->unconfirmed_matches = (YR_MATCHES*) yr_calloc(
279
16.4k
      rules->num_strings, sizeof(YR_MATCHES));
280
281
16.4k
  if (new_scanner->rule_matches_flags == NULL ||
282
16.4k
      new_scanner->required_eval == NULL ||
283
16.4k
      new_scanner->ns_unsatisfied_flags == NULL ||
284
16.4k
      new_scanner->strings_temp_disabled == NULL ||
285
16.4k
      (new_scanner->matches == NULL && rules->num_strings > 0) ||
286
16.4k
      (new_scanner->unconfirmed_matches == NULL && rules->num_strings > 0))
287
0
  {
288
0
    yr_scanner_destroy(new_scanner);
289
0
    return ERROR_INSUFFICIENT_MEMORY;
290
0
  }
291
292
#ifdef YR_PROFILING_ENABLED
293
  new_scanner->profiling_info = yr_calloc(
294
      rules->num_rules, sizeof(YR_PROFILING_INFO));
295
296
  if (new_scanner->profiling_info == NULL && rules->num_rules > 0)
297
  {
298
    yr_scanner_destroy(new_scanner);
299
    return ERROR_INSUFFICIENT_MEMORY;
300
  }
301
#else
302
16.4k
  new_scanner->profiling_info = NULL;
303
16.4k
#endif
304
305
16.4k
  external = rules->ext_vars_table;
306
307
16.4k
  while (!EXTERNAL_VARIABLE_IS_NULL(external))
308
0
  {
309
0
    YR_OBJECT* object;
310
311
0
    FAIL_ON_ERROR_WITH_CLEANUP(
312
0
        yr_object_from_external_variable(external, &object),
313
        // cleanup
314
0
        yr_scanner_destroy(new_scanner));
315
316
0
    FAIL_ON_ERROR_WITH_CLEANUP(yr_hash_table_add(
317
0
                                   new_scanner->objects_table,
318
0
                                   external->identifier,
319
0
                                   NULL,
320
0
                                   (void*) object),
321
                               // cleanup
322
0
                               yr_object_destroy(object);
323
0
                               yr_scanner_destroy(new_scanner));
324
325
0
    yr_object_set_canary(object, new_scanner->canary);
326
0
    external++;
327
0
  }
328
329
16.4k
  *scanner = new_scanner;
330
331
16.4k
  return ERROR_SUCCESS;
332
16.4k
}
333
334
YR_API void yr_scanner_destroy(YR_SCANNER* scanner)
335
16.4k
{
336
16.4k
  YR_DEBUG_FPRINTF(2, stderr, "- %s() {} \n", __FUNCTION__);
337
338
16.4k
  RE_FIBER* fiber = scanner->re_fiber_pool.fibers.head;
339
340
16.4k
  while (fiber != NULL)
341
0
  {
342
0
    RE_FIBER* next = fiber->next;
343
0
    yr_free(fiber);
344
0
    fiber = next;
345
0
  }
346
347
16.4k
  RE_FAST_EXEC_POSITION* position = scanner->re_fast_exec_position_pool.head;
348
349
16.4k
  while (position != NULL)
350
0
  {
351
0
    RE_FAST_EXEC_POSITION* next = position->next;
352
0
    yr_free(position);
353
0
    position = next;
354
0
  }
355
356
16.4k
  if (scanner->objects_table != NULL)
357
16.4k
  {
358
16.4k
    yr_hash_table_destroy(
359
16.4k
        scanner->objects_table,
360
16.4k
        (YR_HASH_TABLE_FREE_VALUE_FUNC) yr_object_destroy);
361
16.4k
  }
362
363
#ifdef YR_PROFILING_ENABLED
364
  yr_free(scanner->profiling_info);
365
#endif
366
367
16.4k
  yr_free(scanner->rule_matches_flags);
368
16.4k
  yr_free(scanner->ns_unsatisfied_flags);
369
16.4k
  yr_free(scanner->required_eval);
370
16.4k
  yr_free(scanner->strings_temp_disabled);
371
16.4k
  yr_free(scanner->matches);
372
16.4k
  yr_free(scanner->unconfirmed_matches);
373
16.4k
  yr_free(scanner);
374
16.4k
}
375
376
YR_API void yr_scanner_set_callback(
377
    YR_SCANNER* scanner,
378
    YR_CALLBACK_FUNC callback,
379
    void* user_data)
380
16.4k
{
381
16.4k
  scanner->callback = callback;
382
16.4k
  scanner->user_data = user_data;
383
16.4k
}
384
385
YR_API void yr_scanner_set_timeout(YR_SCANNER* scanner, int timeout)
386
16.4k
{
387
  // Convert timeout from seconds to nanoseconds.
388
16.4k
  scanner->timeout = timeout * 1000000000ULL;
389
16.4k
}
390
391
YR_API void yr_scanner_set_flags(YR_SCANNER* scanner, int flags)
392
16.4k
{
393
  // For backward compatibility, if neither SCAN_FLAGS_REPORT_RULES_MATCHING
394
  // nor SCAN_FLAGS_REPORT_RULES_NOT_MATCHING are specified, both are assumed.
395
396
16.4k
  if (!(flags & SCAN_FLAGS_REPORT_RULES_MATCHING) &&
397
16.4k
      !(flags & SCAN_FLAGS_REPORT_RULES_NOT_MATCHING))
398
16.4k
  {
399
16.4k
    flags |= SCAN_FLAGS_REPORT_RULES_MATCHING |
400
16.4k
             SCAN_FLAGS_REPORT_RULES_NOT_MATCHING;
401
16.4k
  }
402
403
16.4k
  scanner->flags = flags;
404
16.4k
}
405
406
YR_API int yr_scanner_define_integer_variable(
407
    YR_SCANNER* scanner,
408
    const char* identifier,
409
    int64_t value)
410
0
{
411
0
  YR_OBJECT* obj = (YR_OBJECT*) yr_hash_table_lookup(
412
0
      scanner->objects_table, identifier, NULL);
413
414
0
  if (obj == NULL)
415
0
    return ERROR_INVALID_ARGUMENT;
416
417
0
  if (obj->type != OBJECT_TYPE_INTEGER)
418
0
    return ERROR_INVALID_EXTERNAL_VARIABLE_TYPE;
419
420
0
  return yr_object_set_integer(value, obj, NULL);
421
0
}
422
423
YR_API int yr_scanner_define_boolean_variable(
424
    YR_SCANNER* scanner,
425
    const char* identifier,
426
    int value)
427
0
{
428
0
  return yr_scanner_define_integer_variable(scanner, identifier, value);
429
0
}
430
431
YR_API int yr_scanner_define_float_variable(
432
    YR_SCANNER* scanner,
433
    const char* identifier,
434
    double value)
435
0
{
436
0
  YR_OBJECT* obj = (YR_OBJECT*) yr_hash_table_lookup(
437
0
      scanner->objects_table, identifier, NULL);
438
439
0
  if (obj == NULL)
440
0
    return ERROR_INVALID_ARGUMENT;
441
442
0
  if (obj->type != OBJECT_TYPE_FLOAT)
443
0
    return ERROR_INVALID_EXTERNAL_VARIABLE_TYPE;
444
445
0
  return yr_object_set_float(value, obj, NULL);
446
0
}
447
448
YR_API int yr_scanner_define_string_variable(
449
    YR_SCANNER* scanner,
450
    const char* identifier,
451
    const char* value)
452
0
{
453
0
  YR_OBJECT* obj = (YR_OBJECT*) yr_hash_table_lookup(
454
0
      scanner->objects_table, identifier, NULL);
455
456
0
  if (obj == NULL)
457
0
    return ERROR_INVALID_ARGUMENT;
458
459
0
  if (obj->type != OBJECT_TYPE_STRING)
460
0
    return ERROR_INVALID_EXTERNAL_VARIABLE_TYPE;
461
462
0
  return yr_object_set_string(value, strlen(value), obj, NULL);
463
0
}
464
465
YR_API int yr_scanner_scan_mem_blocks(
466
    YR_SCANNER* scanner,
467
    YR_MEMORY_BLOCK_ITERATOR* iterator)
468
16.4k
{
469
16.4k
  YR_DEBUG_FPRINTF(2, stderr, "+ %s() {\n", __FUNCTION__);
470
471
16.4k
  YR_RULES* rules;
472
16.4k
  YR_RULE* rule;
473
16.4k
  YR_MEMORY_BLOCK* block;
474
475
16.4k
  int i, result = ERROR_SUCCESS;
476
477
16.4k
  if (scanner->callback == NULL)
478
0
  {
479
0
    result = ERROR_CALLBACK_REQUIRED;
480
0
    goto _exit;
481
0
  }
482
483
16.4k
  scanner->iterator = iterator;
484
16.4k
  rules = scanner->rules;
485
486
16.4k
  if (iterator->last_error == ERROR_BLOCK_NOT_READY)
487
0
  {
488
    // The caller is invoking yr_scanner_scan_mem_blocks again because the
489
    // previous call returned ERROR_BLOCK_NOT_READY.
490
0
    block = iterator->next(iterator);
491
0
  }
492
16.4k
  else
493
16.4k
  {
494
    // Create the notebook that will hold the YR_MATCH structures representing
495
    // each match found. This notebook will also contain snippets of the
496
    // matching data (the "data" field in YR_MATCH points to the snippet
497
    // corresponding to the match). Each notebook's page can store up to 1024
498
    // matches.
499
16.4k
    uint32_t max_match_data;
500
501
16.4k
    FAIL_ON_ERROR(
502
16.4k
        yr_get_configuration_uint32(YR_CONFIG_MAX_MATCH_DATA, &max_match_data));
503
504
16.4k
    result = yr_notebook_create(
505
16.4k
        1024 * (sizeof(YR_MATCH) + max_match_data), &scanner->matches_notebook);
506
507
16.4k
    if (result != ERROR_SUCCESS)
508
0
      goto _exit;
509
510
    // Every rule that doesn't require a matching string must be evaluated
511
    // regardless of whether a string matched or not.
512
16.4k
    memcpy(
513
16.4k
        scanner->required_eval,
514
16.4k
        scanner->rules->no_required_strings,
515
16.4k
        sizeof(YR_BITMASK) * YR_BITMASK_SIZE(rules->num_rules));
516
517
16.4k
    yr_stopwatch_start(&scanner->stopwatch);
518
519
16.4k
    block = iterator->first(iterator);
520
16.4k
  }
521
522
16.4k
  YR_TRYCATCH(
523
16.4k
      !(scanner->flags & SCAN_FLAGS_NO_TRYCATCH),
524
16.4k
      {
525
16.4k
        while (block != NULL)
526
16.4k
        {
527
16.4k
          const uint8_t* data = yr_fetch_block_data(block);
528
529
          // fetch_data may fail and return NULL.
530
16.4k
          if (data == NULL)
531
16.4k
          {
532
16.4k
            block = iterator->next(iterator);
533
16.4k
            continue;
534
16.4k
          }
535
536
16.4k
          if (scanner->entry_point == YR_UNDEFINED)
537
16.4k
          {
538
16.4k
            if (scanner->flags & SCAN_FLAGS_PROCESS_MEMORY)
539
16.4k
              scanner->entry_point = yr_get_entry_point_address(
540
16.4k
                  data, block->size, block->base);
541
16.4k
            else
542
16.4k
              scanner->entry_point = yr_get_entry_point_offset(
543
16.4k
                  data, block->size);
544
16.4k
          }
545
16.4k
          result = _yr_scanner_scan_mem_block(scanner, data, block);
546
16.4k
          if (result != ERROR_SUCCESS)
547
16.4k
          {
548
16.4k
            break;
549
16.4k
          }
550
16.4k
          block = iterator->next(iterator);
551
16.4k
        }
552
16.4k
      },
553
16.4k
      { result = ERROR_COULD_NOT_MAP_FILE; });
554
555
16.4k
  if (result != ERROR_SUCCESS)
556
0
    goto _exit;
557
558
16.4k
  result = iterator->last_error;
559
560
16.4k
  if (result != ERROR_SUCCESS)
561
0
    goto _exit;
562
563
  // If the iterator has a file_size function, ask the function for the file's
564
  // size, if not file size is undefined.
565
16.4k
  if (iterator->file_size != NULL)
566
16.4k
    scanner->file_size = iterator->file_size(iterator);
567
0
  else
568
0
    scanner->file_size = YR_UNDEFINED;
569
570
16.4k
  YR_TRYCATCH(
571
16.4k
      !(scanner->flags & SCAN_FLAGS_NO_TRYCATCH),
572
16.4k
      { result = yr_execute_code(scanner); },
573
16.4k
      { result = ERROR_COULD_NOT_MAP_FILE; });
574
575
16.4k
  if (result != ERROR_SUCCESS)
576
0
    goto _exit;
577
578
25.3k
  for (i = 0, rule = rules->rules_table; !RULE_IS_NULL(rule); i++, rule++)
579
8.92k
  {
580
8.92k
    int message = 0;
581
582
8.92k
    if (yr_bitmask_is_set(scanner->rule_matches_flags, i) &&
583
1.61k
        yr_bitmask_is_not_set(scanner->ns_unsatisfied_flags, rule->ns->idx))
584
1.61k
    {
585
1.61k
      if (scanner->flags & SCAN_FLAGS_REPORT_RULES_MATCHING)
586
1.61k
        message = CALLBACK_MSG_RULE_MATCHING;
587
1.61k
    }
588
7.31k
    else
589
7.31k
    {
590
7.31k
      if (scanner->flags & SCAN_FLAGS_REPORT_RULES_NOT_MATCHING)
591
7.31k
        message = CALLBACK_MSG_RULE_NOT_MATCHING;
592
7.31k
    }
593
594
8.92k
    if (message != 0 && !RULE_IS_PRIVATE(rule))
595
8.92k
    {
596
8.92k
      switch (scanner->callback(scanner, message, rule, scanner->user_data))
597
8.92k
      {
598
0
      case CALLBACK_ABORT:
599
0
        result = ERROR_SUCCESS;
600
0
        goto _exit;
601
602
0
      case CALLBACK_ERROR:
603
0
        result = ERROR_CALLBACK_ERROR;
604
0
        goto _exit;
605
8.92k
      }
606
8.92k
    }
607
8.92k
  }
608
609
16.4k
  scanner->callback(
610
16.4k
      scanner, CALLBACK_MSG_SCAN_FINISHED, NULL, scanner->user_data);
611
612
16.4k
_exit:
613
614
  // If error is ERROR_BLOCK_NOT_READY we don't clean the matches and don't
615
  // destroy the notebook yet. ERROR_BLOCK_NOT_READY is not a permament error,
616
  // the caller can still call this function again for a retry.
617
16.4k
  if (result != ERROR_BLOCK_NOT_READY)
618
16.4k
  {
619
16.4k
    _yr_scanner_clean_matches(scanner);
620
621
16.4k
    if (scanner->matches_notebook != NULL)
622
16.4k
    {
623
16.4k
      yr_notebook_destroy(scanner->matches_notebook);
624
16.4k
      scanner->matches_notebook = NULL;
625
16.4k
    }
626
16.4k
  }
627
628
16.4k
  YR_DEBUG_FPRINTF(
629
16.4k
      2,
630
16.4k
      stderr,
631
16.4k
      "} = %d AKA %s // %s()\n",
632
16.4k
      result,
633
16.4k
      yr_debug_error_as_string(result),
634
16.4k
      __FUNCTION__);
635
636
16.4k
  return result;
637
16.4k
}
638
639
static YR_MEMORY_BLOCK* _yr_get_first_block(YR_MEMORY_BLOCK_ITERATOR* iterator)
640
54.6k
{
641
54.6k
  YR_MEMORY_BLOCK* result = (YR_MEMORY_BLOCK*) iterator->context;
642
643
54.6k
  YR_DEBUG_FPRINTF(
644
54.6k
      2,
645
54.6k
      stderr,
646
54.6k
      "- %s() {} = %p // default iterator; single memory block, blocking\n",
647
54.6k
      __FUNCTION__,
648
54.6k
      result);
649
650
54.6k
  return result;
651
54.6k
}
652
653
static YR_MEMORY_BLOCK* _yr_get_next_block(YR_MEMORY_BLOCK_ITERATOR* iterator)
654
18.9k
{
655
18.9k
  YR_MEMORY_BLOCK* result = NULL;
656
657
18.9k
  YR_DEBUG_FPRINTF(
658
18.9k
      2,
659
18.9k
      stderr,
660
18.9k
      "- %s() {} = %p // default iterator; single memory block, blocking\n",
661
18.9k
      __FUNCTION__,
662
18.9k
      result);
663
664
18.9k
  return result;
665
18.9k
}
666
667
static uint64_t _yr_get_file_size(YR_MEMORY_BLOCK_ITERATOR* iterator)
668
16.4k
{
669
16.4k
  uint64_t file_size = ((YR_MEMORY_BLOCK*) iterator->context)->size;
670
671
16.4k
  YR_DEBUG_FPRINTF(
672
16.4k
      2,
673
16.4k
      stderr,
674
16.4k
      "- %s() {} = %" PRIu64
675
16.4k
      "  // default iterator; single memory block, blocking\n",
676
16.4k
      __FUNCTION__,
677
16.4k
      file_size);
678
679
16.4k
  return file_size;
680
16.4k
}
681
682
static const uint8_t* _yr_fetch_block_data(YR_MEMORY_BLOCK* block)
683
42.9k
{
684
42.9k
  return (const uint8_t*) block->context;
685
42.9k
}
686
687
YR_API const uint8_t* yr_fetch_block_data(YR_MEMORY_BLOCK* block)
688
42.9k
{
689
42.9k
  const uint8_t* data = block->fetch_data(block);
690
42.9k
  if (data == NULL)
691
0
  {
692
0
    return NULL;
693
0
  }
694
42.9k
  jumpinfo* info = (jumpinfo*) yr_thread_storage_get_value(
695
42.9k
      &yr_trycatch_trampoline_tls);
696
42.9k
  if (info == NULL)  // Not called from YR_TRYCATCH
697
42.9k
  {
698
42.9k
    return data;
699
42.9k
  }
700
0
  info->memfault_from = (void*) data;
701
0
  info->memfault_to = (void*) (data + block->size);
702
0
  return data;
703
42.9k
}
704
705
YR_API int yr_scanner_scan_mem(
706
    YR_SCANNER* scanner,
707
    const uint8_t* buffer,
708
    size_t buffer_size)
709
16.4k
{
710
16.4k
  YR_DEBUG_FPRINTF(
711
16.4k
      2,
712
16.4k
      stderr,
713
16.4k
      "+ %s(buffer=%p buffer_size=%zu) {\n",
714
16.4k
      __FUNCTION__,
715
16.4k
      buffer,
716
16.4k
      buffer_size);
717
718
16.4k
  YR_MEMORY_BLOCK block;
719
16.4k
  YR_MEMORY_BLOCK_ITERATOR iterator;
720
16.4k
  int result;
721
722
16.4k
  block.size = buffer_size;
723
16.4k
  block.base = 0;
724
16.4k
  block.fetch_data = _yr_fetch_block_data;
725
16.4k
  block.context = (void*) buffer;
726
727
16.4k
  iterator.context = &block;
728
16.4k
  iterator.first = _yr_get_first_block;
729
16.4k
  iterator.next = _yr_get_next_block;
730
16.4k
  iterator.file_size = _yr_get_file_size;
731
16.4k
  iterator.last_error = ERROR_SUCCESS;
732
733
  // Detect cases where every byte of input is checked for match and input size
734
  // is bigger then 0.2 MB
735
16.4k
  if (scanner->rules->ac_match_table[YR_AC_ROOT_STATE] != 0 &&
736
0
      buffer_size > YR_FILE_SIZE_THRESHOLD)
737
0
  {
738
0
    YR_STRING* report_string =
739
0
        scanner->rules->ac_match_pool[YR_AC_ROOT_STATE].string;
740
0
    result = scanner->callback(
741
0
        scanner,
742
0
        CALLBACK_MSG_TOO_SLOW_SCANNING,
743
0
        (void*) report_string,
744
0
        scanner->user_data);
745
0
    if (result != CALLBACK_CONTINUE)
746
0
      return ERROR_TOO_SLOW_SCANNING;
747
0
  }
748
749
16.4k
  result = yr_scanner_scan_mem_blocks(scanner, &iterator);
750
751
16.4k
  YR_DEBUG_FPRINTF(
752
16.4k
      2,
753
16.4k
      stderr,
754
16.4k
      "} = %d AKA %s // %s()\n",
755
16.4k
      result,
756
16.4k
      yr_debug_error_as_string(result),
757
16.4k
      __FUNCTION__);
758
759
16.4k
  return result;
760
16.4k
}
761
762
YR_API int yr_scanner_scan_file(YR_SCANNER* scanner, const char* filename)
763
0
{
764
0
  YR_MAPPED_FILE mfile;
765
766
0
  int result = yr_filemap_map(filename, &mfile);
767
768
0
  if (result == ERROR_SUCCESS)
769
0
  {
770
0
    result = yr_scanner_scan_mem(scanner, mfile.data, mfile.size);
771
0
    yr_filemap_unmap(&mfile);
772
0
  }
773
774
0
  return result;
775
0
}
776
777
YR_API int yr_scanner_scan_fd(YR_SCANNER* scanner, YR_FILE_DESCRIPTOR fd)
778
0
{
779
0
  YR_MAPPED_FILE mfile;
780
781
0
  int result = yr_filemap_map_fd(fd, 0, 0, &mfile);
782
783
0
  if (result == ERROR_SUCCESS)
784
0
  {
785
0
    result = yr_scanner_scan_mem(scanner, mfile.data, mfile.size);
786
0
    yr_filemap_unmap_fd(&mfile);
787
0
  }
788
789
0
  return result;
790
0
}
791
792
YR_API int yr_scanner_scan_proc(YR_SCANNER* scanner, int pid)
793
0
{
794
0
  YR_MEMORY_BLOCK_ITERATOR iterator;
795
796
0
  int result = yr_process_open_iterator(pid, &iterator);
797
798
0
  if (result == ERROR_SUCCESS)
799
0
  {
800
0
    int prev_flags = scanner->flags;
801
0
    scanner->flags |= SCAN_FLAGS_PROCESS_MEMORY;
802
0
    result = yr_scanner_scan_mem_blocks(scanner, &iterator);
803
0
    scanner->flags = prev_flags;
804
0
    yr_process_close_iterator(&iterator);
805
0
  }
806
807
0
  return result;
808
0
}
809
810
YR_API YR_STRING* yr_scanner_last_error_string(YR_SCANNER* scanner)
811
0
{
812
0
  return scanner->last_error_string;
813
0
}
814
815
YR_API YR_RULE* yr_scanner_last_error_rule(YR_SCANNER* scanner)
816
0
{
817
0
  if (scanner->last_error_string == NULL)
818
0
    return NULL;
819
820
0
  return &scanner->rules->rules_table[scanner->last_error_string->rule_idx];
821
0
}
822
823
static int sort_by_cost_desc(
824
    const struct YR_RULE_PROFILING_INFO* r1,
825
    const struct YR_RULE_PROFILING_INFO* r2)
826
0
{
827
0
  if (r1->cost < r2->cost)
828
0
    return 1;
829
830
0
  if (r1->cost > r2->cost)
831
0
    return -1;
832
833
0
  return 0;
834
0
}
835
836
//
837
// yr_scanner_get_profiling_info
838
//
839
// Returns a pointer to an array of YR_RULE_PROFILING_INFO structures with
840
// information about the cost of each rule. The rules are sorted by cost
841
// in descending order and the last item in the array has rule == NULL.
842
// The caller is responsible for freeing the returned array by calling
843
// yr_free. Calling this function only makes sense if YR_PROFILING_ENABLED
844
// is defined, if not, the cost for each rule won't be computed, it will be
845
// set to 0 for all rules.
846
//
847
YR_API YR_RULE_PROFILING_INFO* yr_scanner_get_profiling_info(
848
    YR_SCANNER* scanner)
849
0
{
850
0
  YR_RULE_PROFILING_INFO* profiling_info = yr_malloc(
851
0
      (scanner->rules->num_rules + 1) * sizeof(YR_RULE_PROFILING_INFO));
852
853
0
  if (profiling_info == NULL)
854
0
    return NULL;
855
856
0
  for (uint32_t i = 0; i < scanner->rules->num_rules; i++)
857
0
  {
858
0
    profiling_info[i].rule = &scanner->rules->rules_table[i];
859
#ifdef YR_PROFILING_ENABLED
860
    profiling_info[i].cost = scanner->profiling_info[i].exec_time +
861
                             (scanner->profiling_info[i].atom_matches *
862
                              scanner->profiling_info[i].match_time) /
863
                                 YR_MATCH_VERIFICATION_PROFILING_RATE;
864
#else
865
0
    memset(&profiling_info[i], 0, sizeof(YR_RULE_PROFILING_INFO));
866
0
#endif
867
0
  }
868
869
0
  qsort(
870
0
      profiling_info,
871
0
      scanner->rules->num_rules,
872
0
      sizeof(YR_RULE_PROFILING_INFO),
873
0
      (int (*)(const void*, const void*)) sort_by_cost_desc);
874
875
0
  profiling_info[scanner->rules->num_rules].rule = NULL;
876
0
  profiling_info[scanner->rules->num_rules].cost = 0;
877
878
0
  return profiling_info;
879
0
}
880
881
YR_API void yr_scanner_reset_profiling_info(YR_SCANNER* scanner)
882
0
{
883
#ifdef YR_PROFILING_ENABLED
884
  memset(
885
      scanner->profiling_info,
886
      0,
887
      scanner->rules->num_rules * sizeof(YR_PROFILING_INFO));
888
#endif
889
0
}
890
891
YR_API int yr_scanner_print_profiling_info(YR_SCANNER* scanner)
892
0
{
893
0
  printf("\n===== PROFILING INFORMATION =====\n\n");
894
895
0
  YR_RULE_PROFILING_INFO* info = yr_scanner_get_profiling_info(scanner);
896
897
0
  if (info == NULL)
898
0
    return ERROR_INSUFFICIENT_MEMORY;
899
900
0
  YR_RULE_PROFILING_INFO* rpi = info;
901
902
0
  while (rpi->rule != NULL)
903
0
  {
904
0
    printf(
905
0
        "%10" PRIu64 " %s:%s: \n",
906
0
        rpi->cost,
907
0
        rpi->rule->ns->name,
908
0
        rpi->rule->identifier);
909
910
0
    rpi++;
911
0
  }
912
913
0
  printf("\n=================================\n");
914
915
0
  yr_free(info);
916
917
0
  return ERROR_SUCCESS;
918
0
}