Closed Bug 566141 Opened 14 years ago Closed 14 years ago

GC hazard in MarkSharpObjects

Categories

(Core :: JavaScript Engine, defect)

Other Branch
defect
Not set
normal

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][critsmash:investigating] fixed-in-tracemonkey)

Attachments

(5 files)

Consider the following code in MarkSharpObject, http://hg.mozilla.org/tracemonkey/file/818656d6f1e4/js/src/jsobj.cpp#l276 :

            ok = obj->lookupProperty(cx, id, &obj2, &prop);
...
            ok = obj2->getAttributes(cx, id, prop, &attrs);
            if (ok) {
                if (obj2->isNative() &&
                    (attrs & (JSPROP_GETTER | JSPROP_SETTER))) {
                    JSScopeProperty *sprop = (JSScopeProperty *) prop;
                    val = JSVAL_VOID;
                    if (attrs & JSPROP_GETTER)
                        val = sprop->getterValue();
                    if (attrs & JSPROP_SETTER) {
                        if (val != JSVAL_VOID) {
                            /* Mark the getter, then set val to setter. */
                            ok = (MarkSharpObjects(cx, JSVAL_TO_OBJECT(val),
                                                   NULL)
                                  != NULL);
                        }
...
            }
            obj2->dropProperty(cx, prop);

This code has a bug as it can start a long-running operation between lookupProperty and dropProperty calls due to a recursion in MarkSharpObjects. Without the proposed changes from the bug 546590 this can only hurt embeddings that share objects between threads as it may nests locks itc. For the browser this is harmless as lookupProperty/getAttributes at worst can run a resolve hook and their implementation in the browser do not run arbitrary code.

But proxies chnage that. Now lookupProperty can run an arbitrary script. Thus if MarkSharpObjects for the setter discovers a proxy, it could run a script that can delete the property under lookup and its scope. That would lead to a hazard.
Whiteboard: [sg:critical?]
This is not currently a bug. The code in question hasn't been landed yet. Also, we are eliminating shared objects. So critical is absolutely overstating this.
Whiteboard: [sg:critical?] → [sg:investigate?]
"we are eliminating shared objects"? You mean eliminating JSProperty * from the JSObjectOps hooks?

/be
Group: core-security
Whiteboard: [sg:investigate?]
We are eliminating sharing native objects across threads.
gal, we don't use [sg:investigate] anymore. Better to just leave it blank (and the bug security-sensitive) if you're not sure.
The proxy code would expose another problem in MarkSharpObjects. There the function does not root the id array it receives from JS_Enumerate. With a proxy it would be trivial to wright a script that in lookupProperty unroots and GC-collects an id stored in the array before they are used. 

Note that this is not a problem with a proxy as a similar issue may exists if a resolve hook could be triggered to run a script.
Group: core-security
One do not need a proxy to exploit this. When working over the object tree MarkSharpObjects may call getProperty on non-native object. But that can run an arbitrary script via, for example, a getter on a native prototype of a non-native fast array.
Summary: New proxy code would expose a hazard in MarkSharpObjects → GC hazard in MarkSharpObjects
(In reply to comment #5)
> The proxy code would expose another problem in MarkSharpObjects. There the
> function does not root the id array it receives from JS_Enumerate. With a proxy
> it would be trivial to wright a script that in lookupProperty unroots and
> GC-collects an id stored in the array before they are used. 

Sorry, the id itself is safe thanks to the JS_KEEP_ATOMS call. What is the problem is sprop itself. A script invoked when MarkSharpObjects is called to mark the getter can remove the property and force the GC so sprop would be deleted before it is used to access the setter. Another possibility is to GC obj2 after obj___proto__ = NULL before it is used in the dropProperty call.

But I will create a test script before doing any father work.
(In reply to comment #7)
> But I will create a test script before doing any father work.

My attempt to create a test case has revealed that one needs a power of proxy to exploit this. Without proxy JS_Enumerate for non-native objects returns ids that would never trigger any script hooks. Thus it is not possible to exploit the bug with getter defined on Array.prototype.
Igor, so would you say this is not sg:critical based on Comment 8 ?
Whiteboard: [sg:critical?][critsmash:investigating]
(In reply to comment #8)
> My attempt to create a test case has revealed that one needs a power of proxy
> to exploit this. Without proxy JS_Enumerate for non-native objects returns ids
> that would never trigger any script hooks. Thus it is not possible to exploit
> the bug with getter defined on Array.prototype.

On 1.9.2 and before one can use liveconnect and create a Java applet with a some Java getter that will be invoked during id iteration loop in MarkSharpObject. That in turn can recurse into JavaScript world and do the damage AFAICS. So the bug is not critical only TM/mozilla-central tips where LiveConnect is switched off but the proxy code is not yet landed.
(In reply to comment #10)
> Igor, so would you say this is not sg:critical based on Comment 8 ?

I would not say for sure yet (I will need to refresh my memories about LiveConnect and create an example for a proof), but it does look like sg:critical.
Who should own this?  Need an owner here.

Thanks a bunch, Igor.
Whiteboard: [sg:critical?][critsmash:investigating] → [sg:critical][critsmash:investigating]
Proxies are about to land, so this needs a fix. Igor, can you take this? You know the code a lot better than me. Otherwise I take it.
Assignee: general → igor
Blocking 1.9.3 final as it's an sg:crit.
blocking2.0: --- → final+
Blocks: 566818
No longer blocks: 566818
Attached patch v1Splinter Review
This is what I am testing
Attachment #446189 - Flags: review?(brendan)
Here is test case that is based on the new Proxy code:

var proxy = Proxy.create({
      enumerateOwn: function() {
            delete x.property_that_can_be_deleted;
            gc();
            return [];
        }
    });

function f() { print("function f");}
f.proxy = proxy;

var x = {};
x.__defineGetter__("property_that_can_be_deleted", f);
x.__defineSetter__("property_that_can_be_deleted", f);
uneval(x);

The test case crashes/asserts when MarkSharpObjects tries to access a setter value for the deleted property.
brendan: review ping
Comment on attachment 446189 [details] [diff] [review]
v1

Maybe invert !isNative test to put best foot forward in prefetched-is-predicted sense. r=me otherwise.

/be
Attachment #446189 - Flags: review?(brendan) → review+
http://hg.mozilla.org/tracemonkey/rev/54acf298872b - with the inverted isNative test.
fixed in tracemonkey?
Whiteboard: [sg:critical][critsmash:investigating] → [sg:critical][critsmash:investigating] fixed-in-tracemonkey
(In reply to comment #21)
> fixed in tracemonkey?

yes
http://hg.mozilla.org/mozilla-central/rev/54acf298872b
Status: NEW → RESOLVED
Closed: 14 years ago
Resolution: --- → FIXED
Depends on: 568485
This bug should be a blocker on branches. AFAICS with liveconnect one can build an exploit here.
blocking1.9.1: --- → ?
blocking1.9.2: --- → ?
Attached patch fix for 192Splinter Review
192 backport follows the logic of TM patch adjusted for older internal API.
Attachment #465981 - Flags: review?(gal)
Attachment #465981 - Flags: review?(gal) → review+
Attached patch fix for 191Splinter Review
191 needs a separated fix to account for OBJ_LOOKUP_PROPERTY change on later
branches.
Attachment #466243 - Flags: review+
Attachment #466243 - Flags: approval1.9.1.13?
Attachment #466243 - Attachment description: fi for 191 → fix for 191
Blocking for the next set of branch releases, the current ones are in (slushy) code-freeze as we try to wrap up.
blocking1.9.1: ? → .13+
blocking1.9.2: ? → .10+
(In reply to comment #28)
> Blocking for the next set of branch releases, the current ones are in (slushy)
> code-freeze as we try to wrap up.

It is important not to open the bug 568465 until this and a related bug 568073 is fixed. Otherwise one can get a strong hit how to look for the problem. 

How do we note such open-together dependency?
Comment on attachment 466243 [details] [diff] [review]
fix for 191

Approved for 1.9.1.13, a=dveditz for release-drivers

Is the other patch ready for 1.9.2 approval, or was there a reason you didn't request it?
Attachment #466243 - Flags: approval1.9.1.13? → approval1.9.1.13+
Attachment #465981 - Flags: approval1.9.2.10?
Comment on attachment 465981 [details] [diff] [review]
fix for 192

Approved for 1.9.2.10, a=dveditz for release-drivers
Attachment #465981 - Flags: approval1.9.2.10? → approval1.9.2.10+
Attachment #481169 - Flags: review?(igor) → review+
Group: core-security
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Creator:
Created:
Updated:
Size: