454 Commits
Author SHA1 Message Date
Mr.XandVictor M. Alvarez 5e8a8ea41f Add yr_get_version to report the version of the library loaded at runtime (#2247)
YR_MAJOR_VERSION, YR_MINOR_VERSION and YR_MICRO_VERSION are fixed when the
caller is compiled, so a program linked against a shared libyara has no way
to tell which version it actually loaded. Distros ship libyara.so in its own
package precisely so it can be updated independently of its consumers, which
is exactly the case the macros cannot describe.

Add yr_get_version(), which reports the version of the library that is
actually loaded. Any argument may be NULL if the caller does not need that
component, and since the function touches no global state it can be called
before yr_initialize.

Closes #2136

---------

Co-authored-by: Victor M. Alvarez <[email protected]>
2026-09-23 11:48:49 +02:00
Mr.X 25a50bd63c elf: expose nine more e_machine values (#2248)
elf.machine can hold any value from the ELF header, but the module only
named 14 of them, so a rule targeting anything else had to hardcode the
number or drop the module and match the header bytes by hand.

Add the architectures from the issue: PARISC, SPARC32PLUS, S390, MCORE,
SH, SPARCV9, ARC_COMPACT, BPF and LOONGARCH.

0x27 is exposed under both EM_MCORE and EM_RCE. EM_RCE is the name it was
originally registered under and still what some toolchains emit, so a rule
written against either name works.

Closes #2149
2026-09-23 10:04:28 +02:00
Victor M. Alvarez 0cdff36723 fix: validate arena buffer count
Ensure `YR_ARENA` objects are created, loaded, and accessed with a valid number of buffers. This prevents out-of-bounds memory access and improves robustness against corrupted arena data or incorrect API usage.

Closes #2238.
2026-08-25 10:29:10 +02:00
Cole Munz dcc4b9166c reject hex jump and repeat lengths that overflow an int (#2237)
The hex string and regexp lexers parse jump lengths and repeat intervals
with atoi, which is undefined for numbers that don't fit in an int. glibc
hands back the low 32 bits, so a value that wraps to a small positive
number passes every bounds check and silently changes the pattern:

  rule r1 { strings: $a = /a{4294967296}/ condition: $a }
  rule r2 { strings: $b = { 61 [0-4294967297] 62 } condition: $b }

Before this change r1 compiled as a{0} and matched at every offset, and
r2 compiled as { 61 [0-1] 62 }. MSVC saturates atoi at INT_MAX instead,
so the same rule behaves differently there, which is what #1791 reports.

Parse with strtoll instead. Numbers too large for a long long are clamped
to LLONG_MAX, which still fails the range check, so "repeat interval too
large" now fires for everything above RE_MAX_RANGE on any platform. Hex
jumps get an explicit INT_MAX check because RE_NODE stores start and end
as ints, and the grammar already casts to int.

The hi_bound < 0 and lo_bound < 0 checks are gone. They were there to
catch atoi wrapping negative and are unreachable now that the only thing
the pattern matches is digits.

Fixes #1791.
2026-08-21 10:34:22 +02:00
jmestwa-coder a69cc6a3bd bound aho-corasick state and match indices on load (#2241)
validate the aho-corasick transition and match tables when loading, otherwise a crafted .yrc whose next-state or match-pool index points past the end of the tables makes the per-byte scan loop in _yr_scanner_scan_mem_block read out of bounds.
2026-08-19 11:31:25 +02:00
jmestwa-coder 46bf55b337 guard repeat-end against empty stack in _yr_re_fiber_sync (#2240)
The RE_OPCODE_REPEAT_END handler in _yr_re_fiber_sync does `fiber->stack[fiber->sp]++` without checking that sp is not negative:
- sp starts at -1 and only a preceding REPEAT_START advances it to 0
- a hand-crafted .yrc can reach REPEAT_END with no matching REPEAT_START, so `stack[-1]++` writes into the fiber's `next` pointer and the later fiber traversal follows the corrupted value
- the REPEAT_START push already carries the paranoid upper-bound guard, only this lower bound was missing

Added the sp < 0 guard under YR_PARANOID_EXEC. A regexp of a single REPEAT_END opcode gives an ASAN SEGV in _yr_re_fiber_split before the patch and a clean ERROR_INTERNAL_FATAL_ERROR after; regression test added in test-re-split.c.
2026-08-19 11:29:48 +02:00
jmestwa-coder 0a5e2f1390 bound jump target within code section in yr_execute_code (#2236)
conditional-jump opcodes add an unchecked 4-byte offset from the compiled bytecode to the instruction pointer, so a crafted .yrc whose taken jump lands past the code section makes yr_execute_code fetch the next opcode out of bounds; reject any ip that leaves the code buffer.
2026-08-19 11:28:58 +02:00
jmestwa-coder 604822da04 reject unknown object type in yr_object_create (#2235)
**Zero-sized allocation for an unknown object type in yr_object_create**

The external variable types stored in a compiled rules file are never validated, so a crafted .yrc reaches yr_object_create with a type that matches no case and leaves object_size at 0, and the field writes right after the allocation land past the end of it. Both switches guarded this with assert only, which is compiled out under NDEBUG the way the projects in windows/ set it.
2026-07-30 08:37:31 +02:00
jmestwa-coder 605452e580 check stored digest length before comparing authenticode digests (#2234)
the digest carried in a signature can be shorter than the digest algorithm's output size, so the memcmp in parse_authenticode and pkcs9_countersig_new reads past the stored digest; compare the lengths first, the way countersignature.c already does at its other three digest compares.
2026-07-28 12:59:52 +02:00
jmestwa-coder 129cdc43fb bound rule table index in OP_PUSH_RULE and OP_INIT_RULE (#2230)
Rule index read from compiled bytecode is used to index rules_table without a bounds check:
- OP_PUSH_RULE dereferences rules_table[r1.i] and indexes rule_matches_flags with the same value, unchecked
- OP_INIT_RULE only had an assert, which is a no-op under NDEBUG
- OP_MATCH_RULE right below them already guards the index with ensure_within_rules_arena

Added the same YR_PARANOID_EXEC guard to both. A crafted .yrc with an out-of-range rule index reaches this through yr_rules_scan_mem and reads past the table; test-exec covers it.
2026-07-22 08:57:13 +02:00
jmestwa-coder f66f730881 bound repeat stack depth in _yr_re_fiber_sync (#2229)
Unbounded push onto the per-fiber repeat stack in _yr_re_fiber_sync:
- REPEAT_START does stack[++sp] = 0 with sp never checked against RE_MAX_STACK
- a crafted rule with a run of more than RE_MAX_STACK REPEAT_START opcodes writes past the 1024-entry stack at the tail of the heap RE_FIBER
- confirmed under ASAN: heap-buffer-overflow write at re.c:1560 reached through yr_re_exec

Guarded under YR_PARANOID_EXEC like the split id check above, with a regression test.
2026-07-22 08:54:38 +02:00
jmestwa-coder 1ad2a079e2 validate summary counts in yr_rules_from_arena (#2222)
Loading a compiled rules file trusts the counts in its summary:
- num_rules drives the rules_table walk in yr_rules_from_arena, so an inflated count reads past YR_RULES_TABLE (ASAN heap-buffer-overflow at rules.c:381, reached through yr_rules_load)
- num_strings and num_namespaces feed scanner-side allocations and index math with the same gap

Reject any count larger than its table's loaded size with ERROR_CORRUPT_FILE. The added test saves a small ruleset, inflates num_rules in the summary, and checks the load is rejected.
2026-07-14 12:24:40 +02:00
jmestwa-coder be24a74f22 bound iterator item count in yr_execute_code (#2216)
The set iterators in yr_execute_code read the enumeration item count from the compiled rules and use it unchecked:
- int_enum sizes the iterator allocation with it and then pops that many values off the stack
- string_set and text_string_set repeat the same pattern
- a .yrc loaded through yr_rules_load can carry a count past the stack depth, so the allocation is undersized and the loop runs off the value stack

Bounded each count against the current stack depth. test-iterators saves `for any i in (1,2,3)`, bumps the stored count from 3 to 255 and scans: ASAN reports an out-of-bounds read in yr_execute_code before the change, clean after.
2026-06-30 20:20:42 +02:00
jmestwa-coder 622ea976c7 byte-swap sh_entry_count in elf symtab/dynsym link check (#2214)
Missing byte swap in the ELF symtab/dynsym link check
The SHT_SYMTAB and SHT_DYNSYM string table check compares sh_link against the raw e_shnum (sh_entry_count) while every other use in the macro byte-swaps it, so on a little-endian host reading a big-endian ELF the check accepts a link past the real section count and parses the symbol string table from an out-of-range section header. Swapped it to match the sibling reads, and added a regression test scanning a crafted big-endian ELF whose only symtab carries an out-of-range sh_link.
2026-06-30 20:20:12 +02:00
jmestwa-coder 6339e36f5f validate relocation target ref in yr_arena_load_stream (#2213)
bound the relocation target ref's buffer_id and offset in yr_arena_load_stream before yr_arena_ref_to_ptr converts it, otherwise a crafted compiled rules file supplies a target buffer_id past the 16-slot buffers array that yr_arena_get_ptr only guards with assert, which is compiled out under NDEBUG and reads out of bounds.
2026-06-30 20:19:53 +02:00
Eritque arcus 510eca24fd fix: Fix INT64_MIN UB in constant folding (*, \, unary -) (#2211)
Constant folding in `grammar.y` hits UB at the `INT64_MIN` boundary, reachable from rule text:

- `*`: `llabs(INT64_MIN)` is UB and returns a negative value, so the overflow guard is bypassed and folds to a garbage constant instead of `ERROR_INTEGER_OVERFLOW`. Now compares magnitudes in unsigned space.
- `\`: `INT64_MIN / -1` is overflow UB and raises SIGFPE on x86. Now rejected with `ERROR_INTEGER_OVERFLOW`.
- unary `-`: `-INT64_MIN` is negation UB. Now negated in unsigned space (wraps to `INT64_MIN`, unchanged behavior).

Reproduce  `condition` expr (each reported an UBSan error):
    `~9223372036854775807 * 9223372036854775807`
    `~9223372036854775807 \ -1`
    `-(~9223372036854775807)`

Example Logs:
```
libyara/grammar.y:2813:30: runtime error: negation of -9223372036854775808 cannot be represented in type 'int64_t' (aka 'long'); cast to an unsigned type to negate this value to itself
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior libyara/grammar.y:2813:30 
```

Note: The VM ops in `exec.c` and the `%` rule likely share this UB.

Disclose: assisted with AI
2026-06-30 20:19:29 +02:00
jmestwa-coder 44a9fa33fb bound reloc read by ref size in yr_arena_load_stream (#2212) 2026-06-25 10:11:00 +02:00
jmestwa-coder 31d644a83a enable split id bounds check in _yr_re_fiber_sync (#2208) 2026-06-24 12:00:26 +02:00
jmestwa-coder 1d58245c8e read dotnet and pe file fields through unaligned helpers (#2210) 2026-06-24 11:49:17 +02:00
jmestwa-coder def0eb0a1a check reloc buffer_id before deref in yr_arena_load_stream (#2202)
noticed the relocation loop in yr_arena_load_stream reads b->data before it checks reloc_ref.buffer_id against num_buffers. the id comes straight from the loaded stream, so a crafted reloc entry with a large buffer_id indexes far past the 16-slot buffers array and reads out of bounds. moving the range check ahead of the dereference rejects it as corrupt first. looks like the check order got flipped in #2178. added a regression test in test-arena.c.
2026-06-16 10:32:03 +02:00
jmestwa-coder 690b3d0fda guard against undersized rich header in pe_parse_rich_signature (#2200)
When the backward scan in pe_parse_rich_signature finds a DanS marker only one to three dwords ahead of the Rich marker, rich_len ends up smaller than RICH_SIGNATURE. The unsigned subtraction rich_len - sizeof(RICH_SIGNATURE) then wraps and rich_count becomes a huge bogus value that drives the version_data allocation and copy loop. _rich_version already rejects rich_length < sizeof(RICH_SIGNATURE) for the same computation, so apply the same check before computing rich_count here.
2026-06-01 12:34:37 +02:00
DavidKorczynski f90a21ca7b tests: Add new fuzzers to be consumed by OSS-Fuzz (#2197)
Adds new fuzzing harnesses that increases the code coverage relative to a recent oss-fuzz coverage report:
https://storage.googleapis.com/oss-fuzz-coverage/yara/reports/20260503/linux/src/report.html

These harnesses will be consumed by OSS-Fuzz and start running once landed.

Signed-off-by: David Korczynski <[email protected]>
2026-05-06 12:09:01 +02:00
Victor M. Alvarez bae530c7f0 Remove Bazel as a build system. (#2144)
Bazel was the build system used by VirusTotal. Now that VirusTotal has moved to YARA-X, maintaining the Bazel infrastructure working is painful, specially with the backward incompatible changes introduced in recent versions of Bazel.
2025-04-09 20:44:51 +02:00
secDre4mer d3eae3258a fix: correct indentation issues (#2133) 2025-01-13 10:12:02 +01:00
Victor M. Alvarez 8616165472 Fix segfault with regular expressions that matched the zero-length string.
In regular expressions, repetition operators`{0,0}` and `{,0}` are valid, but they always match the zero-length string. For instance, `a{0,0}` and `[a-z]{0,0}` both match the zero-length string.

When the whole regular expression consists in one of these repetitions it caused a segfault during the evaluation of the regular expression because the `forward_code_ref` field for the root atom in the atom's tree was null.

Closes #2084.
2024-06-19 13:47:58 +02:00
Victor M. Alvarez f1640e24ec Allow spaces in regexp repetition operators.
For instance, `x{n, m}`, `x{n ,m}` and `x{n  ,  m}` are all equivalent to `x{n,m}`. This is done for compatibility with YARA-X, but I've seen real-life regular expressions in that contain such spaces, for example:

```
/C:\\Users\\qqq\\.{30, 50}\.pdb/
```
2024-05-22 15:51:43 +02:00
Victor M. Alvarez 3395fee53c Remove assertion from test-aligment.c
`off_t` is not 64 bits in all platforms (like Win32)
2024-04-08 10:53:32 +02:00
Victor M. Alvarez 924fa58ce9 Fix issue #2065
The issue was causing false negative with certain patterns.
2024-04-08 10:28:31 +02:00
Victor M. Alvarez 833a580430 Fix issue #2050.
See also PR #2048.
2024-04-07 17:56:43 +02:00
Victor M. Alvarez 7b4dcd8cce Fix alignment tests.
They were returning OK in all cases, it was broken in cba6932759.
2024-04-07 17:56:36 +02:00
Victor M. Alvarez 94b7da931c Add test case for math.entropy where input is an empty string. 2024-03-25 10:49:06 +01:00
Victor M. Alvarez ff959e562a Add more test cases. 2024-03-20 15:49:14 +01:00
Victor M. Alvarez c80cd9debf Fix issue with matches operator not matching empty strings
The `matches` operator was returning false if the left operand was an empty strings. So, `"" matches <some regexp>` was returning false regardless of the regexp used. However, some regexp *do* match the empty strings, like for example `/foo|/`.
2024-03-20 15:47:37 +01:00
Victor M. Alvarez 4369ca6a1b Fix endianness issues in macho module (#2041)
This is backward compatible change that affects the `magic` field. After this change the value in the `magic` field looks exactly as it looks in the file regardless of the endianness of the current platform, if the file starts with `CA FE BA BE` the value in magic is `0xCAFEBABE`, not `0xBEBAFECA` as it used to be in little-endian architectures.
2024-02-12 15:23:09 +01:00
Victor M. Alvarez f3b3027154 Allow quantifiers {0} and {0,0}.
Regexps with quantifiers `{0}` and `{0,0}` were considered syntactically invalid. These quantifiers are not  actually useful, but they are now allowed for compatibility with other regexp engines.

Closes #2037.
2024-02-12 11:47:17 +01:00
Victor M. Alvarez c1c5d89052 pe.is_signed is now defined for all PE files.
Until now, `pe.is_signed` was undefined for every PE file that was not signed, making impossible to use it in negated conditions, like `pe.is_pe and not pe.is_signed`. With this change, `pe.is_signed` is false for every PE file that is not signed.

Closes #2040
2024-02-12 11:10:49 +01:00
Victor M. Alvarez e065be6716 Add test case for magic field in macho module.
This should confirm an issue with the endianness of `magic` field in big-endian platforms.
2024-01-30 21:32:02 +01:00
Victor M. Alvarez 4d696a91b1 Fix test cases 2024-01-15 22:31:18 +01:00
Victor M. Alvarez 79794c4053 Fix issue with regexps not matching empty strings.
Some regexps like `/(abc|)/` where not matching the empty string even if they should. Matching an empty string is not very useful, as such regexp will match on every offset of every file, but this is fixed for correctness.

Also fixes another issue with the `\b` metacharacter in regexps, which was exposed after fixing the main issue.
2024-01-15 16:51:11 +01:00
Victor M. Alvarez bb28999b33 Autoformat test/util.h 2024-01-15 16:34:12 +01:00
Victor M. Alvarez a3d938b429 Minor style fixes. 2024-01-15 13:07:34 +01:00
Victor M. Alvarez 5b6f0f6ecd Add test case for math.mode
Cover the case in which there are two bytes that appear the same number of times. The lowest byte should be the mode.
2023-12-28 18:10:34 +01:00
Victor M. Alvarez a1015aa3a9 math.percentage returns undefined value when the passed value is outside the 0-255 range. 2023-12-28 17:34:23 +01:00
Victor M. Alvarez c6cc3311ce math.count returns undefined value when the passed value is outside the 0-255 range. 2023-12-28 16:44:48 +01:00
Victor M. Alvarez cddec11934 Fix bug that broke global rules.
PR #1927 didn't take into account that as a side-effect of skipping the evaluation of global rules, the corresponding namespace was not flagged as unsatisfied (i.e: a global rule that evaluates to false prevents all other rules in the namespace from evaluating to true). The issue was not caught by any test case because the test case for global rules were using rules that didn't required any strings to match, and therefore were unaffected by the changes introduced in #1927.

This change makes sure that any global rule that is skipped is considered false, and therefore its namespace is flagged as unsatisfied.

Closes #2022.
2023-12-10 20:27:05 +01:00
secDre4mer 19da77ef4f feat: handle SIGBUS / SIGSEGV only when originating from YARA's memory blocks (#2020)
* feat: prevent race conditions on signal handler

If multiple threads were running in parallel (e.g. each using a
YR_SCANNER), race conditions could cause the original signal handler
to not be restored correctly.
Add a mutex that controls access to the (process wide) signal handler
to ensure that the YARA signal handler is only installed once and
only removed when it is no longer needed.

* feat: forward signal to old signal handler

If a signal is received that does not originate from YARA (which is
quite possible in multi-threaded applications using YARA), it is
currently ignored. Especially for SIGSEGV, this may cause unexpected
behaviour in the caller, even in threads that do not use YARA.

Add logic to call the original signal handler to handle this case
more cleanly. It is not perfect - with only a process wide signal
handler, it's probably impossible to have a perfect solution -
but it's better than the current behaviour.

* fix: make exception test more verbose

* fix: only handle signals in memory block data

Some callbacks from YARA code are done from YR_TRYCATCH. Currently,
YARA assumes that SIGBUS / SIGSEGV from these callbacks are due to
the scanned memory range, but this is not necessarily true.
Add logic to identify the currently scanned memory block and only
catch the signal if the SIGBUS / SIGSEGV originated from it.

* chore: simplify signal handler forwarding

* feat: reduce caught signals to required for known OS
2023-12-08 00:12:05 +01:00
Victor M. Alvarez 01032a6cb2 Fix bug while calculating the imphash in PE files.
When the file imported DLLs that contained a dot (.) in its name, like `glib-2.0.dll`, the file extension was not properly removed, causing the the imphash to be wrong.
2023-11-17 11:37:35 +01:00
Victor M. Alvarez f3e3bddabc Add missing data file to BUILD.bazel 2023-11-09 12:03:40 +01:00
Victor M. Alvarez 7def444cb9 Improve extraction of PDB path from PE files.
A check in `pe_parse_debug_directory` was verifying that the size of the debug directory entry was a multiple of `sizeof(IMAGE_DEBUG_DIRECTORY)`. Although this is true in most cases, is not universally true for all PE files. This check was preventing the extraction of the PDB path from certain EFI boot files, like the ones below. The PDB path in such cases is not a file path but a GUID, though.

Some affected files:

`6c2abf4b80a87e63eee2996e5cea8f004d49ec0c1806080fa72e960529cba14c`
`5487a2ff41e360b1d3b0a58e393b0041c3f269f1053a3e367dfecd48e233457e`
2023-11-09 09:31:47 +01:00
John 52e4f1c8f3 Revert "LNK Module (#1957)"
This reverts commit 8ce0c6c4eb. See comments in https://github.com/VirusTotal/yara/pull/1957 for more context.
2023-10-06 11:01:02 +02:00