Bug 939696 - IsScriptedProxy. r=bholley
authorGabor Krizsanits <gkrizsanits@mozilla.com>
Tue, 26 Nov 2013 14:53:20 +0100
changeset 157531 27327f3e2943
parent 157530 142b7b93b58b
child 157532 017167e2056a
push id25716
push userkwierso@gmail.com
push date2013-11-27 01:32 +0000
treeherdermozilla-central@d822990ba9ee [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbholley
bugs939696
milestone28.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 939696 - IsScriptedProxy. r=bholley
js/src/jsproxy.cpp
js/src/jsproxy.h
js/xpconnect/src/Sandbox.cpp
js/xpconnect/src/XPCComponents.cpp
--- a/js/src/jsproxy.cpp
+++ b/js/src/jsproxy.cpp
@@ -776,16 +776,17 @@ class ScriptedIndirectProxyHandler : pub
 
     /* Spidermonkey extensions. */
     virtual bool isExtensible(JSContext *cx, HandleObject proxy, bool *extensible) MOZ_OVERRIDE;
     virtual bool call(JSContext *cx, HandleObject proxy, const CallArgs &args) MOZ_OVERRIDE;
     virtual bool construct(JSContext *cx, HandleObject proxy, const CallArgs &args) MOZ_OVERRIDE;
     virtual bool nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl,
                             CallArgs args) MOZ_OVERRIDE;
     virtual JSString *fun_toString(JSContext *cx, HandleObject proxy, unsigned indent) MOZ_OVERRIDE;
+    virtual bool isScripted() MOZ_OVERRIDE { return true; }
 
     static ScriptedIndirectProxyHandler singleton;
 };
 
 /*
  * Old-style indirect proxies allow callers to specify distinct scripted
  * [[Call]] and [[Construct]] traps. We use an intermediate object so that we
  * can stash this information in a single reserved slot on the proxy object.
@@ -1096,16 +1097,17 @@ class ScriptedDirectProxyHandler : publi
                      bool strict, MutableHandleValue vp) MOZ_OVERRIDE;
     virtual bool keys(JSContext *cx, HandleObject proxy, AutoIdVector &props) MOZ_OVERRIDE;
     virtual bool iterate(JSContext *cx, HandleObject proxy, unsigned flags,
                          MutableHandleValue vp) MOZ_OVERRIDE;
 
     /* Spidermonkey extensions. */
     virtual bool call(JSContext *cx, HandleObject proxy, const CallArgs &args) MOZ_OVERRIDE;
     virtual bool construct(JSContext *cx, HandleObject proxy, const CallArgs &args) MOZ_OVERRIDE;
+    virtual bool isScripted() MOZ_OVERRIDE { return true; }
 
     static ScriptedDirectProxyHandler singleton;
 };
 
 // This variable exists solely to provide a unique address for use as an identifier.
 static const char sScriptedDirectProxyHandlerFamily = 0;
 
 // Aux.2 FromGenericPropertyDescriptor(Desc)
--- a/js/src/jsproxy.h
+++ b/js/src/jsproxy.h
@@ -169,16 +169,17 @@ class JS_FRIEND_API(BaseProxyHandler)
     // These two hooks must be overridden, or not overridden, in tandem -- no
     // overriding just one!
     virtual bool watch(JSContext *cx, JS::HandleObject proxy, JS::HandleId id,
                        JS::HandleObject callable);
     virtual bool unwatch(JSContext *cx, JS::HandleObject proxy, JS::HandleId id);
 
     /* See comment for weakmapKeyDelegateOp in js/Class.h. */
     virtual JSObject *weakmapKeyDelegate(JSObject *proxy);
+    virtual bool isScripted() { return false; }
 };
 
 /*
  * DirectProxyHandler includes a notion of a target object. All traps are
  * reimplemented such that they forward their behavior to the target. This
  * allows consumers of this class to forward to another object as transparently
  * and efficiently as possible.
  */
@@ -304,16 +305,27 @@ inline bool IsProxyClass(const Class *cl
            clasp == OuterWindowProxyClassPtr;
 }
 
 inline bool IsProxy(JSObject *obj)
 {
     return IsProxyClass(GetObjectClass(obj));
 }
 
+BaseProxyHandler *
+GetProxyHandler(JSObject *obj);
+
+inline bool IsScriptedProxy(JSObject *obj)
+{
+    if (!IsProxy(obj))
+        return false;
+
+    return GetProxyHandler(obj)->isScripted();
+}
+
 /*
  * These are part of the API.
  *
  * NOTE: PROXY_PRIVATE_SLOT is 0 because that way slot 0 is usable by API
  * clients for both proxy and non-proxy objects.  So an API client that only
  * needs to store one slot's worth of data doesn't need to branch on what sort
  * of object it has.
  */
--- a/js/xpconnect/src/Sandbox.cpp
+++ b/js/xpconnect/src/Sandbox.cpp
@@ -237,16 +237,21 @@ ExportFunction(JSContext *cx, HandleValu
     // We can only export functions to scopes those are transparent for us,
     // so if there is a security wrapper around targetScope we must throw.
     targetScope = CheckedUnwrap(targetScope);
     if (!targetScope) {
         JS_ReportError(cx, "Permission denied to export function into scope");
         return false;
     }
 
+    if (js::IsScriptedProxy(targetScope)) {
+        JS_ReportError(cx, "Defining property on proxy object is not allowed");
+        return false;
+    }
+
     if (JS_GetStringLength(funName) == 0) {
         JS_ReportError(cx, "3rd argument should be a non-empty string");
         return false;
     }
 
     {
         // We need to operate in the target scope from here on, let's enter
         // its compartment.
--- a/js/xpconnect/src/XPCComponents.cpp
+++ b/js/xpconnect/src/XPCComponents.cpp
@@ -3023,28 +3023,36 @@ xpc::CreateObjectIn(JSContext *cx, Handl
     }
 
     RootedObject scope(cx, js::CheckedUnwrap(&vobj.toObject()));
     if (!scope) {
         JS_ReportError(cx, "Permission denied to create object in the target scope");
         return false;
     }
 
+    bool define = !JSID_IS_VOID(options.defineAs);
+
+    if (define && js::IsScriptedProxy(scope)) {
+        JS_ReportError(cx, "Defining property on proxy object is not allowed");
+        return false;
+    }
+
     RootedObject obj(cx);
     {
         JSAutoCompartment ac(cx, scope);
         obj = JS_NewObject(cx, nullptr, nullptr, scope);
         if (!obj)
             return false;
 
-        if (!JSID_IS_VOID(options.defineAs) &&
-            !JS_DefinePropertyById(cx, scope, options.defineAs, ObjectValue(*obj),
-                                   JS_PropertyStub, JS_StrictPropertyStub,
-                                   JSPROP_ENUMERATE))
-            return false;
+        if (define) {
+            if (!JS_DefinePropertyById(cx, scope, options.defineAs, ObjectValue(*obj),
+                                       JS_PropertyStub, JS_StrictPropertyStub,
+                                       JSPROP_ENUMERATE))
+                return false;
+        }
     }
 
     rval.setObject(*obj);
     if (!WrapperFactory::WaiveXrayAndWrap(cx, rval))
         return false;
 
     return true;
 }