Closed Bug 312871 Opened 19 years ago Closed 19 years ago

Content can access XBL compilation scope by using xbl.method.valueOf.call() or xbl.method.valueOf.apply()

Categories

(Core :: Security, defect, P2)

x86
Windows XP
defect

Tracking

()

VERIFIED FIXED
mozilla1.8rc1

People

(Reporter: moz_bug_r_a4, Assigned: mrbkap)

Details

(Keywords: fixed1.7.13, fixed1.8, Whiteboard: [sg:critical])

Attachments

(3 files, 2 obsolete files)

User-Agent:       Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.12) Gecko/20050915
Build Identifier: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9a1) Gecko/20051017 Firefox/1.6a1

Content can access XBL compilation scope by using xbl.method.valueOf.call() or 
xbl.method.valueOf.apply(). And can create a privileged function by using 
Function constructor in the XBL compilation scope.

trunk 20051017 and fx 1.0.7 and suite 1.7.12 are vulnerable.


<marquee id="m">marquee</marquee>
m = document.getElementById("m");
x = m.init.valueOf.call(null); // or .apply(null)
y = m.init.valueOf.call(); // or .apply()

On trunk:
x is: [object nsXBLPrototypeScript compilation scope]
y is: [object nsXBLPrototypeScript compilation scope]

On 1.0.x:
x is: [object nsXBLPrototypeScript compilation scope]
y is: [object Object]

x.Function can be used to create a privileged function, on trunk and 1.0.x.


When m.init.valueOf.call is called, m.init.valueOf's parent chain is used to 
find an object that should be used as |this| object, if |this| parameter is not
passed, or |this| parameter is null or undefined.

m.init.valueOf.__parent__ is:
  [object Object]
m.init.valueOf.__parent__.__parent__ is:
  [object nsXBLPrototypeScript compilation scope]


On trunk and 1.0.x:
m.init.valueOf.call(null) returns m.init.valueOf.__parent__.__parent__

http://lxr.mozilla.org/mozilla/source/js/src/jsinterp.c#461
461 js_ComputeThis(JSContext *cx, JSObject *thisp, JSStackFrame *fp)
  ...
492         if (JSVAL_IS_PRIMITIVE(fp->argv[-2]) ||
493             !(parent = OBJ_GET_PARENT(cx, JSVAL_TO_OBJECT(fp->argv[-2])))) {
494             thisp = cx->globalObject;
495         } else {
496             /* walk up to find the top-level object */
497             thisp = parent;
498             while ((parent = OBJ_GET_PARENT(cx, thisp)) != NULL)
499                 thisp = parent;
500         }


On trunk:
m.init.valueOf.call() returns m.init.valueOf.__parent__.__parent__

http://lxr.mozilla.org/mozilla/source/js/src/jsfun.c#1456
1456 fun_call(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
  ...
1477     if (argc == 0) {
1478         /* Call fun with its global object as the 'this' param if no args. */
1479         while ((tmp = OBJ_GET_PARENT(cx, obj)) != NULL)
1480             obj = tmp;
1481     } else {


On 1.0.x:
m.init.valueOf.call() returns m.init.valueOf.__parent__

http://lxr.mozilla.org/aviary101branch/source/js/src/jsfun.c#1437
1437 fun_call(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
  ...
1457     if (argc == 0) {
1458         /* Call fun with its parent as the 'this' parameter if no args. */
1459         obj = OBJ_GET_PARENT(cx, obj);
1460     } else {


Reproducible: Always

Steps to Reproduce:
Status: UNCONFIRMED → NEW
Ever confirmed: true
js_ComputeThis is low-level, it should not do any access checks.  On the other
hand, something has to, and fun_call and fun_apply, at least, need to.

The capability model in Gecko does not support mixing JS objects from different
trust domains, so we need to check for other paths up the parent chain that
might be troublesome.

/be
(In reply to comment #3)
> The capability model in Gecko does not support mixing JS objects from different
> trust domains

within a single window-like container, I mean.

/be
Flags: blocking1.8rc1+
Flags: blocking1.7.13+
Flags: blocking-aviary1.0.8+
Whiteboard: [sg:critical]
I get to take this one. The plan is to make the XBL compilation scope do
security checks on gets and sets.
Assignee: dveditz → mrbkap
Priority: -- → P2
Target Milestone: --- → mozilla1.8rc1
Status: NEW → ASSIGNED
> The capability model in Gecko does not support mixing JS objects from different
> trust domains

I'm not sure I follow this statement.  If I do foo.prop = bar where foo and bar
are objects from different trust domains, nothing stops me (assuming I have
enough privileges to access both trust domains).
(In reply to comment #6)
> > The capability model in Gecko does not support mixing JS objects from different
> > trust domains
> 
> I'm not sure I follow this statement.  If I do foo.prop = bar where foo and bar
> are objects from different trust domains, nothing stops me (assuming I have
> enough privileges to access both trust domains).

My statement was incomplete, sorry.  If you have UniversalBrowserRead or similar
capability, you can have your way.  That's not what concerns us here, or in
other bugs to-do with same-origin or chrome/content violations.

The problem I'm talking about needs to be formally stated, and I'm working on
the language to do that.  The essence is that we check access mainly in
window-like object getProperty and setProperty hooks, and not deeper in the DOM
or JS object trees connected to a given window.

Thus, windows are articulation points in the object graph a given script may
construct, and while evil.org may load in window A, open window B, load
victim.com in it, and try to access B's DOM or JS objects, the access checks at
the window layer stop evil.org.

There are other checks needed besides these articulation point checks, but with
XBL, we were missing these.

I wrote that the existing capability model doesn't cope with mixed trust to mean
that we go up the JS-lexical and DOM scope chains (same linkage for
SpiderMonkey) to find trust labels associated with windows.  We don't label
individual data items.

So we don't check access in the middle of a sub-graph, nor do we have the
discrete labels to do that with disconnected sub-graphs.  These are helpful
optimizations, or were.  We might evolve toward a system that labels everything
(and taints flow of control, etc., to handle timing channels).  But given where
we are, and how XBL works, we need at least this bug's fix, which was suggested
by the above thinking.

Ask me anything!

/be
Attached patch potential patch (obsolete) — Splinter Review
I still need to make sure this doesn't break XBL bindings accessing their own
code (especially user XBL bindings), but this does fix the testcase in this
bug.
Attached patch fixing some style nits (obsolete) — Splinter Review
I'm still not sure this isn't totally breaking the world (marquee still works
though!).
Attachment #199994 - Attachment is obsolete: true
Attachment #200006 - Flags: superreview?(brendan)
Attachment #200006 - Flags: review?(bzbarsky)
Comment on attachment 200006 [details] [diff] [review]
fixing some style nits

>Index: content/xbl/src/nsXBLDocumentInfo.cpp
>+  nsIScriptSecurityManager *GetSecurityManager()
>+  {

Is there a reason this is not using nsContentUtils::SecurityManager() ?  I bet
it should.

>+doCheckAccess(JSContext *cx, JSObject *obj, jsval id, PRUint32 
>+  if (!ssm) {
>+    NS_WARNING("Unable to get the script security manager");
>+    return JS_TRUE;

I'd prefer JS_FALSE, I think...  ssm might be null during shutdown; will that
break anyone?

>+  nsresult rv = ssm->CheckPropertyAccess(cx, obj, ::JS_GetClass(cx, obj)->name,

Hmm... Will that give the same classname as classinfo does for objects with
classinfo?  If not, should we be passing null instead, perhaps (so that the
security manager looks up the classname in classinfo)?
(In reply to comment #10)
> Is there a reason this is not using nsContentUtils::SecurityManager() ?  I bet
> it should.

I could have sworn I looked for SecurityManager, bug didn't find it. That makes
things simpler.

> I'd prefer JS_FALSE, I think...  ssm might be null during shutdown; will that
> break anyone?

I don't think we should be running any web page (untrusted) content during
shutdown. I think the only XBL we should be running here would be either browser
or extension XBL, but I'll make this change if you feel strongly about it.

> Hmm... Will that give the same classname as classinfo does for objects with
> classinfo?  If not, should we be passing null instead, perhaps (so that the
> security manager looks up the classname in classinfo)?

Except that we can only ever get into this function when we're doing a lookup on
the actual global object (with this particular class), I think. If we're looking
up a property on another object that actually has classinfo, then we'll do the
resolution in XPConnect (maybe through native wrappers).
Attachment #200006 - Attachment is obsolete: true
Attachment #200022 - Flags: superreview?(brendan)
Attachment #200022 - Flags: review?(bzbarsky)
Attachment #200006 - Flags: superreview?(brendan)
Attachment #200006 - Flags: review?(bzbarsky)
Attachment #200022 - Flags: review?(bzbarsky) → review+
Comment on attachment 200022 [details] [diff] [review]
updated to comments

> JSClass nsXBLDocGlobalObject::gSharedGlobalClass = {
>     "nsXBLPrototypeScript compilation scope",
>     JSCLASS_HAS_PRIVATE | JSCLASS_PRIVATE_IS_NSISUPPORTS,
>-    JS_PropertyStub,  JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
>-    JS_EnumerateStub, nsXBLDocGlobalObject_resolve,  JS_ConvertStub,
>-    nsXBLDocGlobalObject_finalize
>+    JS_PropertyStub,  JS_PropertyStub, nsXBLDocGlobalObject_getProperty,
>+    nsXBLDocGlobalObject_setProperty, JS_EnumerateStub,
>+    nsXBLDocGlobalObject_resolve,  JS_ConvertStub,
>+    nsXBLDocGlobalObject_finalize, NULL, nsXBLDocGlobalObject_checkAccess

Nit, maybe warning abatement on some compilers: organize the initializers into
two columns, eight rows, nulls for the trailing stuff (that supposedly
eliminates warnings, perhaps only for gcc -- what's the point of C initializers
if you can't leave stuff out and assume 0 static init!	I guess the idea is
that you forgot to include something; bleah).

sr=me, thanks for tackling this.

/be
Attachment #200022 - Flags: superreview?(brendan)
Attachment #200022 - Flags: superreview+
Attachment #200022 - Flags: approval1.8rc1?
can we get this landed and verified on the trunk today so that we can properly
evaluate for the branch?
Fix checked into trunk.
Status: ASSIGNED → RESOLVED
Closed: 19 years ago
Resolution: --- → FIXED
who can verify this on today's trunk build? 
Asa: you can, with the attached testcase.

/be
Verified on trunk. Note: second testcase still shows nsXBLPrototypeScript
compilation scope, the fix as demonstrated in the first testcase is that we
don't let people use the object.
Status: RESOLVED → VERIFIED
Attachment #200022 - Flags: approval1.8rc1? → approval1.8rc1+
Fix checked into MOZILLA_1_8_BRANCH.
Keywords: fixed1.8
Flags: testcase+
Comment on attachment 200022 [details] [diff] [review]
updated to comments

aviary101/moz17 landing approval: a=dveditz for drivers. Please add the fixed1.7.13 and fixed-aviary1.0.8 keywords when landed.
Attachment #200022 - Flags: approval1.7.13+
Attachment #200022 - Flags: approval-aviary1.0.8+
This is now fixed on the 1.7 branches (see my comment in bug 313236).
v.fixed on 1.0.1 Aviary branch with Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.13) Gecko/20060213 Firefox/1.0.8, saw the same results as dveditz did in comment #18 using the testcases.
Group: security
Flags: in-testsuite+ → in-testsuite?
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Creator:
Created:
Updated:
Size: