Skip to content

jerryscript jerry-snapshot tool: unbounded literals-list parser → global-buffer-overflow (OOB write) in process_generate #5293

Description

@h0rk1p

jerryscript jerry-snapshot tool: unbounded literals-list parser -> global-buffer-overflow (OOB write) in process_generate

Severity: LOW | CVSS 3.1: 3.9 CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:L/A:L | CWE: CWE-787 | Affected: jerryscript @ b7069350c2e5

Summary

The jerry-snapshot command-line tool's --load-literals-list-format parser (process_generate) reads literal entries from a text file in a loop, incrementing num_of_lit and writing magic_string_items[num_of_lit] (an 8-byte pointer) and magic_string_lengths[num_of_lit] (a 4-byte attacker-controlled length) per entry, WITHOUT ever bounding num_of_lit against JERRY_LITERAL_LENGTH (4096), the size of those two fixed-size global arrays. A literals-list with more than 4096 positive-size entries writes past the end of magic_string_items (size 32768 = 4096*8) into adjacent globals (input_buffer), a controllable global-buffer-overflow write. This is in the jerry-snapshot tool, which is built only with -DJERRY_CMDLINE_SNAPSHOT=ON (documented, supported, but OFF by default; the default jerry binary does not contain it).

Affected

  • Component: jerryscript@b7069350c2e52e7dc721dfb75f067147bd79b39b - jerry-main/main-snapshot.c:323 (process_generate, the --load-literals-list-format parser); fixed-size globals magic_string_items[4096]/magic_string_lengths[4096] declared at main-snapshot.c:47
  • Repository / commit: https://github.com/jerryscript-project/jerryscript @ b7069350c2e52e7dc721dfb75f067147bd79b39b
  • Attacker / interface: An actor who can supply the literals-list FILE consumed by jerry-snapshot generate --load-literals-list-format <FILE> <src.js> (a local/build-time vector; the victim runs the snapshot generator on the attacker-provided list).

Root cause

jerry-main/main-snapshot.c:47  static const char *magic_string_items[JERRY_LITERAL_LENGTH]; static jerry_length_t magic_string_lengths[JERRY_LITERAL_LENGTH];  /* JERRY_LITERAL_LENGTH == 4096 */
... process_generate (~line 300-325): while parsing the literals-list, for each entry: magic_string_items[num_of_lit] = <ptr into input_buffer>; magic_string_lengths[num_of_lit] = <attacker length>; num_of_lit++;  /* no `num_of_lit < JERRY_LITERAL_LENGTH` guard -> OOB write at entry #4097 (index 4096) */

Reachability (untrusted source -> sink)

  1. Build the snapshot tool: python3 tools/build.py --jerry-cmdline-snapshot=on (documented option; produces build/bin/jerry-snapshot). 2. jerry-snapshot generate --load-literals-list-format <src.js> -> process_generate parses -> unbounded loop -> OOB write. NOT reachable from the default jerry binary (JERRY_CMDLINE_SNAPSHOT=OFF by default).

To reproduce

  1. git clone https://github.com/jerryscript-project/jerryscript && cd jerryscript && git checkout b706935
  2. python3 tools/build.py --jerry-cmdline-snapshot=on # documented option; builds build/bin/jerry-snapshot
  3. python3 -c "open('/tmp/lits.list','w').write('1 a\n'*4097)"
  4. printf 'var a=1;\n' > /tmp/src.js
  5. build/bin/jerry-snapshot generate --load-literals-list-format /tmp/lits.list /tmp/src.js -o /tmp/out.snapshot # -> OOB write past magic_string_items (crash; ASAN: global-buffer-overflow at main-snapshot.c:47)
  6. Negative control (exactly 4096 entries): python3 -c "open('/tmp/lits.list','w').write('1 a\n'*4096)" then re-run -> clean snapshot, no overflow

Output

AddressSanitizer: global-buffer-overflow, WRITE of size 8, '0 bytes after global variable magic_string_items ... main-snapshot.c:47 of size 32768'. Deterministic across both runs, exact boundary at entry #4097.

Demonstrated vs inferred: Demonstrated: controllable global OOB write (8-byte pointer + 4-byte attacker value) past a fixed 4096-entry global array in the jerry-snapshot tool; crash/corruption. Not demonstrated: end-to-end exploitation. Severity reflects the local/non-default-build/file vector (Low).

Impact

Out-of-bounds write of a layout-controlled pointer plus a fully attacker-controlled 4-byte value past the magic_string_items global; demonstrated effect is memory corruption / crash of the jerry-snapshot generation tool. Low severity: requires the non-default jerry-snapshot build, a local literals-list file, and the victim to run the generator on it (developer/build-pipeline scenario), so real-world impact is limited.

Suggested fix

Bound the parse loop: reject or stop when num_of_lit reaches JERRY_LITERAL_LENGTH (e.g. if (num_of_lit >= JERRY_LITERAL_LENGTH) { error "too many literals"; } before writing magic_string_items[num_of_lit]/magic_string_lengths[num_of_lit]).

References

Environment

  • jerryscript @ commit b7069350c2e52e7dc721dfb75f067147bd79b39b - default build (./configure && make), default config.

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