Closed Bug 2073652 Opened 1 month ago Closed 1 month ago

Ion skips Proxy get validation for non-writable array length

Categories

(Core :: JavaScript Engine, defect, P3)

defect

Tracking

()

RESOLVED FIXED
158 Branch
Tracking Status
firefox158 --- fixed

People

(Reporter: bugmon, Assigned: iain)

References

(Blocks 1 open bug)

Details

(Keywords: sec-other, testcase, Whiteboard: [adv-main158-])

Attachments

(3 files, 1 external file)

GetObjectFlagsForNewProperty uses isDataProperty() when setting NeedsProxyGetSetResultValidation, excluding custom data properties such as array length. Making length non-writable therefore leaves the validation flag unset, causing Ion's scripted Proxy getter to skip the required result check.

A webpage can bypass JavaScript Proxy invariants by exercising Ion's optimized getter with an array whose length is non-writable. The verified result is 17 for a target length fixed at 0, where a TypeError is required. No memory corruption or sandbox escape was demonstrated.

This finding was discovered during variant analysis seeded by bug 1989978.

Build Info

Affected Code

File: js/src/vm/ObjectFlags-inl.h, line 41-42

    if (propFlags.isDataProperty() && !propFlags.writable()) {
      flags.setFlag(ObjectFlag::NeedsProxyGetSetResultValidation);

File: js/src/vm/PropertyInfo.h, line 66-68

  bool isDataProperty() const {
    return !isAccessorProperty() && !isCustomDataProperty();
  }

File: js/src/jit/CodeGenerator.cpp, line 17960-17963

  masm.unboxObject(target, scratch);
  masm.branchTestObjectNeedsProxyResultValidation(Assembler::NonZero, scratch,
                                                  scratch2, ool->entry());
  masm.bind(ool->rejoin());

ArraySetLength preserves the custom-data classification when clearing Writable (js/src/builtin/Array.cpp:915-923). The generated validation gate tests NeedsProxyGetSetResultValidation (js/src/jit/MacroAssembler.cpp:6233-6235). The interpreter instead checks the exposed data descriptor and rejects unequal values (js/src/proxy/ScriptedProxyHandler.cpp:1195-1203).

Exploit Chain

  1. Create an empty array and a Proxy whose get trap returns 17.
  2. Warm a function reading proxy.length until Ion compiles the optimized getter.
  3. Make the target array's length non-writable.
  4. Read through the optimized getter; it returns 17 instead of throwing the required TypeError.

Steps to Reproduce

  1. Use /app/output/verification-proxy-readonly-length/proxy-readonly-length.js.
  2. Build clean source using build_firefox with firefox_dir=/firefox and mozconfig_path=/app/mozconfigs/mozconfig.js.linux.debug.
  3. Run js_shell_differential_evaluator with /firefox/obj-js-debug/dist/bin/js for both shells, flags_a=[--no-threads,--no-jit-backend], and flags_b=[--no-threads,--ion-warmup-threshold=100]. The evaluator adds --fuzzing-safe.
  4. Observe differs: true, shell A exit 0, and shell B exit 3 with Error: Missing TypeError for immutable array length.
  5. Repeat with --differential-testing added to both flag sets; observe the same discrepancy without timeouts.
  6. Independent controls pass with Ion disabled or --cache-ir-stubs=off. Adding an ordinary non-configurable, non-writable target property restores validation; adding a configurable property does not.
  7. Exact evaluator commands, captured logs, and control testcases are preserved in /app/output/verification-proxy-readonly-length/evidence.json.

Security Impact

  • Severity: Low
  • Attacker capability: Obtain an incorrect Proxy result that violates an immutable property's invariant. The demonstrated capability is limited to JavaScript semantics; no memory corruption, disclosure, or privilege escalation was established.
  • Preconditions: The property read must reach Ion's optimized scripted Proxy getter. The target array has non-writable length and lacks another property that sets the validation flag. Reproduction required no source patches, browser preferences, external services, or shell-only helpers.

ASAN Report

No sanitizer crash occurred; this finding is js_differential. Both required comparisons reported differs: true, with interpreter exit 0 and Ion exit 3. Ion stderr reported: Error: Missing TypeError for immutable array length. A diagnostic control confirmed returned value 17 with target length descriptor {"value":0,"writable":false,"enumerable":false,"configurable":false}.
Attached patch fix.patch — — Splinter Review
Attached file crash_stack.txt —

This bug was filed automatically by an AI-powered security testing tool. The analysis, testcase, and any suggested patches were generated by an AI model and have NOT been verified by a human.

Please review all details carefully before triaging. The issue was confirmed by an independent verifier, but for non-ASAN issues, the verifier has been made less strict. Additionally, the root cause analysis and suggested fix may contain errors.

Group: core-security → javascript-core-security

This isn't security-sensitive, but sure, the patch looks correct.

Group: javascript-core-security
Blocks: sm-security
Severity: -- → S3
Priority: -- → P3
Assignee: nobody → iireland
Status: UNCONFIRMED → ASSIGNED
Ever confirmed: true
Status: ASSIGNED → RESOLVED
Closed: 1 month ago
Resolution: --- → FIXED
Target Milestone: --- → 158 Branch
QA Whiteboard: [qa-triage-done-c159/b158]
Whiteboard: [adv-main158-]
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: