Mozilla Home
Privacy
Cookies
Legal
Bugzilla
Browse
Advanced Search
New Bug
Reports
Documentation
Log In
Log In with GitHub
or
Remember me
Browse
Advanced Search
New Bug
Reports
Documentation
Attachment 492083 Details for
Bug 605271
[patch]
Stop untrusted script from QIing to non-ClassInfo interfaces
605271 (text/plain), 25.72 KB, created by
Kyle Huey (Exited; not receiving bugmail, old account, do not use)
(
hide
)
Description:
Stop untrusted script from QIing to non-ClassInfo interfaces
Filename:
MIME Type:
Creator:
Kyle Huey (Exited; not receiving bugmail, old account, do not use)
Size:
25.72 KB
patch
obsolete
># HG changeset patch ># User Kyle Huey <khuey@kylehuey.com> ># Date 1290285663 18000 ># Node ID 46aae924fafbebf4a216573b9d9f213c53e11b3b ># Parent 5c6fa4a5c3da3251baa57efe71eb4423b92aeb29 >Bug 605271: Stop untrusted script from QIing to non-ClassInfo interfaces > >diff --git a/content/base/src/nsGenericElement.cpp b/content/base/src/nsGenericElement.cpp >--- a/content/base/src/nsGenericElement.cpp >+++ b/content/base/src/nsGenericElement.cpp >@@ -4490,6 +4490,22 @@ > nsIContent, > nsNodeUtils::LastRelease(this)) > >+PRBool >+nsGenericElement::ImplementsXBLIface(REFNSIID aIID) >+{ >+ nsIDocument *document = GetOwnerDoc(); >+ if (!document) { >+ return PR_FALSE; >+ } >+ >+ nsXBLBinding *binding = document->BindingManager()->GetBinding(this); >+ if (!binding) { >+ return PR_FALSE; >+ } >+ >+ return binding->ImplementsInterface(aIID); >+} >+ > nsresult > nsGenericElement::PostQueryInterface(REFNSIID aIID, void** aInstancePtr) > { >diff --git a/content/base/src/nsGenericElement.h b/content/base/src/nsGenericElement.h >--- a/content/base/src/nsGenericElement.h >+++ b/content/base/src/nsGenericElement.h >@@ -337,6 +337,7 @@ > * get an interface for this element. > */ > nsresult PostQueryInterface(REFNSIID aIID, void** aInstancePtr); >+ PRBool ImplementsXBLIface(REFNSIID aIID); > > // nsINode interface methods > virtual PRUint32 GetChildCount() const; >diff --git a/content/base/test/test_bug166235.html b/content/base/test/test_bug166235.html >--- a/content/base/test/test_bug166235.html >+++ b/content/base/test/test_bug166235.html >@@ -67,6 +67,8 @@ > function testPasteText(expected, test) { > textarea.value=""; > textarea.focus(); >+ // To QI to non-ClassInfo interfaces we must assert privileges >+ netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect'); > textarea.QueryInterface(Components.interfaces.nsIDOMNSEditableElement) > .editor.paste(1); > is(textarea.value, expected, test + ": textarea paste"); >diff --git a/content/base/test/test_copypaste.html b/content/base/test/test_copypaste.html >--- a/content/base/test/test_copypaste.html >+++ b/content/base/test/test_copypaste.html >@@ -104,6 +104,8 @@ > function testPasteText(expected) { > textarea.value=""; > textarea.focus(); >+ // To QI to non-ClassInfo interfaces we must assert privileges >+ netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect'); > textarea.QueryInterface(Components.interfaces.nsIDOMNSEditableElement) > .editor.paste(1); > is(textarea.value, expected, "value of the textarea after the paste"); >diff --git a/content/html/content/test/Makefile.in b/content/html/content/test/Makefile.in >--- a/content/html/content/test/Makefile.in >+++ b/content/html/content/test/Makefile.in >@@ -241,6 +241,7 @@ > test_bug607145.html \ > test_bug601061.html \ > test_bug596511.html \ >+ test_bug605271.html \ > reflect.js \ > $(NULL) > >diff --git a/content/html/content/test/test_bug388558.html b/content/html/content/test/test_bug388558.html >--- a/content/html/content/test/test_bug388558.html >+++ b/content/html/content/test/test_bug388558.html >@@ -24,7 +24,8 @@ > var textareaChange = 0; > > function testUserInput() { >- netscape.security.PrivilegeManager.enablePrivilege('UniversalBrowserWrite'); >+ // To QI to non-ClassInfo interfaces we must assert privileges >+ netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect'); > var input = document.getElementById("input"); > var textarea = document.getElementById("textarea"); > >diff --git a/content/html/content/test/test_bug389797.html b/content/html/content/test/test_bug389797.html >--- a/content/html/content/test/test_bug389797.html >+++ b/content/html/content/test/test_bug389797.html >@@ -23,6 +23,7 @@ > var classInfos = {}; > var interfaces = {}; > var interfacesNonClassinfo = {}; >+var interfacesNonDOM = {}; > > netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); > var prefs = Components.classes["@mozilla.org/preferences-service;1"] >@@ -45,11 +46,16 @@ > "nsIDOMNodeSelector" ]; > > // Some interfaces don't appear in classinfo because other interfaces that >- // inherit from them do. >+ // inherit from them do. These are visible to unprivileged script. > interfacesNonClassinfo[aTagName] = > [ "nsIDOMNode", >- "nsIDOMElement", >- "nsIDOM3EventTarget", >+ "nsIDOMElement"]; >+ >+ // Some interfaces don't appear in classinfo because they are implementation >+ // details of the underlying XPCOM objects. These are not visible to >+ // unprivileged script. >+ interfacesNonDOM[aTagName] = >+ [ "nsIDOM3EventTarget", > "nsISupportsWeakReference" ]; > > var interfaceName = "nsIDOM" + getClassName(aTagName); >@@ -76,7 +82,7 @@ > > if (arguments.length > 3) { > for (i = 0; i < arguments[3].length; ++i) { >- interfacesNonClassinfo[aTagName].push(arguments[3][i]); >+ interfacesNonDOM[aTagName].push(arguments[3][i]); > } > } > } >@@ -247,6 +253,8 @@ > return "<" + aTag + ">"; > } > >+netscape.security.PrivilegeManager.revertPrivilege('UniversalXPConnect'); >+ > for each (var tag in allTags) { > var node = document.createElement(tag); > >@@ -272,8 +280,36 @@ > tagName(tag) + " does not QI to " + iface); > } > >+ // Check that each node doesn't QI to non-DOM things >+ for each (var iface in interfacesNonDOM[tag]) { >+ is(iface in Components.interfaces, true, >+ iface + " not in Components.interfaces"); >+ is(node instanceof Components.interfaces[iface], false, >+ tagName(tag) + " should not QI to " + iface); >+ } >+} >+ >+netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect'); >+for each (var tag in allTags) { >+ var node = document.createElement(tag); >+ >+ // Have to use the proto's toString(), since HTMLAnchorElement and company >+ // override toString(). >+ var nodeString = HTMLElement.prototype.toString.apply(node); >+ >+ // Debug builds have extra info, so chop off after "Element" if it's followed >+ // by ' ' or ']' >+ nodeString = nodeString.replace(/Element[\] ].*/, "Element"); >+ >+ // Check that each node doesn't QI to non-DOM things, except when we have privs >+ for each (var iface in interfacesNonDOM[tag]) { >+ is(iface in Components.interfaces, true, >+ iface + " not in Components.interfaces"); >+ is(node instanceof Components.interfaces[iface], true, >+ tagName(tag) + " should QI to " + iface + " from privileged script"); >+ } >+ > // Now see what classinfo reports >- netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); > var nodeClassInfo = node.QueryInterface(Components.interfaces.nsIClassInfo); > var count = {}; > var classInfoInterfaces = >@@ -294,6 +330,45 @@ > iface); > } > } >+ >+netscape.security.PrivilegeManager.revertPrivilege('UniversalXPConnect'); >+ >+// Finally, run all of the non privileged checks again to make sure that >+// tearoffs were not cached inappropriately. >+for each (var tag in allTags) { >+ var node = document.createElement(tag); >+ >+ // Have to use the proto's toString(), since HTMLAnchorElement and company >+ // override toString(). >+ var nodeString = HTMLElement.prototype.toString.apply(node); >+ >+ // Debug builds have extra info, so chop off after "Element" if it's followed >+ // by ' ' or ']' >+ nodeString = nodeString.replace(/Element[\] ].*/, "Element"); >+ >+ var classInfoString = getClassName(tag); >+ is(nodeString, "[object " + classInfoString, >+ "Unexpected classname for " + tagName(tag)); >+ is(node instanceof window[classInfoString], true, >+ tagName(tag) + " not an instance of " + classInfos[tag]); >+ >+ // Check that each node QIs to all the things we expect it to QI to >+ for each (var iface in interfaces[tag].concat(interfacesNonClassinfo[tag])) { >+ is(iface in Components.interfaces, true, >+ iface + " not in Components.interfaces"); >+ is(node instanceof Components.interfaces[iface], true, >+ tagName(tag) + " does not QI to " + iface); >+ } >+ >+ // Check that each node doesn't QI to non-DOM things >+ for each (var iface in interfacesNonDOM[tag]) { >+ is(iface in Components.interfaces, true, >+ iface + " not in Components.interfaces"); >+ is(node instanceof Components.interfaces[iface], false, >+ tagName(tag) + " should not QI to " + iface); >+ } >+} >+ > </script> > </pre> > </body> >diff --git a/content/html/content/test/test_bug605271.html b/content/html/content/test/test_bug605271.html >new file mode 100644 >--- /dev/null >+++ b/content/html/content/test/test_bug605271.html >@@ -0,0 +1,35 @@ >+<!DOCTYPE HTML> >+<html> >+<!-- >+https://bugzilla.mozilla.org/show_bug.cgi?id={BUGNUMBER} >+--> >+<head> >+ <title>Test for Bug {BUGNUMBER}</title> >+ <script type="text/javascript" src="/MochiKit/MochiKit.js"></script> >+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> >+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> >+</head> >+<body> >+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id={BUGNUMBER}">Mozilla Bug {BUGNUMBER}</a> >+<p id="display"></p> >+<div id="content" style="display: none"> >+ >+</div> >+<pre id="test"> >+<script class="testbody" type="text/javascript"> >+ >+/** Test for Bug {BUGNUMBER} **/ >+var elem = $("display"); >+netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect'); >+elem.QueryInterface(Components.interfaces.nsIDOM3EventTarget); >+elem.addGroupedEventListener; // force this to be resolved >+netscape.security.PrivilegeManager.revertPrivilege('UniversalXPConnect'); >+ok(!(elem instanceof Components.interfaces.nsIDOM3EventTarget), >+ "tearoff crossed privilege scope"); >+is(elem.addGroupedEventListener, undefined, "tearoff crossed privilege scope"); >+is(Object.keys(elem), "", "tearoff crossed privilege scope"); >+ >+</script> >+</pre> >+</body> >+</html> >diff --git a/dom/base/nsDOMClassInfo.cpp b/dom/base/nsDOMClassInfo.cpp >--- a/dom/base/nsDOMClassInfo.cpp >+++ b/dom/base/nsDOMClassInfo.cpp >@@ -533,6 +533,7 @@ > > #define ELEMENT_SCRIPTABLE_FLAGS \ > ((NODE_SCRIPTABLE_FLAGS & ~nsIXPCScriptable::CLASSINFO_INTERFACES_ONLY) | \ >+ nsIXPCScriptable::CLASSINFO_INTERFACES_ONLY_NOPRIVS | \ > nsIXPCScriptable::WANT_POSTCREATE | \ > nsIXPCScriptable::WANT_ENUMERATE) > >@@ -4730,6 +4731,13 @@ > &unused); > } > >+PRBool >+nsDOMClassInfo::ShouldReflectNonClassInfoIface(nsISupports* aObj, >+ REFNSIID aIID) >+{ >+ return PR_FALSE; >+} >+ > // static > nsIClassInfo * > NS_GetDOMClassInfoInstance(nsDOMClassInfoID aID) >@@ -7722,6 +7730,41 @@ > return PR_TRUE; > } > >+// If the prop is on this object (classinfo interfaces are on the proto) >+// and it isn't exposed through XBL, veto access to unprivileged callers. >+NS_IMETHODIMP >+nsElementSH::GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, >+ JSObject *obj, jsid id, jsval *vp, PRBool *_retval) >+{ >+ if (!wrapper) >+ return NS_OK; // Not interested in slim wrappers >+ >+ nsISupports* native = wrapper->Native(); >+ nsGenericElement *element = static_cast<nsGenericElement*>(native); >+ nsCOMPtr<nsIInterfaceInfo> iInfo; >+ nsresult rv = wrapper->FindInterfaceWithMember(id, getter_AddRefs(iInfo)); >+ NS_ENSURE_SUCCESS(rv, rv); >+ >+ if (!iInfo) >+ return NS_OK; >+ >+ const nsIID* iid; >+ rv = iInfo->GetIIDShared(&iid); >+ NS_ENSURE_SUCCESS(rv, rv); >+ >+ if (element->ImplementsXBLIface(*iid)) >+ return NS_OK; // Allow this to proceed >+ >+ // Otherwise, veto if appropriate >+ if (!nsContentUtils::IsCallerTrustedForCapability("UniversalXPConnect")) { >+ *vp = JSVAL_VOID; >+ *_retval = JS_TRUE; >+ return NS_SUCCESS_I_DID_SOMETHING; >+ } >+ >+ return nsNodeSH::GetProperty(wrapper, cx, obj, id, vp, _retval); >+} >+ > NS_IMETHODIMP > nsElementSH::PreCreate(nsISupports *nativeObj, JSContext *cx, > JSObject *globalObj, JSObject **parentObj) >@@ -7880,7 +7923,18 @@ > > return NS_OK; > } >- >+ >+PRBool >+nsElementSH::ShouldReflectNonClassInfoIface(nsISupports* aObj, REFNSIID aIID) >+{ >+ nsCOMPtr<Element> element = do_QueryInterface(aObj); >+ if (!element) { >+ return PR_FALSE; >+ } >+ >+ nsGenericElement* object = static_cast<nsGenericElement*>(element.get()); >+ return object->ImplementsXBLIface(aIID); >+} > > // Generic array scriptable helper. > >diff --git a/dom/base/nsDOMClassInfo.h b/dom/base/nsDOMClassInfo.h >--- a/dom/base/nsDOMClassInfo.h >+++ b/dom/base/nsDOMClassInfo.h >@@ -702,6 +702,11 @@ > JSObject *obj); > NS_IMETHOD Enumerate(nsIXPConnectWrappedNative *wrapper, JSContext *cx, > JSObject *obj, PRBool *_retval); >+ NS_IMETHOD GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, >+ JSObject *obj, jsid id, jsval *vp, PRBool *_retval); >+ >+ virtual PRBool ShouldReflectNonClassInfoIface(nsISupports *aObj, >+ REFNSIID aIID); > > static nsIClassInfo *doCreate(nsDOMClassInfoData* aData) > { >diff --git a/js/src/xpconnect/idl/nsIXPCScriptable.idl b/js/src/xpconnect/idl/nsIXPCScriptable.idl >--- a/js/src/xpconnect/idl/nsIXPCScriptable.idl >+++ b/js/src/xpconnect/idl/nsIXPCScriptable.idl >@@ -115,6 +115,9 @@ > const PRUint32 DONT_REFLECT_INTERFACE_NAMES = 1 << 27; > const PRUint32 WANT_EQUALITY = 1 << 28; > const PRUint32 WANT_OUTER_OBJECT = 1 << 29; >+ // Just like CLASSINFO_INTERFACES_ONLY, but code with >+ // UniversalXPConnect can QI through >+ const PRUInt32 CLASSINFO_INTERFACES_ONLY_NOPRIVS= 1 << 30; > > // The high order bit is RESERVED for consumers of these flags. > // No implementor of this interface should ever return flags >@@ -197,6 +200,10 @@ > in JSContextPtr cx, in JSObjectPtr obj); > > void postCreatePrototype(in JSContextPtr cx, in JSObjectPtr proto); >+ >+ >+ [notxpcom] PRBool ShouldReflectNonClassInfoIface(in nsISupports obj, >+ in nsIIDRef iid); > }; > > %{ C++ >@@ -204,8 +211,8 @@ > #include "nsAutoPtr.h" > > #define NS_XPCCLASSINFO_IID \ >-{ 0x9a5b0342, 0x0f70, 0x4d31, \ >- { 0xb7, 0xd7, 0x29, 0x68, 0xa5, 0x70, 0x4b, 0xd8 } } >+{ 0x56355458, 0x109f, 0x4148, \ >+ { 0xa9, 0x92, 0x98, 0x93, 0x3e, 0x28, 0xca, 0xa2 } } > > class NS_NO_VTABLE nsXPCClassInfo : public nsIClassInfo, > public nsIXPCScriptable >@@ -219,6 +226,12 @@ > virtual void PreserveWrapper(nsISupports *aNative) = 0; > > virtual PRUint32 GetInterfacesBitmap() = 0; >+ >+ virtual PRBool ShouldReflectNonClassInfoIface(nsISupports* aObj, >+ REFNSIID aIID) >+ { >+ return PR_FALSE; >+ } > }; > > NS_DEFINE_STATIC_IID_ACCESSOR(nsXPCClassInfo, NS_XPCCLASSINFO_IID) >diff --git a/js/src/xpconnect/idl/nsIXPConnect.idl b/js/src/xpconnect/idl/nsIXPConnect.idl >--- a/js/src/xpconnect/idl/nsIXPConnect.idl >+++ b/js/src/xpconnect/idl/nsIXPConnect.idl >@@ -81,6 +81,8 @@ > /***************************************************************************/ > #define GENERATE_XPC_FAILURE(x) \ > (NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_XPCONNECT,x)) >+#define GENERATE_XPC_SUCCESS(x) \ >+ (NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODULE_XPCONNECT,x)) > > #define NS_ERROR_XPC_NOT_ENOUGH_ARGS GENERATE_XPC_FAILURE( 1) > #define NS_ERROR_XPC_NEED_OUT_OBJECT GENERATE_XPC_FAILURE( 2) >@@ -136,6 +138,8 @@ > #define NS_ERROR_XPC_CANT_MODIFY_PROP_ON_WN GENERATE_XPC_FAILURE(52) > #define NS_ERROR_XPC_BAD_CONVERT_JS_ZERO_ISNOT_NULL GENERATE_XPC_FAILURE(53) > >+#define NS_SUCCESS_XPC_DONT_CACHE_TEAROFF GENERATE_XPC_SUCCESS( 1) >+ > #ifdef XPC_IDISPATCH_SUPPORT > // IDispatch support related errors > #define NS_ERROR_XPC_COM_UNKNOWN GENERATE_XPC_FAILURE(54) >diff --git a/js/src/xpconnect/public/xpc_map_end.h b/js/src/xpconnect/public/xpc_map_end.h >--- a/js/src/xpconnect/public/xpc_map_end.h >+++ b/js/src/xpconnect/public/xpc_map_end.h >@@ -56,6 +56,13 @@ > return NS_OK; > } > >+PRBool >+XPC_MAP_CLASSNAME::ShouldReflectNonClassInfoIface(nsISupports* aObj, >+ REFNSIID aIID) >+{ >+ return PR_FALSE; >+} >+ > /**************************************************************/ > > NS_IMETHODIMP XPC_MAP_CLASSNAME::GetScriptableFlags(PRUint32 *aFlags) >diff --git a/js/src/xpconnect/src/xpcinlines.h b/js/src/xpconnect/src/xpcinlines.h >--- a/js/src/xpconnect/src/xpcinlines.h >+++ b/js/src/xpconnect/src/xpcinlines.h >@@ -686,7 +686,8 @@ > inline JSBool > XPCWrappedNative::HasInterfaceNoQI(const nsIID& iid) > { >- return nsnull != GetSet()->FindInterfaceWithIID(iid); >+ XPCNativeInterface* iface = GetSet()->FindInterfaceWithIID(iid); >+ return nsnull != iface && !iface->IsUnsafe(); > } > > inline void >diff --git a/js/src/xpconnect/src/xpcprivate.h b/js/src/xpconnect/src/xpcprivate.h >--- a/js/src/xpconnect/src/xpcprivate.h >+++ b/js/src/xpconnect/src/xpcprivate.h >@@ -1749,12 +1749,18 @@ > void DebugDump(PRInt16 depth); > > #define XPC_NATIVE_IFACE_MARK_FLAG ((PRUint16)JS_BIT(15)) // only high bit of 16 is set >+#define XPC_NATIVE_IFACE_NOT_SAFE ((PRUint16)JS_BIT(14)) > > void Mark() {mMemberCount |= XPC_NATIVE_IFACE_MARK_FLAG;} > void Unmark() {mMemberCount &= ~XPC_NATIVE_IFACE_MARK_FLAG;} > JSBool IsMarked() const > {return 0 != (mMemberCount & XPC_NATIVE_IFACE_MARK_FLAG);} > >+ void MarkUnsafe() {mMemberCount |= XPC_NATIVE_IFACE_NOT_SAFE;} >+ void UnmarkUnsafe() {mMemberCount &= ~XPC_NATIVE_IFACE_NOT_SAFE;} >+ JSBool IsUnsafe() const >+ {return 0 != (mMemberCount & XPC_NATIVE_IFACE_NOT_SAFE);} >+ > // NOP. This is just here to make the AutoMarkingPtr code compile. > inline void TraceJS(JSTracer* trc) {} > inline void AutoTrace(JSTracer* trc) {} >@@ -1988,6 +1994,7 @@ > JSBool AllowPropModsToPrototype() GET_IT(ALLOW_PROP_MODS_TO_PROTOTYPE) > JSBool DontSharePrototype() GET_IT(DONT_SHARE_PROTOTYPE) > JSBool DontReflectInterfaceNames() GET_IT(DONT_REFLECT_INTERFACE_NAMES) >+ JSBool ClassInfoInterfacesOnlyNoPrivs() GET_IT(CLASSINFO_INTERFACES_ONLY_NOPRIVS) > > #undef GET_IT > }; >@@ -2087,6 +2094,11 @@ > > void Mark() {if(mShared) mShared->Mark();} > >+ PRBool ShouldReflectNonClassInfoIface(nsISupports* aObj, REFNSIID aIID) >+ { >+ return mCallback->ShouldReflectNonClassInfoIface(aObj, aIID); >+ } >+ > protected: > XPCNativeScriptableInfo(nsIXPCScriptable* scriptable = nsnull, > XPCNativeScriptableShared* shared = nsnull) >@@ -2368,7 +2380,8 @@ > void JSObjectFinalized() {SetJSObject(nsnull);} > > XPCWrappedNativeTearOff() >- : mInterface(nsnull), mNative(nsnull), mJSObject(nsnull) {} >+ : mInterface(nsnull), mNative(nsnull), mJSObject(nsnull), mUnsafe(PR_FALSE) >+ {} > ~XPCWrappedNativeTearOff(); > > // NOP. This is just here to make the AutoMarkingPtr code compile. >@@ -2379,6 +2392,9 @@ > void Unmark() {mJSObject = (JSObject*)(((jsword)mJSObject) & ~1);} > JSBool IsMarked() const {return (JSBool)(((jsword)mJSObject) & 1);} > >+ void MarkUnsafe() {mUnsafe = PR_TRUE;} >+ PRBool IsUnsafe() const {return mUnsafe;} >+ > #ifdef XPC_IDISPATCH_SUPPORT > enum JSObject_flags > { >@@ -2397,6 +2413,7 @@ > XPCNativeInterface* mInterface; > nsISupports* mNative; > JSObject* mJSObject; >+ PRBool mUnsafe; > }; > > /***********************************************/ >@@ -2772,6 +2789,9 @@ > > JSBool ExtendSet(XPCCallContext& ccx, XPCNativeInterface* aInterface); > >+ nsresult ShouldAllowQI(nsISupports* aIdentity, >+ XPCNativeInterface* aInterface); >+ > nsresult InitTearOff(XPCCallContext& ccx, > XPCWrappedNativeTearOff* aTearOff, > XPCNativeInterface* aInterface, >diff --git a/js/src/xpconnect/src/xpcwrappednative.cpp b/js/src/xpconnect/src/xpcwrappednative.cpp >--- a/js/src/xpconnect/src/xpcwrappednative.cpp >+++ b/js/src/xpconnect/src/xpcwrappednative.cpp >@@ -1066,6 +1066,12 @@ > "Can't set DONT_SHARE_PROTOTYPE on an instance scriptable " > "without also setting it on the class scriptable (if present and shared)"); > >+ NS_ASSERTION(!(sciWrapper.GetFlags().ClassInfoInterfacesOnlyNoPrivs() && >+ !sciProto.GetFlags().ClassInfoInterfacesOnlyNoPrivs() && >+ sciProto.GetCallback()), >+ "Can't set CLASSINFO_INTERFACES_ONLY_NOPRIVS on an instance scriptable " >+ "without also setting it on the class scriptable (if present and shared)"); >+ > return sciWrapper; > } > >@@ -1826,6 +1832,9 @@ > { > if(to->GetInterface() == aInterface) > { >+ if(to->IsUnsafe()) >+ continue; // Don't reuse an unsafe tearoff >+ > if(needJSObject && !to->GetJSObject()) > { > AutoMarkingWrappedNativeTearOffPtr tearoff(ccx, to); >@@ -1870,6 +1879,8 @@ > to->Unmark(); > if(NS_FAILED(rv)) > to = nsnull; >+ if (rv == NS_SUCCESS_XPC_DONT_CACHE_TEAROFF) >+ to->MarkUnsafe(); > } > > return_result: >@@ -1880,6 +1891,50 @@ > } > > nsresult >+XPCWrappedNative::ShouldAllowQI(nsISupports* aIdentity, >+ XPCNativeInterface* aInterface) >+{ >+ if(!mScriptableInfo) >+ return NS_OK; >+ >+ // Does the scriptable helper say ClassInfo only for everyone? >+ if (mScriptableInfo->GetFlags().ClassInfoInterfacesOnly() && >+ // NB: If the interface is Unsafe then we can't rely on it being in >+ // the set as a test of whether this is safe or not. >+ (aInterface->IsUnsafe() || >+ (!mSet->HasInterface(aInterface) && >+ !mSet->HasInterfaceWithAncestor(aInterface))) && >+ !mScriptableInfo->ShouldReflectNonClassInfoIface(aIdentity, >+ *aInterface->GetIID())) >+ { >+ // Don't even try the QI >+ return NS_ERROR_NO_INTERFACE; >+ } >+ >+ PRBool shouldRestrictTearoff = PR_FALSE; >+ // Or for non-privileged callers when the caller is non-privileged? >+ if (mScriptableInfo->GetFlags().ClassInfoInterfacesOnlyNoPrivs() && >+ // NB: If the interface is Unsafe then we can't rely on it being in >+ // the set as a test of whether this is safe or not. >+ (aInterface->IsUnsafe() || >+ (!mSet->HasInterface(aInterface) && >+ !mSet->HasInterfaceWithAncestor(aInterface))) && >+ !mScriptableInfo->ShouldReflectNonClassInfoIface(aIdentity, >+ *aInterface->GetIID()) && >+ (!NS_SUCCEEDED(XPCWrapper::GetSecurityManager()-> >+ IsCapabilityEnabled("UniversalXPConnect", >+ &shouldRestrictTearoff)) || >+ !shouldRestrictTearoff)) >+ { >+ // Don't even try the QI >+ return NS_ERROR_NO_INTERFACE; >+ } >+ >+ // Otherwise, try the QI, but be careful with the result tearoff if necessary >+ return shouldRestrictTearoff ? NS_SUCCESS_XPC_DONT_CACHE_TEAROFF : NS_OK; >+} >+ >+nsresult > XPCWrappedNative::InitTearOff(XPCCallContext& ccx, > XPCWrappedNativeTearOff* aTearOff, > XPCNativeInterface* aInterface, >@@ -1888,20 +1943,14 @@ > // This is only called while locked (during XPCWrappedNative::FindTearOff). > > // Determine if the object really does this interface... >- >+ nsresult rv; > const nsIID* iid = aInterface->GetIID(); > nsISupports* identity = GetIdentityObject(); > nsISupports* obj; > >- // If the scriptable helper forbids us from reflecting additional >- // interfaces, then don't even try the QI, just fail. >- if(mScriptableInfo && >- mScriptableInfo->GetFlags().ClassInfoInterfacesOnly() && >- !mSet->HasInterface(aInterface) && >- !mSet->HasInterfaceWithAncestor(aInterface)) >- { >- return NS_ERROR_NO_INTERFACE; >- } >+ // Check to see if we should allow this QI >+ rv = ShouldAllowQI(identity, aInterface); >+ if (NS_FAILED(rv)) { return rv; }; > > // We are about to call out to unlock and other code. > // So protect our intended tearoff. >@@ -2051,8 +2100,8 @@ > // Note: we do not cache the result of the previous call to HasInterface() > // because we unlocked and called out in the interim and the result of the > // previous call might not be correct anymore. >- >- if(!mSet->HasInterface(aInterface) && !ExtendSet(ccx, aInterface)) >+ if(!mSet->HasInterface(aInterface) && >+ !ExtendSet(ccx, aInterface)) > { > NS_RELEASE(obj); > aTearOff->SetInterface(nsnull); >@@ -2061,6 +2110,9 @@ > > aTearOff->SetInterface(aInterface); > aTearOff->SetNative(obj); >+ if (rv == NS_SUCCESS_XPC_DONT_CACHE_TEAROFF) >+ aInterface->MarkUnsafe(); >+ > #ifdef XPC_IDISPATCH_SUPPORT > // Are we building a tearoff for IDispatch? > if(iid->Equals(NSID_IDISPATCH)) >@@ -2071,7 +2123,7 @@ > if(needJSObject && !InitTearOffJSObject(ccx, aTearOff)) > return NS_ERROR_OUT_OF_MEMORY; > >- return NS_OK; >+ return rv; > } > > JSBool >diff --git a/js/src/xpconnect/src/xpcwrappednativejsops.cpp b/js/src/xpconnect/src/xpcwrappednativejsops.cpp >--- a/js/src/xpconnect/src/xpcwrappednativejsops.cpp >+++ b/js/src/xpconnect/src/xpcwrappednativejsops.cpp >@@ -1173,9 +1173,15 @@ > XPCNativeMember* member; > XPCNativeInterface* iface; > JSBool IsLocal; >+ PRBool isPrivileged; > > if(set->FindMember(id, &member, &iface, protoSet, &IsLocal) && >- IsLocal) >+ IsLocal && >+ !(iface->IsUnsafe() && >+ (!NS_SUCCEEDED(XPCWrapper::GetSecurityManager()-> >+ IsCapabilityEnabled("UniversalXPConnect", >+ &isPrivileged)) || >+ !isPrivileged))) > { > XPCWrappedNative* oldResolvingWrapper; >
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
Actions:
View
|
Diff
|
Review
Attachments on
bug 605271
:
485584
|
485607
| 492083