Closed Bug 47354 Opened 24 years ago Closed 24 years ago

capabilities settings don't obey lexical closure of JS funcs

Categories

(Core :: Security: CAPS, defect, P3)

x86
Linux
defect

Tracking

()

VERIFIED FIXED

People

(Reporter: dmosedale, Assigned: shaver)

Details

Attachments

(2 files)

I have a JS component that is creating an anonymous JS function object, binding it to some data with a closure, and handing it to a C++ object as a callback. The JS component itself can call dangerous functions such as dump(), but the anonymous callback cannot; it gets an exception: "Access to XPConnect service denied. [nsILDAPMessageListener::onLDAPMessage]" nsresult: "0x8057001e (NS_ERROR_XPC_JS_THREW_STRING)" It seems like this ought to just work. For what it's worth, even if I do add an n.s.P.enablePrivilege() call at the indicated spot in the code below, it fails with the exact same error as in bug 35116 ("ReferenceError: netscape is not defined"). However, no amount of restarting works around that error, despite the description in 35116. The code: function boundCallback() {} boundCallback.prototype = { onLDAPMessage: {} } function GetTargets () { function generateBoundCallback() { cb = new boundCallback(); cb.onLDAPMessage = function() { // enablePrivilege here if (DEBUG) { dump("boundCallback() called with scope: \n\t" + aSource.Value + "\n\t" + aProperty.Value + "\n\t" + aTruthValue + "\n\n"); } } return cb; } this.getConnection(url.host, url.port, generateBoundCallback()); return; }
This looks like 39975, for which I don't have an accessible patch (the machine with my Mozilla hackery is at home, sans internet). (If this is really a dup of 39975, someone else should probably take it, too.)
Note that there is no security check for 'dump'. The property accesses are what is probably failing. I don't know about whether the principles ought to get conveyed to the new closure function. In the cases where privileges come from an explicit call to the security manager then they certainly should not get conveyed. But in this case of priniciples that came with the original JSComponent I'm out of my depth. The bug 35116 part is bad. The netscape.security.* stuff to *too* entertwined with the DOM JSContexts. I don't have a solution.
Naive question: why shouldn't they be conveyed to the closure function even in the case of privs that come from an explicit call to the security managemer?
Looks like there are two issues here, which should probably be filed as separate bugs. JS components should have the system principal, so they shouldn't even have to call enablePrivilege in order to use XPConnect. As to why we aren't getting the system principal in this case, I'm not sure. The "netscape is not defined" issue is separate, I think. Dan, could you show me how to reproduce this bug, or maybe I could sit down and look it over with you? How important is this, is it nsbeta3?
Status: NEW → ASSIGNED
Target Milestone: --- → M18
Mitch: I think 35516 and 39975 may be the two bugs in question, or at least something like them. shaver is actually in the middle of consing up a patch for me, so maybe the right thing to do is reassign to him.
OK, I think I nailed it. In the patch I will attach below, I put a system-principal-having object at the top of every JS component's scope chain, where it can keep nsScriptSecurityManager happy. I had to alter nsScriptSecurityManager::GetObjectPrincipal to handle the case where the nsISupports private data was a wrapped native, because the nsXPCWrappedNative doesn't pass QI through to the native it's wrapping. I think that's correct, and I'm pretty sure it's safe. jband: I turned out to not need the InitClassesWithWrappedNative thing, so it doesn't appear in the patch.
Assignee: mstoltz → shaver
Status: ASSIGNED → NEW
shaver's patches works great for me, with a slightly different test case: the current tip of directory/xpcom/datasource/nsLDAPDataSource.js, which is what I actually care about.
Looks alright to me, but I want to hear jband's take on any possible security implications of this change. Can you hold off checking it in until we hear from jband?
I'd really like to get it in before it rots, and I can't imagine how there are security implications here -- an attacker who can put a wrapped object with access to a system principal in place on the scope chain would seem to already be able to subvert the current system -- but I can wait for jband to point out what I'm missing.
Status: NEW → ASSIGNED
A few things biug and small... - the lines *aPrincipal = mPrincipal; NS_ADDREF(*aPrincipal); ...can be... NS_ADDREF(*aPrincipal = mPrincipal); This saves a pointer deref. - You ended up with 2 JS_InitStandardClasses... blocks. The second one is unnecessary, no? - not having your initializers for memeber in the same order as declared in mozJSComponentLoader will give a warning. When initizilers depend on each other then this can be bad. - You end up with only one shred Components object. This should be OK. It does mean that any natives reflected into more than one one global space will be reflected using the same wrapper in each. At some future point when the __proto__ of the wrapper is of interest this could be bad. We can worry about that later I think. - securitywise... I don't see any new holes or anything. I'd rather see this code try to QI to nsIScriptObjectPrincipal first and then only try to QI to nsIXPConnectWrappedNative if the former fails. This allows more flexibility as the DOM stuff moves to use xpconnect. no? This also puts the more likely case first and avoids an extra QI for DOM stuff.
I'll tidy up the first 2 stat, thanks. I don't see the out-of-order initializers, though I think I can just remove the #ifdef'd init for mSystemPrincipal: nsCOMPtrs get initialized implicitly to nsnull, right? Didn't I always have a single shared Components object in the super-global? 323 rv = mXPC->InitClasses(mContext, mSuperGlobal); Conceptually, I think of the WrappedNative thing being a wrapper that we should remove before testing the characteristics of the object, but your DOM-performance argument compels. I'll fix. New patch coming shortly.
A security issues to consider... With the double-wrapping stuff a JS user of a JS Component can ask for the underlying JSObject using 'wrappedJSObject'. If the caller has UniversalXPConnect and the callee implemented wrappedJSObject then the underlying object is exposed. The if the callee then reparents some code then that code gets system princpals. Right? Is this bad? Any more powerful then just having UniversalXPConnect?
Hmm. I have another concern here: I now end up with the super-global in the scope chain, which is not what I want. jband, is it safe to do something like this to the JSObject for the wrapped native? JS_SetParent(cx, obj, nsnull); JS_SetPrototype(cx, obj, mSuperGlobal); ?
Firstly, I don't think you can reparent code; __parent__ setting went the way of obj.eval a little while back, for security reasons. And then, if you already have UniversalXPConnect, you're out of the box. It might be more of a concern once we get partial-XPConnect privileges, because they too could reach the magic privilege object via __parent__ walking from a wrappedJSObject, but any partial-XPConnect priv system will have to deal with containing that sort of access bleed -- just making wrappedJSObject require UniversalXPConnect might be enough.
Am I seeing things, or does the patch mix nsnull with valid nsresult values in return statements: return NS_ERROR_OUT_OF_MEMORY; + +#ifndef XPCONNECT_STANDALONE + NS_WITH_SERVICE(nsIScriptSecurityManager, secman, + NS_SCRIPTSECURITYMANAGER_PROGID, &rv); + if(NS_FAILED(rv) || !secman) + return nsnull; + + rv = secman->GetSystemPrincipal(getter_AddRefs(mSystemPrincipal)); + if(NS_FAILED(rv) || !mSystemPrincipal) + return nsnull; +#endif - mSuperGlobal = JS_NewObject(mContext, &gGlobalClass, NULL, NULL); + mSuperGlobal = JS_NewObject(mContext, &gGlobalClass, nsnull, nsnull); + if (!mSuperGlobal) - return NS_ERROR_OUT_OF_MEMORY; + return nsnull; /be
We do have a partial-XPConnect privilege system, nsISecurityCheckedComponent. John, could the exploit that Shaver's describing work with a SecurityCheckedComponent object? What if we assume you can reassign __parent__?
Brendan: how embarrassing. Fixed in my tree, patch awaiting jband input on the proto/parent frob of the wrapped object.
If you can reassign __parent__, I think the jig is generally up for us, no?
Allowing assignment to __parent__ would wreak havoc with all scope-based security checks, along with optimizations based on static analysis by compilers. We don't allow it, so don't worry about it. /be
shaver: yes you can change parent and proto of wrappers via the jsapi. At some future point xpconnect is going to manage shared protos for all wrappers around a given class (CLSID) within a give scope. At that point this will matter and we can revisit. bug 13425 mstoltz: I don't know that I'd call nsISecurityCheckedComponent a "partial-XPConnect privilege system". I think it is more of a "distribution of responsibility for security system". As far as I can see, the impact here is that it allows a JS Component to give away that system principal to any caller even if the caller does not have UniversalXPConnect. But that is the nature of the distributed security system - it just allows more code to do something wrong. I don't think the synergy here makes things especially less safe. I didn't realize that obj.eval was fully gone and that there was no way to sneek into a parent chain. Good.
jband: obj.eval(s) is still with us, but it is equivalent to with(obj)eval(s). /be
shaver: I forgot to mention that I don't think it's kosher to trim out IBM's copyright notice. Is it?
mkaply said that when modifying IBM-splattered files, it was OK to normalize them to simply indicate their contributorship. (IBM puts that stuff there because they believe the license requires them to -- and it's not an unreasonable interpretation -- not because they really care about having that text in place, I believe.) At an absolute minimum, it needs to be more respectful of the 80th column. I'll put up the new patch, seeking r and a.
r=jband I can't see anything wrong with it. It compiles without warnings on NT and seems to run and work. You're running testcases that shows this fixes the bug?
The latest patch works for on the tip of nsLDAPDataSource.js.
a=brendan@mozilla.org modulo whitespace whining. /be
Yeah, dmose and I have verified that it gives privileges to his LDAP closures, and stuff, and stepping around with the debugger I can see where it gets called to check the principal. Going in! Thanks, all!
Status: ASSIGNED → RESOLVED
Closed: 24 years ago
QA Contact: czhang → junruh
Verified per shaver@mozilla.org's comments.
Status: RESOLVED → VERIFIED
mid-air collision ? / bugzilla cleanup Reopening (current State: verified and no resolution)
Status: VERIFIED → REOPENED
fixed
Status: REOPENED → RESOLVED
Closed: 24 years ago24 years ago
Resolution: --- → FIXED
and verfied....
Status: RESOLVED → VERIFIED
This patch adds the code: + nsCOMPtr<nsIScriptObjectPrincipal> backstagePass = + new BackstagePass(mSystemPrincipal); and if one just starts a browser with XPCOM_MEM_BLOAT_LOG and closes it, it will show a leak of a BackstagePass. Is it certain that this doesn't leak? (It is the only file that allocates BackstagePasses according to lxr).
There's a well-known leak that entrains the backstage pass, but this bug's fix did not introduce that leak. Cc'ing stephend and dbaron. /be
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: