Bug 1084245 - Introduce a hacky opt-out of the new security checks for MozTCPSocket. r=bz
authorBobby Holley <bobbyholley@gmail.com>
Fri, 17 Oct 2014 18:02:19 +0200
changeset 211075 5dc1be48edc3bf0d474a413497e433caac4d9aa9
parent 211074 82ff6f0054839c90b6ef22e991e08e4773ebb8e7
child 211076 54f0944c9d07e6be6f7d0252ca8aaeb8e378bc2d
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewersbz
bugs1084245
milestone36.0a1
Bug 1084245 - Introduce a hacky opt-out of the new security checks for MozTCPSocket. r=bz
dom/network/TCPServerSocket.js
dom/network/TCPSocket.js
js/xpconnect/idl/xpccomponents.idl
js/xpconnect/src/XPCComponents.cpp
js/xpconnect/src/xpcprivate.h
js/xpconnect/wrappers/AccessCheck.cpp
--- a/dom/network/TCPServerSocket.js
+++ b/dom/network/TCPServerSocket.js
@@ -40,16 +40,20 @@ function TCPServerSocket() {
   this._onerror = null;
 
   this._inChild = false;
   this._neckoTCPServerSocket = null;
   this._serverBridge = null;
   this.useWin = null;
 }
 
+// When this API moves to WebIDL and these __exposedProps__ go away, remove
+// this call here and remove the API from XPConnect.
+Cu.skipCOWCallableChecks();
+
 TCPServerSocket.prototype = {
   __exposedProps__: {
     port: 'r',
     onconnect: 'rw',
     onerror: 'rw'
   },
   get localPort() {
     return this._localPort;
--- a/dom/network/TCPSocket.js
+++ b/dom/network/TCPSocket.js
@@ -64,16 +64,20 @@ function LOG(msg) {
  */
 
 function TCPSocketEvent(type, sock, data) {
   this._type = type;
   this._target = sock;
   this._data = data;
 }
 
+// When this API moves to WebIDL and these __exposedProps__ go away, remove
+// this call here and remove the API from XPConnect.
+Cu.skipCOWCallableChecks();
+
 TCPSocketEvent.prototype = {
   __exposedProps__: {
     type: 'r',
     target: 'r',
     data: 'r'
   },
   get type() {
     return this._type;
--- a/js/xpconnect/idl/xpccomponents.idl
+++ b/js/xpconnect/idl/xpccomponents.idl
@@ -117,17 +117,17 @@ interface nsIXPCComponents_utils_Sandbox
 interface ScheduledGCCallback : nsISupports
 {
     void callback();
 };
 
 /**
 * interface of Components.utils
 */
-[scriptable, uuid(faa33210-536b-42e5-b9b0-8ea239899ba4)]
+[scriptable, uuid(ad41689c-ed0e-4a92-8f19-a53c2dba5711)]
 interface nsIXPCComponents_Utils : nsISupports
 {
 
     /* reportError is designed to be called from JavaScript only.
      *
      * It will report a JS Error object to the JS console, and return. It
      * is meant for use in exception handler blocks which want to "eat"
      * an exception, but still want to report it to the console.
@@ -460,16 +460,26 @@ interface nsIXPCComponents_Utils : nsISu
      * For gecko internal automation use only. Calling this in production code
      * would result in security vulnerabilities, so it will crash if used outside
      * of automation.
      */
     [implicit_jscontext]
     void forcePermissiveCOWs();
 
     /*
+     * Disables the XPConnect security checks that deny access to callables and
+     * accessor descriptors on COWs. Do not use this unless you are bholley.
+     *
+     * For the benefit of his magesty TCPSocket while he takes his sweet time
+     * converting to WebIDL. See bug 885982.
+     */
+    [implicit_jscontext]
+    void skipCOWCallableChecks();
+
+    /*
      * Forces the usage of a privileged |Components| object for a potentially-
      * unprivileged scope. This will crash if used outside of automation.
      */
     [implicit_jscontext]
     void forcePrivilegedComponentsForScope(in jsval vscope);
 
     /*
      * This seemingly-paradoxical API allows privileged code to explicitly give
--- a/js/xpconnect/src/XPCComponents.cpp
+++ b/js/xpconnect/src/XPCComponents.cpp
@@ -3145,16 +3145,24 @@ nsXPCComponents_Utils::SetWantXrays(Hand
 NS_IMETHODIMP
 nsXPCComponents_Utils::ForcePermissiveCOWs(JSContext *cx)
 {
     CrashIfNotInAutomation();
     CompartmentPrivate::Get(CurrentGlobalOrNull(cx))->forcePermissiveCOWs = true;
     return NS_OK;
 }
 
+/* jsval skipCOWCallableChecks(); */
+NS_IMETHODIMP
+nsXPCComponents_Utils::SkipCOWCallableChecks(JSContext *cx)
+{
+    CompartmentPrivate::Get(CurrentGlobalOrNull(cx))->skipCOWCallableChecks = true;
+    return NS_OK;
+}
+
 /* jsval forcePrivilegedComponentsForScope(jsval vscope); */
 NS_IMETHODIMP
 nsXPCComponents_Utils::ForcePrivilegedComponentsForScope(HandleValue vscope,
                                                          JSContext *cx)
 {
     if (!vscope.isObject())
         return NS_ERROR_INVALID_ARG;
     CrashIfNotInAutomation();
--- a/js/xpconnect/src/xpcprivate.h
+++ b/js/xpconnect/src/xpcprivate.h
@@ -3638,16 +3638,17 @@ public:
     };
 
     explicit CompartmentPrivate(JSCompartment *c)
         : wantXrays(false)
         , writeToGlobalPrototype(false)
         , skipWriteToGlobalPrototype(false)
         , universalXPConnectEnabled(false)
         , forcePermissiveCOWs(false)
+        , skipCOWCallableChecks(false)
         , scriptability(c)
         , scope(nullptr)
     {
         MOZ_COUNT_CTOR(xpc::CompartmentPrivate);
         mozilla::PodArrayZero(wrapperDenialWarnings);
     }
 
     ~CompartmentPrivate();
@@ -3690,16 +3691,20 @@ public:
     // This is only ever set during mochitest runs when enablePrivilege is called.
     // It allows the SpecialPowers scope to waive the normal chrome security
     // wrappers and expose properties directly to content. This lets us avoid a
     // bunch of overhead and complexity in our SpecialPowers automation glue.
     //
     // Using it in production is inherently unsafe.
     bool forcePermissiveCOWs;
 
+    // Disables the XPConnect security checks that deny access to callables and
+    // accessor descriptors on COWs. Do not use this unless you are bholley.
+    bool skipCOWCallableChecks;
+
     // Whether we've emitted a warning about a property that was filtered out
     // by a security wrapper. See XrayWrapper.cpp.
     bool wrapperDenialWarnings[WrapperDenialTypeCount];
 
     // The scriptability of this compartment.
     Scriptability scriptability;
 
     // Our XPCWrappedNativeScope. This is non-null if and only if this is an
--- a/js/xpconnect/wrappers/AccessCheck.cpp
+++ b/js/xpconnect/wrappers/AccessCheck.cpp
@@ -341,27 +341,28 @@ ExposedPropertiesOnly::check(JSContext *
     }
 
     if ((act == Wrapper::SET && !(access & WRITE)) ||
         (act != Wrapper::SET && !(access & READ))) {
         return false;
     }
 
     // Inspect the property on the underlying object to check for red flags.
+    bool skipCallableChecks = CompartmentPrivate::Get(wrappedObject)->skipCOWCallableChecks;
     if (!JS_GetPropertyDescriptorById(cx, wrappedObject, id, &desc))
         return false;
 
     // Reject accessor properties.
-    if (desc.hasGetterOrSetter()) {
+    if (!skipCallableChecks && desc.hasGetterOrSetter()) {
         EnterAndThrow(cx, wrapper, "Exposing privileged accessor properties is prohibited");
         return false;
     }
 
     // Reject privileged or cross-origin callables.
-    if (desc.value().isObject()) {
+    if (!skipCallableChecks && desc.value().isObject()) {
         RootedObject maybeCallable(cx, js::UncheckedUnwrap(&desc.value().toObject()));
         if (JS::IsCallable(maybeCallable) && !AccessCheck::subsumes(wrapper, maybeCallable)) {
             EnterAndThrow(cx, wrapper, "Exposing privileged or cross-origin callable is prohibited");
             return false;
         }
     }
 
     return true;