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