Coverage Report

Created: 2025-11-11 06:56

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
4.21k
{
50
4.21k
  YR_DEBUG_FPRINTF(
51
4.21k
      2,
52
4.21k
      stderr,
53
4.21k
      "+ %s(block_data=%p block->base=0x%" PRIx64 " block->size=%zu) {\n",
54
4.21k
      __FUNCTION__,
55
4.21k
      block_data,
56
4.21k
      block->base,
57
4.21k
      block->size);
58
59
4.21k
  int result = ERROR_SUCCESS;
60
61
4.21k
  YR_RULES* rules = scanner->rules;
62
4.21k
  YR_AC_TRANSITION* transition_table = rules->ac_transition_table;
63
4.21k
  uint32_t* match_table = rules->ac_match_table;
64
65
4.21k
  YR_AC_MATCH* match;
66
4.21k
  YR_AC_TRANSITION transition;
67
68
4.21k
  size_t i = 0;
69
4.21k
  uint32_t state = YR_AC_ROOT_STATE;
70
4.21k
  uint16_t index;
71
4.21k
  YR_STRING* report_string = NULL;
72
4.21k
  YR_RULE* rule = NULL;
73
74
58.8M
  while (i < block->size)
75
58.8M
  {
76
58.8M
    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
58.8M
    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
58.8M
    index = block_data[i++] + 1;
135
58.8M
    transition = transition_table[state + index];
136
137
58.8M
    while (YR_AC_INVALID_TRANSITION(transition, index))
138
58.8M
    {
139
58.8M
      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
58.8M
      else
145
58.8M
      {
146
58.8M
        transition = 0;
147
58.8M
        break;
148
58.8M
      }
149
58.8M
    }
150
151
58.8M
    state = YR_AC_NEXT_STATE(transition);
152
58.8M
  }
153
154
4.21k
  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
4.21k
  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
4.21k
_exit:
194
195
4.21k
  YR_DEBUG_FPRINTF(
196
4.21k
      2,
197
4.21k
      stderr,
198
4.21k
      "} = %d AKA %s // %s()\n",
199
4.21k
      result,
200
4.21k
      yr_debug_error_as_string(result),
201
4.21k
      __FUNCTION__);
202
203
4.21k
  return result;
204
4.21k
}
205
206
static void _yr_scanner_clean_matches(YR_SCANNER* scanner)
207
4.21k
{
208
4.21k
  YR_DEBUG_FPRINTF(2, stderr, "- %s() {} \n", __FUNCTION__);
209
210
4.21k
  memset(
211
4.21k
      scanner->rule_matches_flags,
212
4.21k
      0,
213
4.21k
      sizeof(YR_BITMASK) * YR_BITMASK_SIZE(scanner->rules->num_rules));
214
215
4.21k
  memset(
216
4.21k
      scanner->required_eval,
217
4.21k
      0,
218
4.21k
      sizeof(YR_BITMASK) * YR_BITMASK_SIZE(scanner->rules->num_rules));
219
220
4.21k
  memset(
221
4.21k
      scanner->ns_unsatisfied_flags,
222
4.21k
      0,
223
4.21k
      sizeof(YR_BITMASK) * YR_BITMASK_SIZE(scanner->rules->num_namespaces));
224
225
4.21k
  memset(
226
4.21k
      scanner->strings_temp_disabled,
227
4.21k
      0,
228
4.21k
      sizeof(YR_BITMASK) * YR_BITMASK_SIZE(scanner->rules->num_strings));
229
230
4.21k
  memset(scanner->matches, 0, sizeof(YR_MATCHES) * scanner->rules->num_strings);
231
232
4.21k
  memset(
233
4.21k
      scanner->unconfirmed_matches,
234
4.21k
      0,
235
4.21k
      sizeof(YR_MATCHES) * scanner->rules->num_strings);
236
4.21k
}
237
238
YR_API int yr_scanner_create(YR_RULES* rules, YR_SCANNER** scanner)
239
4.21k
{
240
4.21k
  YR_DEBUG_FPRINTF(2, stderr, "- %s() {} \n", __FUNCTION__);
241
242
4.21k
  YR_EXTERNAL_VARIABLE* external;
243
4.21k
  YR_SCANNER* new_scanner;
244
245
4.21k
  new_scanner = (YR_SCANNER*) yr_calloc(1, sizeof(YR_SCANNER));
246
247
4.21k
  if (new_scanner == NULL)
248
0
    return ERROR_INSUFFICIENT_MEMORY;
249
250
4.21k
  FAIL_ON_ERROR_WITH_CLEANUP(
251
4.21k
      yr_hash_table_create(64, &new_scanner->objects_table),
252
4.21k
      yr_free(new_scanner));
253
254
4.21k
  new_scanner->rules = rules;
255
4.21k
  new_scanner->entry_point = YR_UNDEFINED;
256
4.21k
  new_scanner->file_size = YR_UNDEFINED;
257
4.21k
  new_scanner->canary = rand();
258
259
  // By default report both matching and non-matching rules.
260
4.21k
  new_scanner->flags = SCAN_FLAGS_REPORT_RULES_MATCHING |
261
4.21k
                       SCAN_FLAGS_REPORT_RULES_NOT_MATCHING;
262
263
4.21k
  new_scanner->rule_matches_flags = (YR_BITMASK*) yr_calloc(
264
4.21k
      sizeof(YR_BITMASK), YR_BITMASK_SIZE(rules->num_rules));
265
266
4.21k
  new_scanner->required_eval = (YR_BITMASK*) yr_calloc(
267
4.21k
      sizeof(YR_BITMASK), YR_BITMASK_SIZE(rules->num_rules));
268
269
4.21k
  new_scanner->ns_unsatisfied_flags = (YR_BITMASK*) yr_calloc(
270
4.21k
      sizeof(YR_BITMASK), YR_BITMASK_SIZE(rules->num_namespaces));
271
272
4.21k
  new_scanner->strings_temp_disabled = (YR_BITMASK*) yr_calloc(
273
4.21k
      sizeof(YR_BITMASK), YR_BITMASK_SIZE(rules->num_strings));
274
275
4.21k
  new_scanner->matches = (YR_MATCHES*) yr_calloc(
276
4.21k
      rules->num_strings, sizeof(YR_MATCHES));
277
278
4.21k
  new_scanner->unconfirmed_matches = (YR_MATCHES*) yr_calloc(
279
4.21k
      rules->num_strings, sizeof(YR_MATCHES));
280
281
4.21k
  if (new_scanner->rule_matches_flags == NULL ||
282
4.21k
      new_scanner->required_eval == NULL ||
283
4.21k
      new_scanner->ns_unsatisfied_flags == NULL ||
284
4.21k
      new_scanner->strings_temp_disabled == NULL ||
285
4.21k
      (new_scanner->matches == NULL && rules->num_strings > 0) ||
286
4.21k
      (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
4.21k
  new_scanner->profiling_info = NULL;
303
4.21k
#endif
304
305
4.21k
  external = rules->ext_vars_table;
306
307
4.21k
  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
4.21k
  *scanner = new_scanner;
330
331
4.21k
  return ERROR_SUCCESS;
332
4.21k
}
333
334
YR_API void yr_scanner_destroy(YR_SCANNER* scanner)
335
4.21k
{
336
4.21k
  YR_DEBUG_FPRINTF(2, stderr, "- %s() {} \n", __FUNCTION__);
337
338
4.21k
  RE_FIBER* fiber = scanner->re_fiber_pool.fibers.head;
339
340
4.21k
  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
4.21k
  RE_FAST_EXEC_POSITION* position = scanner->re_fast_exec_position_pool.head;
348
349
4.21k
  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
4.21k
  if (scanner->objects_table != NULL)
357
4.21k
  {
358
4.21k
    yr_hash_table_destroy(
359
4.21k
        scanner->objects_table,
360
4.21k
        (YR_HASH_TABLE_FREE_VALUE_FUNC) yr_object_destroy);
361
4.21k
  }
362
363
#ifdef YR_PROFILING_ENABLED
364
  yr_free(scanner->profiling_info);
365
#endif
366
367
4.21k
  yr_free(scanner->rule_matches_flags);
368
4.21k
  yr_free(scanner->ns_unsatisfied_flags);
369
4.21k
  yr_free(scanner->required_eval);
370
4.21k
  yr_free(scanner->strings_temp_disabled);
371
4.21k
  yr_free(scanner->matches);
372
4.21k
  yr_free(scanner->unconfirmed_matches);
373
4.21k
  yr_free(scanner);
374
4.21k
}
375
376
YR_API void yr_scanner_set_callback(
377
    YR_SCANNER* scanner,
378
    YR_CALLBACK_FUNC callback,
379
    void* user_data)
380
4.21k
{
381
4.21k
  scanner->callback = callback;
382
4.21k
  scanner->user_data = user_data;
383
4.21k
}
384
385
YR_API void yr_scanner_set_timeout(YR_SCANNER* scanner, int timeout)
386
4.21k
{
387
  // Convert timeout from seconds to nanoseconds.
388
4.21k
  scanner->timeout = timeout * 1000000000ULL;
389
4.21k
}
390
391
YR_API void yr_scanner_set_flags(YR_SCANNER* scanner, int flags)
392
4.21k
{
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
4.21k
  if (!(flags & SCAN_FLAGS_REPORT_RULES_MATCHING) &&
397
4.21k
      !(flags & SCAN_FLAGS_REPORT_RULES_NOT_MATCHING))
398
4.21k
  {
399
4.21k
    flags |= SCAN_FLAGS_REPORT_RULES_MATCHING |
400
4.21k
             SCAN_FLAGS_REPORT_RULES_NOT_MATCHING;
401
4.21k
  }
402
403
4.21k
  scanner->flags = flags;
404
4.21k
}
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
4.21k
{
469
4.21k
  YR_DEBUG_FPRINTF(2, stderr, "+ %s() {\n", __FUNCTION__);
470
471
4.21k
  YR_RULES* rules;
472
4.21k
  YR_RULE* rule;
473
4.21k
  YR_MEMORY_BLOCK* block;
474
475
4.21k
  int i, result = ERROR_SUCCESS;
476
477
4.21k
  if (scanner->callback == NULL)
478
0
  {
479
0
    result = ERROR_CALLBACK_REQUIRED;
480
0
    goto _exit;
481
0
  }
482
483
4.21k
  scanner->iterator = iterator;
484
4.21k
  rules = scanner->rules;
485
486
4.21k
  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
4.21k
  else
493
4.21k
  {
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
4.21k
    uint32_t max_match_data;
500
501
4.21k
    FAIL_ON_ERROR(
502
4.21k
        yr_get_configuration_uint32(YR_CONFIG_MAX_MATCH_DATA, &max_match_data));
503
504
4.21k
    result = yr_notebook_create(
505
4.21k
        1024 * (sizeof(YR_MATCH) + max_match_data), &scanner->matches_notebook);
506
507
4.21k
    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
4.21k
    memcpy(
513
4.21k
        scanner->required_eval,
514
4.21k
        scanner->rules->no_required_strings,
515
4.21k
        sizeof(YR_BITMASK) * YR_BITMASK_SIZE(rules->num_rules));
516
517
4.21k
    yr_stopwatch_start(&scanner->stopwatch);
518
519
4.21k
    block = iterator->first(iterator);
520
4.21k
  }
521
522
4.21k
  YR_TRYCATCH(
523
4.21k
      !(scanner->flags & SCAN_FLAGS_NO_TRYCATCH),
524
4.21k
      {
525
4.21k
        while (block != NULL)
526
4.21k
        {
527
4.21k
          const uint8_t* data = yr_fetch_block_data(block);
528
529
          // fetch_data may fail and return NULL.
530
4.21k
          if (data == NULL)
531
4.21k
          {
532
4.21k
            block = iterator->next(iterator);
533
4.21k
            continue;
534
4.21k
          }
535
536
4.21k
          if (scanner->entry_point == YR_UNDEFINED)
537
4.21k
          {
538
4.21k
            if (scanner->flags & SCAN_FLAGS_PROCESS_MEMORY)
539
4.21k
              scanner->entry_point = yr_get_entry_point_address(
540
4.21k
                  data, block->size, block->base);
541
4.21k
            else
542
4.21k
              scanner->entry_point = yr_get_entry_point_offset(
543
4.21k
                  data, block->size);
544
4.21k
          }
545
4.21k
          result = _yr_scanner_scan_mem_block(scanner, data, block);
546
4.21k
          if (result != ERROR_SUCCESS)
547
4.21k
          {
548
4.21k
            break;
549
4.21k
          }
550
4.21k
          block = iterator->next(iterator);
551
4.21k
        }
552
4.21k
      },
553
4.21k
      { result = ERROR_COULD_NOT_MAP_FILE; });
554
555
4.21k
  if (result != ERROR_SUCCESS)
556
0
    goto _exit;
557
558
4.21k
  result = iterator->last_error;
559
560
4.21k
  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
4.21k
  if (iterator->file_size != NULL)
566
4.21k
    scanner->file_size = iterator->file_size(iterator);
567
0
  else
568
0
    scanner->file_size = YR_UNDEFINED;
569
570
4.21k
  YR_TRYCATCH(
571
4.21k
      !(scanner->flags & SCAN_FLAGS_NO_TRYCATCH),
572
4.21k
      { result = yr_execute_code(scanner); },
573
4.21k
      { result = ERROR_COULD_NOT_MAP_FILE; });
574
575
4.21k
  if (result != ERROR_SUCCESS)
576
0
    goto _exit;
577
578
8.43k
  for (i = 0, rule = rules->rules_table; !RULE_IS_NULL(rule); i++, rule++)
579
4.21k
  {
580
4.21k
    int message = 0;
581
582
4.21k
    if (yr_bitmask_is_set(scanner->rule_matches_flags, i) &&
583
1
        yr_bitmask_is_not_set(scanner->ns_unsatisfied_flags, rule->ns->idx))
584
1
    {
585
1
      if (scanner->flags & SCAN_FLAGS_REPORT_RULES_MATCHING)
586
1
        message = CALLBACK_MSG_RULE_MATCHING;
587
1
    }
588
4.21k
    else
589
4.21k
    {
590
4.21k
      if (scanner->flags & SCAN_FLAGS_REPORT_RULES_NOT_MATCHING)
591
4.21k
        message = CALLBACK_MSG_RULE_NOT_MATCHING;
592
4.21k
    }
593
594
4.21k
    if (message != 0 && !RULE_IS_PRIVATE(rule))
595
4.21k
    {
596
4.21k
      switch (scanner->callback(scanner, message, rule, scanner->user_data))
597
4.21k
      {
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
4.21k
      }
606
4.21k
    }
607
4.21k
  }
608
609
4.21k
  scanner->callback(
610
4.21k
      scanner, CALLBACK_MSG_SCAN_FINISHED, NULL, scanner->user_data);
611
612
4.21k
_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
4.21k
  if (result != ERROR_BLOCK_NOT_READY)
618
4.21k
  {
619
4.21k
    _yr_scanner_clean_matches(scanner);
620
621
4.21k
    if (scanner->matches_notebook != NULL)
622
4.21k
    {
623
4.21k
      yr_notebook_destroy(scanner->matches_notebook);
624
4.21k
      scanner->matches_notebook = NULL;
625
4.21k
    }
626
4.21k
  }
627
628
4.21k
  YR_DEBUG_FPRINTF(
629
4.21k
      2,
630
4.21k
      stderr,
631
4.21k
      "} = %d AKA %s // %s()\n",
632
4.21k
      result,
633
4.21k
      yr_debug_error_as_string(result),
634
4.21k
      __FUNCTION__);
635
636
4.21k
  return result;
637
4.21k
}
638
639
static YR_MEMORY_BLOCK* _yr_get_first_block(YR_MEMORY_BLOCK_ITERATOR* iterator)
640
8.43k
{
641
8.43k
  YR_MEMORY_BLOCK* result = (YR_MEMORY_BLOCK*) iterator->context;
642
643
8.43k
  YR_DEBUG_FPRINTF(
644
8.43k
      2,
645
8.43k
      stderr,
646
8.43k
      "- %s() {} = %p // default iterator; single memory block, blocking\n",
647
8.43k
      __FUNCTION__,
648
8.43k
      result);
649
650
8.43k
  return result;
651
8.43k
}
652
653
static YR_MEMORY_BLOCK* _yr_get_next_block(YR_MEMORY_BLOCK_ITERATOR* iterator)
654
6.03k
{
655
6.03k
  YR_MEMORY_BLOCK* result = NULL;
656
657
6.03k
  YR_DEBUG_FPRINTF(
658
6.03k
      2,
659
6.03k
      stderr,
660
6.03k
      "- %s() {} = %p // default iterator; single memory block, blocking\n",
661
6.03k
      __FUNCTION__,
662
6.03k
      result);
663
664
6.03k
  return result;
665
6.03k
}
666
667
static uint64_t _yr_get_file_size(YR_MEMORY_BLOCK_ITERATOR* iterator)
668
4.21k
{
669
4.21k
  uint64_t file_size = ((YR_MEMORY_BLOCK*) iterator->context)->size;
670
671
4.21k
  YR_DEBUG_FPRINTF(
672
4.21k
      2,
673
4.21k
      stderr,
674
4.21k
      "- %s() {} = %" PRIu64
675
4.21k
      "  // default iterator; single memory block, blocking\n",
676
4.21k
      __FUNCTION__,
677
4.21k
      file_size);
678
679
4.21k
  return file_size;
680
4.21k
}
681
682
static const uint8_t* _yr_fetch_block_data(YR_MEMORY_BLOCK* block)
683
8.43k
{
684
8.43k
  return (const uint8_t*) block->context;
685
8.43k
}
686
687
YR_API const uint8_t* yr_fetch_block_data(YR_MEMORY_BLOCK* block)
688
8.43k
{
689
8.43k
  const uint8_t* data = block->fetch_data(block);
690
8.43k
  if (data == NULL)
691
0
  {
692
0
    return NULL;
693
0
  }
694
8.43k
  jumpinfo* info = (jumpinfo*) yr_thread_storage_get_value(
695
8.43k
      &yr_trycatch_trampoline_tls);
696
8.43k
  if (info == NULL)  // Not called from YR_TRYCATCH
697
8.43k
  {
698
8.43k
    return data;
699
8.43k
  }
700
0
  info->memfault_from = (void*) data;
701
0
  info->memfault_to = (void*) (data + block->size);
702
0
  return data;
703
8.43k
}
704
705
YR_API int yr_scanner_scan_mem(
706
    YR_SCANNER* scanner,
707
    const uint8_t* buffer,
708
    size_t buffer_size)
709
4.21k
{
710
4.21k
  YR_DEBUG_FPRINTF(
711
4.21k
      2,
712
4.21k
      stderr,
713
4.21k
      "+ %s(buffer=%p buffer_size=%zu) {\n",
714
4.21k
      __FUNCTION__,
715
4.21k
      buffer,
716
4.21k
      buffer_size);
717
718
4.21k
  YR_MEMORY_BLOCK block;
719
4.21k
  YR_MEMORY_BLOCK_ITERATOR iterator;
720
4.21k
  int result;
721
722
4.21k
  block.size = buffer_size;
723
4.21k
  block.base = 0;
724
4.21k
  block.fetch_data = _yr_fetch_block_data;
725
4.21k
  block.context = (void*) buffer;
726
727
4.21k
  iterator.context = &block;
728
4.21k
  iterator.first = _yr_get_first_block;
729
4.21k
  iterator.next = _yr_get_next_block;
730
4.21k
  iterator.file_size = _yr_get_file_size;
731
4.21k
  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
4.21k
  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
4.21k
  result = yr_scanner_scan_mem_blocks(scanner, &iterator);
750
751
4.21k
  YR_DEBUG_FPRINTF(
752
4.21k
      2,
753
4.21k
      stderr,
754
4.21k
      "} = %d AKA %s // %s()\n",
755
4.21k
      result,
756
4.21k
      yr_debug_error_as_string(result),
757
4.21k
      __FUNCTION__);
758
759
4.21k
  return result;
760
4.21k
}
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
}