Closed Bug 446494 Opened 17 years ago Closed 17 years ago

Buffer overflow in Number.toLocaleString()

Categories

(Core :: JavaScript Engine, defect)

1.9.0 Branch
x86
Linux
defect
Not set
critical

Tracking

()

VERIFIED FIXED

People

(Reporter: philip, Assigned: crowderbt)

References

Details

(Keywords: verified1.8.1.17, verified1.9.0.2, Whiteboard: [sg:critical?])

Attachments

(6 files, 1 obsolete file)

Using SpiderMonkey from CVS trunk: $ LANG=C valgrind ./js -e '1e-10.toLocaleString()' ==3190== Invalid read of size 1 ==3190== at 0x80A5DD0: num_toLocaleString (jsnum.c:367) ==3190== by 0x81226A4: js_Interpret (jsinterp.c:4835) ==3190== by 0x80A0D96: js_Execute (jsinterp.c:1536) ==3190== by 0x80620DB: JS_EvaluateUCScriptForPrincipals (jsapi.c:4999) ==3190== by 0x8062049: JS_EvaluateUCScript (jsapi.c:4980) ==3190== by 0x8061F53: JS_EvaluateScript (jsapi.c:4946) ==3190== by 0x804A076: ProcessArgs (js.c:518) ==3190== by 0x804F4D5: main (js.c:3931) ==3190== Address 0x41cc0ce is 0 bytes after a block of size 6 alloc'd ==3190== at 0x402291D: malloc (in /usr/lib/valgrind/x86-linux/vgpreload_memcheck.so) ==3190== by 0x805BBE0: JS_malloc (jsapi.c:1791) ==3190== by 0x80F6F62: js_DeflateString (jsstr.c:2927) ==3190== by 0x80F7B08: js_GetStringBytes (jsstr.c:3232) ==3190== by 0x80A5BDB: num_toLocaleString (jsnum.c:323) ==3190== by 0x81226A4: js_Interpret (jsinterp.c:4835) ==3190== by 0x80A0D96: js_Execute (jsinterp.c:1536) ==3190== by 0x80620DB: JS_EvaluateUCScriptForPrincipals (jsapi.c:4999) ==3190== by 0x8062049: JS_EvaluateUCScript (jsapi.c:4980) ==3190== by 0x8061F53: JS_EvaluateScript (jsapi.c:4946) ==3190== by 0x804A076: ProcessArgs (js.c:518) ==3190== by 0x804F4D5: main (js.c:3931) ==3190== ==3190== Invalid write of size 1 ==3190== at 0x80A5E80: num_toLocaleString (jsnum.c:384) ==3190== by 0x81226A4: js_Interpret (jsinterp.c:4835) ==3190== by 0x80A0D96: js_Execute (jsinterp.c:1536) ==3190== by 0x80620DB: JS_EvaluateUCScriptForPrincipals (jsapi.c:4999) ==3190== by 0x8062049: JS_EvaluateUCScript (jsapi.c:4980) ==3190== by 0x8061F53: JS_EvaluateScript (jsapi.c:4946) ==3190== by 0x804A076: ProcessArgs (js.c:518) ==3190== by 0x804F4D5: main (js.c:3931) ==3190== Address 0x41cc146 is 0 bytes after a block of size 6 alloc'd ==3190== at 0x402291D: malloc (in /usr/lib/valgrind/x86-linux/vgpreload_memcheck.so) ==3190== by 0x805BBE0: JS_malloc (jsapi.c:1791) ==3190== by 0x80A5D98: num_toLocaleString (jsnum.c:360) ==3190== by 0x81226A4: js_Interpret (jsinterp.c:4835) ==3190== by 0x80A0D96: js_Execute (jsinterp.c:1536) ==3190== by 0x80620DB: JS_EvaluateUCScriptForPrincipals (jsapi.c:4999) ==3190== by 0x8062049: JS_EvaluateUCScript (jsapi.c:4980) ==3190== by 0x8061F53: JS_EvaluateScript (jsapi.c:4946) ==3190== by 0x804A076: ProcessArgs (js.c:518) ==3190== by 0x804F4D5: main (js.c:3931) jsnum.c:367 is the line "while (*tmpSrc == '-' || remainder--)". jsnum.c:384 is the line "*tmpDest++ = '\0';".
Assignee: general → crowder
Severity: normal → critical
Flags: blocking1.9.1?
Flags: blocking1.9.0.2?
Flags: blocking1.8.1.17?
Group: security
So we don't handle exponential notation in this routine at all.
Non-finite values aren't handled properly either -- Infinity.toLocaleString() == "In,fin,ity" in my default locale (en_GB).
Attached patch v1 (obsolete) — Splinter Review
Will ask for review after testing.
Attached patch v2Splinter Review
Attachment #330789 - Attachment is obsolete: true
Since we use strcpy() later, we need the '\0'. It's semi-extraneous, since we use JS_NewString at the end (ie., we don't need the terminator), but the string routines are convenient and clean, so I think it's a worthwhile tradeoff.
Attachment #330794 - Flags: review?(mrbkap)
Comment on attachment 330794 [details] [diff] [review] v3, leave room for '\0' >--- mozilla.7c4f66de2dee/js/src/jsnum.cpp 2008-07-22 10:24:36.000000000 -0700 >+ while(*nint >= '0' && *nint <= '9') >+ nint++; Nit: space after while. r=mrbkap with that.
Attachment #330794 - Flags: review?(mrbkap) → review+
changeset: 16181:c37a070f8397
Attachment #331172 - Flags: approval1.9.0.2?
Attached patch 1.8 branch patchSplinter Review
Attachment #331175 - Flags: approval1.8.1.17?
Status: NEW → RESOLVED
Closed: 17 years ago
Resolution: --- → FIXED
(In reply to comment #6) > (From update of attachment 330794 [details] [diff] [review]) > >--- mozilla.7c4f66de2dee/js/src/jsnum.cpp 2008-07-22 10:24:36.000000000 -0700 > > >+ while(*nint >= '0' && *nint <= '9') > >+ nint++; > > Nit: space after while. r=mrbkap with that. Uber-nit: usually SpiderMonkey style uses number-line order: '0' <= c && c <= '9'. Could also rearrange (check that gcc doesn't do this) to avoid a branch: (uintN)(c - '0') <= '9' - '0' or (uintN)(c - '0') < 10 /be
Can we get an automated test for this before landing on the 1.9 branch?
Flags: wanted1.9.0.x+
Flags: in-testsuite?
Whiteboard: [needs test]
Flags: blocking1.9.0.2?
Flags: blocking1.9.0.2+
Flags: blocking1.8.1.17?
Flags: blocking1.8.1.17+
Whiteboard: [needs test] → [sg:critical?][needs test]
QA doesn't want to take on the 1.8 branch without a testcase, and not on the 1.9.0 branch without an automated one (which was probably a requirement for mozilla-central, right?)
The original bug will be difficult to write a testcase for, but the In,fin,ity one and similar bugs may not be. The reason for difficulty in writing a case for the original bug is that the overflow is caused by an off-by-one in the buffer math, which means we usually don't overflow the space provided by malloc(). I'll see if I can figure out something more consistent/reliable.
Even if we can't get a reliable crash for the overrun, we can still detect this using valgrind. I'll check this test in later today.
dveditz: Am I cleared-to-land for branches, once the testcase is landed?
Whiteboard: [sg:critical?][needs test] → [sg:critical?]
Comment on attachment 331172 [details] [diff] [review] 1.9 branch patch (jsnum.cpp => jsnum.c Approved for 1.9.0.2. Please land in CVS. a=ss (After the test lands.)
Attachment #331172 - Flags: approval1.9.0.2? → approval1.9.0.2+
Comment on attachment 331175 [details] [diff] [review] 1.8 branch patch Approved for 1.8.1.17. Please land in CVS. a=ss (After the test lands.)
Attachment #331175 - Flags: approval1.8.1.17? → approval1.8.1.17+
/cvsroot/mozilla/js/tests/ecma_3/Number/15.7.4.3-02.js,v <-- 15.7.4.3-02.js initial revision: 1.1 mozilla-central: changeset: 16381:779beff502f0 Typically I don't check in tests for outstanding security bugs, but here it is.
Flags: in-testsuite?
Flags: in-testsuite+
Flags: in-litmus-
Yeah, I confess I'm not sure I understand the procedure here, and why we went this route. Fortunately, the test doesn't -look- like an obvious security bug (or so it seems to me), but it still seems odd that we're landing a test for it before the fix has shipped in all relevant browsers.
Maybe we need to set some type of policy for tests in relation to security fixes?
We have a policy and the policy is to land the test after fixed releases are out. This was my bad for not noticing the s-s of this bug and pushing to get the test landed.
Flags: blocking1.9.1?
> or > (uintN)(c - '0') < 10 For what it's worth, gcc -does- do this optimization if -fif-conversion is enabled (which it is for -0 and up).
verified 1.8.1, 1.9.0, 1.9.1 shell/browser linux
Status: RESOLVED → VERIFIED
a=asac for 1.8.0.15
Attachment #336242 - Flags: approval1.8.0.15+
Group: core-security
Flags: blocking1.8.0.next+
Depends on: 614931
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Creator:
Created:
Updated:
Size: