Closed Bug 1012642 Opened 6 years ago Closed 6 years ago

Crash on Heap near [@ js::irregexp::ExecuteCode] with possible use-after-free

Categories

(Core :: JavaScript Engine, defect)

x86
Linux
defect
Not set
critical

Tracking

()

VERIFIED FIXED
mozilla32
Tracking Status
firefox31 --- unaffected
firefox32 --- fixed
firefox-esr24 --- unaffected

People

(Reporter: decoder, Assigned: bhackett1024)

References

Details

(5 keywords, Whiteboard: [jsbugmon:update,bisect])

Crash Data

Attachments

(2 files)

The following testcase crashes on mozilla-central revision 41a54c8add09 (run with --fuzzing-safe --ion-eager):


var gTestcases = new Array();
function TestCase(e, a) {
  this.passed = getTestCaseResult();
  gTestcases[gTc++] = this;
}
TestCase.prototype.dump = function() { toPrinted() };
function toPrinted(value) {
  value = String(value);
  value = value.replace(/\\n/g, 'NL').replace(/\\r/g, 'CR').replace(/[^\x20-\x7E]+/g, escapeString);
}
function escapeString (str) {}
function reportCompare (e, a) {
  toPrinted(e);
  toPrinted(a);
  new TestCase();
}
function getTestCaseResult() dump = (function () {});
for ( gTc=0; gTc < gTestcases.length; gTc++ ) {}
function jsTestDriverEnd() {
  try {
    foo();
  } catch(ex) {}
  for (var i = 0; i < gTestcases.length; i++)
    gTestcases[i].dump();
}
reportCompare('', '');
function callback(obj) {}
setObjectMetadataCallback(callback);
gczeal(8);
reportCompare(true, '');
function test2() {
  jsTestDriverEnd();
} test2();
Crash trace:


Program received signal SIGSEGV, Segmentation fault.
0x00007ffff595b7f0 in ?? ()
#0  0x00007ffff595b7f0 in ?? ()
#1  0x0000000000515179 in js::irregexp::ExecuteCode (cx=<optimized out>, codeBlock=<optimized out>, chars=<optimized out>, start=<optimized out>, length=<optimized out>, matches=<optimized out>) at irregexp/RegExpEngine.cpp:1665
#2  0x00000000009afdf4 in js::RegExpShared::execute (this=0x18e74f0, cx=0x180e340, chars=0x7ffff581b608 u"undefined", length=9, lastIndex=0x7fffffff82e0, matches=...) at vm/RegExpObject.cpp:707
#3  0x00000000008eb108 in DoMatchForReplaceGlobal (rdata=..., re=..., linearStr=..., res=0x18ef8e0, cx=0x180e340) at jsstr.cpp:2315
#4  StrReplaceRegExp (cx=0x180e340, rdata=..., rval=...) at jsstr.cpp:2954
#5  0x00000000008ec461 in str_replace_regexp (rdata=..., cx=0x180e340, args=...) at jsstr.cpp:2986
#6  js::str_replace (cx=0x180e340, argc=<optimized out>, vp=<optimized out>) at jsstr.cpp:3213
#7  0x00007ffff6bd0544 in ?? ()
rax     0xf581b61a      140737312306714
=> 0x7ffff595b7f0:      cmpb   $0x0,0x7ffff595(%rax)


On 32 bit, I also saw a trace like this earlier:

Program received signal SIGSEGV, Segmentation fault.
0x4b4b4b4b in ?? ()
(gdb) bt 32
#0  0x4b4b4b4b in ?? ()
#1  0x081026fb in js::irregexp::ExecuteCode (cx=0x91ff810, codeBlock=0xf6940920, chars=0xf6812e68 u"undefined", start=0, length=9, matches=0xffff9c4c)
    at irregexp/RegExpEngine.cpp:1665
#2  0x084ad75f in js::RegExpShared::execute (this=0x92be4e0, cx=0x91ff810, chars=0xf6812e68 u"undefined", length=9, lastIndex=0xffff9c98, matches=...)
    at vm/RegExpObject.cpp:707
#3  0x0841604c in DoMatchForReplaceGlobal (rdata=..., re=..., linearStr=..., res=0x92b3d20, cx=0x91ff810) at jsstr.cpp:2315
#4  StrReplaceRegExp (cx=0x91ff810, rdata=..., rval=...) at jsstr.cpp:2954
#5  0x08417c6d in str_replace_regexp (rdata=..., args=..., cx=0x91ff810) at jsstr.cpp:2986
#6  js::str_replace (cx=0x91ff810, argc=2, vp=0xffff9f4c) at jsstr.cpp:3213
#7  0xf7aeecc4 in ?? ()
#8  0x092fafc0 in ?? ()
#9  0xf7ae56ff in ?? ()


This is sec-critical because it jumps to a poison pattern 0x4b4b4b4b. Jan mentioned this could be a use-after-free. Likely a regression from the irregexp landing, not sure why we didn't pick this up during the fuzzing review.
Flags: needinfo?(bhackett1024)
Keywords: sec-critical
Whiteboard: [jsbugmon:update,bisect]
Group: javascript-core-security
Attached patch patchSplinter Review
This is something I noticed earlier today while trying to fix bug 1010441.  The existing code is missing a read barrier when a RegExpShared is copied from one RegExpObject to another during cloning.  There is a window where the RegExpShared is held live on the stack (via RegExpGuard) but hasn't been copied to the new object (which will trigger a barrier via prepareForUse()).  If a GC is finished (and wasn't started) in this window then the contents of the RegExpShared will not have been traced even though it is kept alive by the RegExpGuard.

This didn't cause problems with yarr because in that case the RegExpShared only holds a reference on a JSAtom* which is also a property of the RegExpObject, but now the RegExpShared is the only object pointing to its JitCode*.
Attachment #8425827 - Flags: review?(wmccloskey)
Flags: needinfo?(bhackett1024)
Assignee: nobody → bhackett1024
Attachment #8425827 - Flags: review?(wmccloskey) → review+
https://hg.mozilla.org/mozilla-central/rev/8eaf03433640
Status: NEW → RESOLVED
Closed: 6 years ago
Flags: in-testsuite?
Resolution: --- → FIXED
Target Milestone: --- → mozilla32
Status: RESOLVED → VERIFIED
JSBugMon: This bug has been automatically verified fixed.
Blocks: 1017154
Group: javascript-core-security
Group: core-security
You need to log in before you can comment on or make changes to this bug.