Coverage Report

Created: 2026-10-17 06:42

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