You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[Bug]Snapshot deserialization lacks bounds checks on untrusted offset/length fields -> out-of-bounds read (SEGV / ASan use-after-poison / DoS) (CWE-125) #5301
jerry_exec_snapshot deserializes an external, untrusted buffer directly as a snapshot (header + function bytecode + literal table). It only validates func_index < number_of_funcs and lit_table_offset <= snapshot_size, but never validates that:
func_offsets[func_index] points inside the valid bytecode region, or
the bytecode's internal size/refs fields, or the literal-table offset/length fields, are in-bounds.
The code then constructs an ecma_compiled_code_t * from (snapshot_data_p + func_offset) and dereferences it, or performs memcpy/memcmp/loop reads over untrusted lengths in snapshot_load_compiled_code / ecma_snapshot_get_literal / lit_utf8_string_length / lit_is_utf8_string_magic. This reads beyond the input buffer: ASan marks bytes past the real input as poisoned (use-after-poison), and huge/illegal offsets directly cause SEGV.
The deserializer trusts attacker-controlled offset/length fields in the snapshot header and bytecode. A malformed snapshot (from ~36 bytes up to a few hundred bytes) drives:
==3332255==ERROR: AddressSanitizer: SEGV on unknown address 0x7b3c4d2c47f9 (pc ... T0)
The signal is caused by a READ memory access.
#0 0x55d24492ea0a in jerry_exec_snapshot jerry-snapshot.c:915:32
#1 0x55d24492ac56 in fuzz_snapshot harness.c:138:25
#2 0x55d24492ac56 in LLVMFuzzerTestOneInput harness.c:185:5
Other variants in the same root cause: ASan use-after-poison in snapshot_load_compiled_code (memcpy of size 65536) and ecma_snapshot_get_literal (READ of size 1/2/8).
Replay exit code: 134 (ASan abort)
Deterministic: yes — 16+ distinct crash inputs across the campaign, all in the snapshot deserialization path.
Impact
Any application that passes an untrusted byte string to jerry_exec_snapshot (loading user-uploaded / network-downloaded .jsn snapshots, or precompiled bytecode on embedded devices) can be crashed deterministically by a tens-of-bytes malformed snapshot (DoS). The defect is an OOB read (not write), so direct arbitrary-code-execution is not realistic; however, the OOB read can pull adjacent/uninitialized heap memory into JS string/number values. If the app subsequently prints/logs/serializes those values, heap information disclosure is possible, which can serve as a leak primitive for further exploitation.
Suggested fix
Validate func_offsets[func_index] against the actual bytecode region bounds before constructing the ecma_compiled_code_t pointer (jerry-snapshot.c:915).
Bound-check every internal size/length field in snapshot_load_compiled_code and the literal table before memcpy/memcmp/loop reads (ecma-literal-storage.c, lit-strings.c, lit-magic-strings.c).
Treat the snapshot as untrusted input: enforce that all offsets/lengths are >= header_size and <= snapshot_size, and reject malformed layouts (e.g., number of funcs vs. available bytes).
Opened #5311 with a fix. Three unchecked offsets are involved: the func_offsets[func_index] used to locate the compiled code, the block size
stored in the compiled code header, and the literal offsets recursed into by snapshot_load_compiled_code(). The fix bounds each of them by the snapshot
buffer and threads the bounds through the recursive call.
Re-verified on current master (b706935), 73-byte snapshot:
Distinct from #5302: that one is a stack OOB read inside vm_init_exec
(vm.c:5190) after a snapshot has loaded, fixed by #5310. This one is the
deserializer reading outside the input buffer before the VM is reached.
Activity
[-]Snapshot deserialization lacks bounds checks on untrusted offset/length fields -> out-of-bounds read (SEGV / ASan use-after-poison / DoS) (CWE-125)[/-][+][Bug]Snapshot deserialization lacks bounds checks on untrusted offset/length fields -> out-of-bounds read (SEGV / ASan use-after-poison / DoS) (CWE-125)[/+]1820893135-pixel commentedon Sep 23, 2026
Opened #5311 with a fix. Three unchecked offsets are involved: the
func_offsets[func_index]used to locate the compiled code, the block sizestored in the compiled code header, and the literal offsets recursed into by
snapshot_load_compiled_code(). The fix bounds each of them by the snapshotbuffer and threads the bounds through the recursive call.
Re-verified on current
master(b706935), 73-byte snapshot:Distinct from #5302: that one is a stack OOB read inside
vm_init_exec(
vm.c:5190) after a snapshot has loaded, fixed by #5310. This one is thedeserializer reading outside the input buffer before the VM is reached.