Closed Bug 1947139 (CVE-2025-1942) Opened 10 months ago Closed 10 months ago

A bug in toUpperCase string chars reallocation

Categories

(Core :: JavaScript Engine, defect)

Other Branch
defect

Tracking

()

RESOLVED FIXED
137 Branch
Tracking Status
firefox-esr115 --- unaffected
firefox-esr128 --- unaffected
firefox135 --- wontfix
firefox136 + fixed
firefox137 + fixed

People

(Reporter: anbu1024.me, Assigned: jandem)

References

(Regression)

Details

(4 keywords, Whiteboard: [adv-main136+])

Attachments

(3 files)

User Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36 Edg/132.0.0.0

Steps to reproduce:

A bug in JIT optimization, whether there are security risks or not requires further in-depth analysis.

version:commit 3166120f85161b7fe84565135b04c685da1dd34f

Build options:

/bin/sh ../../gecko-dev/js/src/configure --enable-debug --disable-optimize --disable-shared-js --disable-tests --enable-gczeal

Test case:

./js --baseline-warmup-threshold=10 --ion-warmup-threshold=50 --ion-check-range-analysis --ion-extra-checks

case1:

function opt(){
  const v0 = String.fromCharCode(-1896350971);
  const v1 = Number();
  const v2 = [v1,-128,v0];
  const v3 = JSON.stringify(v2);
  const v4 = String.fromCharCode();
  const v5 = eval();
  async function v6() {
      const v7 = await "";
  }
  const v8 = v6();
  const v9 = v4.padEnd(46985);
  const v10 = v9.replace(v4);
  const v11 = v3.toUpperCase();
  return v11;
}
  
let a = opt();
let b = opt();
for (let i = 0; i < 55; i++) {
  opt();
}
let c = opt();
print(a);
print(b);
print(c);

case2:

function opt(){
  function v0() {
      let v1 = 1024;
      async function v2() {
          await "";
      }
      v2();
      const v3 = [];
      const v4 = v1--;
      v3.length = v4;
      const v5 = v3.toLocaleString();
      const v6 = eval();
  }
  v0();
  v0();
  const v7 = [2282168226];
  const v8 = v7 + v7;
  const v9 = "valueOf".includes();
  const v10 = String.fromCharCode(v9,2282168226,v8,v7);
  const v11 = JSON.stringify(v10);
  const v12 = v11.toUpperCase();
  return v12;
}
  
let a = opt();
let b = opt();
for (let i = 0; i < 55; i++) {
  opt();
}
let c = opt();
print(a);
print(b);
print(c);

case3:

function opt(){
  const v0 = [2282168226];
  const v1 = v0 + v0;
  const v2 = new WeakMap();
  const v3 = [1e-15,[],Proxy];
  const v4 = new Proxy([],v2);
  for (const v5 in v3) {
      v4[1000] >>= v5;
      let v6 = 1024;
      const v7 = [];
      const v8 = v6--;
      v7.length = v8;
      const v9 = v7.toLocaleString();
      function v10() {
      }
      const v11 = new Promise(Promise);
      const v12 = v11.catch(v10);
      const v13 = eval();
  }
  const v14 = new Uint16Array();
  const v15 = "valueOf".includes();
  const v16 = String.fromCharCode(v15,2282168226,v1,v0);
  const v17 = JSON.stringify(v16);
  const v18 = v17.toUpperCase();
  return v18;
}
  
let a = opt();
let b = opt();
for (let i = 0; i < 55; i++) {
  opt();
}
let c = opt();
print(JSON.stringify(a));
print(JSON.stringify(b));
print(JSON.stringify(c));

Actual results:

The result has changed after JIT optimization.
case1:

a = [0,-12ⴭ<ⴭST"]
b = [0,-12ⴭ<ⴭST"]
c = [0,-12

case2:

a = "\U000ⴭὪΙ怀ὪΙ"
b = "\U000ⴭὪΙ怀ὪΙ"
c = "\U000

case3:

a = "\"\\U000ⴭὪΙ怀ὪΙ\""
b = "\"\\U000ⴭὪΙ怀ὪΙ\""
c = "\"\\U000\u0000ὪΙ怀ὪΙ\""
Group: core-security → javascript-core-security

I'm looking into this. Likely a problem with toUpperCase.

Flags: needinfo?(jdemooij)

This is a nice catch. Here's a minimal test case:

assertEq("...........\u1FA2".toUpperCase(), "...........\u1F6A\u0399");

This fails with:

Error: Assertion failed: got "......\u2D2D\uFFFE\u2D2D\u2D2D\u2D2D\u1F6A\u0399", expected "...........\u1F6A\u0399"

Note that 0x2D is a poison value. The original test is more complicated, to end up with different values for the uninitialized/poison bytes that then fail the check.

This happens because in StringChars<CharT>::maybeRealloc we do a memcpy that copies InlineLength bytes from the inline storage to a nursery-allocated buffer, instead of InlineLength * sizeof(CharT) bytes. This affects strings like this case where the upper-case version is longer than the original string.

I'll mark this sec-moderate because this could be used to read (a small number of) uninitialized nursery memory bytes.

Assignee: nobody → jdemooij
Status: NEW → ASSIGNED
Component: JavaScript Engine: JIT → JavaScript Engine
Flags: needinfo?(jdemooij)
Regressed by: 1910084
Summary: A bug in JIT optimization: an exception about the value of strings → A bug in toUpperCase string chars reallocation

Set release status flags based on info from the regressing bug 1910084

Pushed by jdemooij@mozilla.com: https://hg.mozilla.org/integration/autoland/rev/6307454330d5 Fix memcpy in StringChars::maybeRealloc. r=iain

Comment on attachment 9465641 [details]
Bug 1947139 - Fix memcpy in StringChars::maybeRealloc. r?iain!

Beta/Release Uplift Approval Request

  • User impact if declined/Reason for urgency: Security issues, broken websites.
  • Is this code covered by automated tests?: Yes
  • Has the fix been verified in Nightly?: No
  • Needs manual test from QE?: No
  • If yes, steps to reproduce:
  • List of other uplifts needed: None
  • Risk to taking this patch: Low
  • Why is the change risky/not risky? (and alternatives if risky): It's a very small and straight-forward patch.
  • String changes made/needed: N/A
  • Is Android affected?: Yes
Attachment #9465641 - Flags: approval-mozilla-beta?
Group: javascript-core-security → core-security-release
Status: ASSIGNED → RESOLVED
Closed: 10 months ago
Resolution: --- → FIXED
Target Milestone: --- → 137 Branch

Comment on attachment 9465641 [details]
Bug 1947139 - Fix memcpy in StringChars::maybeRealloc. r?iain!

Approved for 136.0b7

Attachment #9465641 - Flags: approval-mozilla-beta? → approval-mozilla-beta+
QA Whiteboard: [post-critsmash-triage]
Flags: qe-verify-
Whiteboard: [adv-main136+]
Attached file advisory.txt
Alias: CVE-2025-1942
Group: core-security-release
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: