Bug 932315 - Throw a different error when this-unwrapping fails for security reasons. r=bz.
authorPeter Van der Beken <peterv@propagandism.org>
Wed, 16 Oct 2013 18:11:25 +0200
changeset 167586 e790b3c30e1a62e05079cd99c5caa002218d87b6
parent 167585 a6878c4ee086c844e6b86bb7c2b69a2881c8bc13
child 167587 392ee11b1ff6467d055ea5cf69d86bb54f2302eb
push id3224
push userlsblakk@mozilla.com
push dateTue, 04 Feb 2014 01:06:49 +0000
treeherdermozilla-beta@60c04d0987f1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz
bugs932315
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 932315 - Throw a different error when this-unwrapping fails for security reasons. r=bz.
dom/bindings/BindingUtils.h
dom/bindings/Codegen.py
dom/bindings/Errors.msg
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -59,16 +59,37 @@ UnwrapArg(JSContext* cx, JS::Handle<JS::
   nsISupports* argRef = *ppArgRef;
   nsresult rv = xpc_qsUnwrapArgImpl(cx, v, NS_GET_TEMPLATE_IID(Interface),
                                     reinterpret_cast<void**>(ppArg), &argRef,
                                     vp);
   *ppArgRef = static_cast<StrongRefType*>(argRef);
   return rv;
 }
 
+inline const ErrNum
+GetInvalidThisErrorForMethod(bool aSecurityError)
+{
+  return aSecurityError ? MSG_METHOD_THIS_UNWRAPPING_DENIED :
+                          MSG_METHOD_THIS_DOES_NOT_IMPLEMENT_INTERFACE;
+}
+
+inline const ErrNum
+GetInvalidThisErrorForGetter(bool aSecurityError)
+{
+  return aSecurityError ? MSG_GETTER_THIS_UNWRAPPING_DENIED :
+                          MSG_GETTER_THIS_DOES_NOT_IMPLEMENT_INTERFACE;
+}
+
+inline const ErrNum
+GetInvalidThisErrorForSetter(bool aSecurityError)
+{
+  return aSecurityError ? MSG_SETTER_THIS_UNWRAPPING_DENIED :
+                          MSG_SETTER_THIS_DOES_NOT_IMPLEMENT_INTERFACE;
+}
+
 bool
 ThrowInvalidThis(JSContext* aCx, const JS::CallArgs& aArgs,
                  const ErrNum aErrorNumber,
                  const char* aInterfaceName);
 
 inline bool
 ThrowMethodFailedWithDetails(JSContext* cx, ErrorResult& rv,
                              const char* ifaceName,
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -2448,23 +2448,24 @@ class CastableObjectUnwrapper():
                 "} else {\n"
                 "${codeOnFailure}\n"
                 "}").substitute(self.substitution)), 4).define()
         else:
             self.substitution["codeOnFailure"] = CGIndenter(
                 CGGeneric(self.substitution["codeOnFailure"])).define()
 
     def __str__(self):
+        codeOnFailure = self.substitution["codeOnFailure"] % {'securityError': 'rv == NS_ERROR_XPC_SECURITY_MANAGER_VETO'}
         return string.Template(
 """{
   nsresult rv = UnwrapObject<${protoID}, ${type}>(cx, ${source}, ${target});
   if (NS_FAILED(rv)) {
 ${codeOnFailure}
   }
-}""").substitute(self.substitution)
+}""").substitute(self.substitution, codeOnFailure=codeOnFailure)
 
 class FailureFatalCastableObjectUnwrapper(CastableObjectUnwrapper):
     """
     As CastableObjectUnwrapper, but defaulting to throwing if unwrapping fails
     """
     def __init__(self, descriptor, source, target, exceptionCode,
                  isCallbackReturnValue, sourceDescription):
         CastableObjectUnwrapper.__init__(
@@ -5448,17 +5449,18 @@ class CGAbstractBindingMethod(CGAbstract
         else:
             if getThisObj is None:
                 if descriptor.interface.isOnGlobalProtoChain():
                     ensureCondition = "!args.thisv().isNullOrUndefined() && !args.thisv().isObject()"
                     getThisObj = "args.thisv().isObject() ? &args.thisv().toObject() : js::GetGlobalForObjectCrossCompartment(&args.callee())"
                 else:
                     ensureCondition = "!args.thisv().isObject()"
                     getThisObj = "&args.thisv().toObject()"
-                ensureThisObj = CGIfWrapper(CGGeneric(self.unwrapFailureCode),
+                unwrapFailureCode = self.unwrapFailureCode % {'securityError': 'false'}
+                ensureThisObj = CGIfWrapper(CGGeneric(unwrapFailureCode),
                                             ensureCondition)
             else:
                 ensureThisObj = None
             self.getThisObj = CGList(
                 [ensureThisObj,
                  CGGeneric("JS::RootedObject obj(cx, %s);\n" %
                            getThisObj)],
                 "\n")
@@ -5515,17 +5517,17 @@ def MakeNativeName(name):
 class CGGenericMethod(CGAbstractBindingMethod):
     """
     A class for generating the C++ code for an IDL method..
     """
     def __init__(self, descriptor):
         args = [Argument('JSContext*', 'cx'), Argument('unsigned', 'argc'),
                 Argument('JS::Value*', 'vp')]
         unwrapFailureCode = (
-            'return ThrowInvalidThis(cx, args, MSG_METHOD_THIS_DOES_NOT_IMPLEMENT_INTERFACE, \"%s\");' %
+            'return ThrowInvalidThis(cx, args, GetInvalidThisErrorForMethod(%%(securityError)s), "%s");' %
             descriptor.interface.identifier.name)
         CGAbstractBindingMethod.__init__(self, descriptor, 'genericMethod',
                                          args,
                                          unwrapFailureCode=unwrapFailureCode)
 
     def generate_code(self):
         return CGIndenter(CGGeneric(
             "const JSJitInfo *info = FUNCTION_VALUE_TO_JITINFO(JS_CALLEE(cx, vp));\n"
@@ -5715,17 +5717,17 @@ class CGGenericGetter(CGAbstractBindingM
                 "if (!ReportLenientThisUnwrappingFailure(cx, &args.callee())) {\n"
                 "  return false;\n"
                 "}\n"
                 "args.rval().set(JS::UndefinedValue());\n"
                 "return true;")
         else:
             name = "genericGetter"
             unwrapFailureCode = (
-                'return ThrowInvalidThis(cx, args, MSG_GETTER_THIS_DOES_NOT_IMPLEMENT_INTERFACE, "%s");' %
+                'return ThrowInvalidThis(cx, args, GetInvalidThisErrorForGetter(%%(securityError)s), "%s");' %
                 descriptor.interface.identifier.name)
         CGAbstractBindingMethod.__init__(self, descriptor, name, args,
                                          unwrapFailureCode)
 
     def generate_code(self):
         return CGIndenter(CGGeneric(
             "const JSJitInfo *info = FUNCTION_VALUE_TO_JITINFO(JS_CALLEE(cx, vp));\n"
             "MOZ_ASSERT(info->type == JSJitInfo::Getter);\n"
@@ -5795,17 +5797,17 @@ class CGGenericSetter(CGAbstractBindingM
                 "if (!ReportLenientThisUnwrappingFailure(cx, &args.callee())) {\n"
                 "  return false;\n"
                 "}\n"
                 "args.rval().set(JS::UndefinedValue());\n"
                 "return true;")
         else:
             name = "genericSetter"
             unwrapFailureCode = (
-                'return ThrowInvalidThis(cx, args, MSG_SETTER_THIS_DOES_NOT_IMPLEMENT_INTERFACE, "%s");' %
+                'return ThrowInvalidThis(cx, args, GetInvalidThisErrorForSetter(%%(securityError)s), "%s");' %
                 descriptor.interface.identifier.name)
 
         CGAbstractBindingMethod.__init__(self, descriptor, name, args,
                                          unwrapFailureCode)
 
     def generate_code(self):
         return CGIndenter(CGGeneric(
                 "if (args.length() == 0) {\n"
--- a/dom/bindings/Errors.msg
+++ b/dom/bindings/Errors.msg
@@ -20,18 +20,21 @@
  */
 
 MSG_DEF(MSG_INVALID_ENUM_VALUE, 3, "{0} '{1}' is not a valid value for enumeration {2}.")
 MSG_DEF(MSG_MISSING_ARGUMENTS, 1, "Not enough arguments to {0}.")
 MSG_DEF(MSG_NOT_OBJECT, 1, "{0} is not an object.")
 MSG_DEF(MSG_NOT_CALLABLE, 1, "{0} is not callable.")
 MSG_DEF(MSG_DOES_NOT_IMPLEMENT_INTERFACE, 2, "{0} does not implement interface {1}.")
 MSG_DEF(MSG_METHOD_THIS_DOES_NOT_IMPLEMENT_INTERFACE, 2, "'{0}' called on an object that does not implement interface {1}.")
+MSG_DEF(MSG_METHOD_THIS_UNWRAPPING_DENIED, 1, "Permission to call '{0}' denied.")
 MSG_DEF(MSG_GETTER_THIS_DOES_NOT_IMPLEMENT_INTERFACE, 2, "'{0}' getter called on an object that does not implement interface {1}.")
+MSG_DEF(MSG_GETTER_THIS_UNWRAPPING_DENIED, 1, "Permission to call '{0}' getter denied.")
 MSG_DEF(MSG_SETTER_THIS_DOES_NOT_IMPLEMENT_INTERFACE, 2, "'{0}' setter called on an object that does not implement interface {1}.")
+MSG_DEF(MSG_SETTER_THIS_UNWRAPPING_DENIED, 1, "Permission to call '{0}' setter denied.")
 MSG_DEF(MSG_THIS_DOES_NOT_IMPLEMENT_INTERFACE, 1, "\"this\" object does not implement interface {0}.")
 MSG_DEF(MSG_NOT_IN_UNION, 2, "{0} could not be converted to any of: {1}.")
 MSG_DEF(MSG_ILLEGAL_CONSTRUCTOR, 0, "Illegal constructor.")
 MSG_DEF(MSG_NO_INDEXED_SETTER, 1, "{0} doesn't have an indexed property setter.")
 MSG_DEF(MSG_NO_NAMED_SETTER, 1, "{0} doesn't have a named property setter.")
 MSG_DEF(MSG_ENFORCE_RANGE_NON_FINITE, 1, "Non-finite value is out of range for {0}.")
 MSG_DEF(MSG_ENFORCE_RANGE_OUT_OF_RANGE, 1, "Value is out of range for {0}.")
 MSG_DEF(MSG_NOT_SEQUENCE, 1, "{0} can't be converted to a sequence.")