mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1036214 - Do a subsumes check on object and any parameters (and things containing them) to JS-implemented WebIDL. r=bz
This commit is contained in:
parent
fd4bd58644
commit
12abd6ffbc
@ -2645,5 +2645,12 @@ AssertReturnTypeMatchesJitinfo(const JSJitInfo* aJitInfo,
|
||||
}
|
||||
#endif
|
||||
|
||||
bool
|
||||
CallerSubsumes(JSObject *aObject)
|
||||
{
|
||||
nsIPrincipal* objPrin = nsContentUtils::ObjectPrincipal(js::UncheckedUnwrap(aObject));
|
||||
return nsContentUtils::SubjectPrincipal()->Subsumes(objPrin);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
@ -2937,6 +2937,18 @@ AssertReturnTypeMatchesJitinfo(const JSJitInfo* aJitinfo,
|
||||
bool
|
||||
CheckPermissions(JSContext* aCx, JSObject* aObj, const char* const aPermissions[]);
|
||||
|
||||
bool
|
||||
CallerSubsumes(JSObject* aObject);
|
||||
|
||||
MOZ_ALWAYS_INLINE bool
|
||||
CallerSubsumes(JS::Handle<JS::Value> aValue)
|
||||
{
|
||||
if (!aValue.isObject()) {
|
||||
return true;
|
||||
}
|
||||
return CallerSubsumes(&aValue.toObject());
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
|
@ -3572,6 +3572,9 @@ class JSToNativeConversionInfo():
|
||||
for whether we have a JS::Value. Only used when
|
||||
defaultValue is not None or when True is passed for
|
||||
checkForValue to instantiateJSToNativeConversion.
|
||||
${passedToJSImpl} replaced by an expression that evaluates to a boolean
|
||||
for whether this value is being passed to a JS-
|
||||
implemented interface.
|
||||
|
||||
declType: A CGThing representing the native C++ type we're converting
|
||||
to. This is allowed to be None if the conversion code is
|
||||
@ -3827,7 +3830,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
|
||||
return templateBody
|
||||
|
||||
# A helper function for converting things that look like a JSObject*.
|
||||
def handleJSObjectType(type, isMember, failureCode):
|
||||
def handleJSObjectType(type, isMember, failureCode, exceptionCode, sourceDescription):
|
||||
if not isMember:
|
||||
if isOptional:
|
||||
# We have a specialization of Optional that will use a
|
||||
@ -3843,6 +3846,19 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
|
||||
declType = CGGeneric("JSObject*")
|
||||
declArgs = None
|
||||
templateBody = "${declName} = &${val}.toObject();\n"
|
||||
|
||||
# For JS-implemented APIs, we refuse to allow passing objects that the
|
||||
# API consumer does not subsume.
|
||||
if not isinstance(descriptorProvider, Descriptor) or descriptorProvider.interface.isJSImplemented():
|
||||
templateBody = fill("""
|
||||
if ($${passedToJSImpl} && !CallerSubsumes($${val})) {
|
||||
ThrowErrorMessage(cx, MSG_PERMISSION_DENIED_TO_PASS_ARG, "${sourceDescription}");
|
||||
$*{exceptionCode}
|
||||
}
|
||||
""",
|
||||
sourceDescription=sourceDescription,
|
||||
exceptionCode=exceptionCode) + templateBody
|
||||
|
||||
setToNullCode = "${declName} = nullptr;\n"
|
||||
template = wrapObjectTemplate(templateBody, type, setToNullCode,
|
||||
failureCode)
|
||||
@ -3917,7 +3933,8 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
|
||||
# We only need holderName here to handle isExternal()
|
||||
# interfaces, which use an internal holder for the
|
||||
# conversion even when forceOwningType ends up true.
|
||||
"holderName": "tempHolder"
|
||||
"holderName": "tempHolder",
|
||||
"passedToJSImpl": "${passedToJSImpl}"
|
||||
})
|
||||
|
||||
# NOTE: Keep this in sync with variadic conversions as needed
|
||||
@ -4021,7 +4038,8 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
|
||||
# We only need holderName here to handle isExternal()
|
||||
# interfaces, which use an internal holder for the
|
||||
# conversion even when forceOwningType ends up true.
|
||||
"holderName": "tempHolder"
|
||||
"holderName": "tempHolder",
|
||||
"passedToJSImpl": "${passedToJSImpl}"
|
||||
})
|
||||
|
||||
templateBody = fill(
|
||||
@ -4114,7 +4132,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
|
||||
for memberType in interfaceMemberTypes:
|
||||
name = getUnionMemberName(memberType)
|
||||
interfaceObject.append(
|
||||
CGGeneric("(failed = !%s.TrySetTo%s(cx, ${val}, tryNext)) || !tryNext" %
|
||||
CGGeneric("(failed = !%s.TrySetTo%s(cx, ${val}, tryNext, ${passedToJSImpl})) || !tryNext" %
|
||||
(unionArgumentObj, name)))
|
||||
names.append(name)
|
||||
interfaceObject = CGWrapper(CGList(interfaceObject, " ||\n"),
|
||||
@ -4127,7 +4145,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
|
||||
assert len(arrayObjectMemberTypes) == 1
|
||||
name = getUnionMemberName(arrayObjectMemberTypes[0])
|
||||
arrayObject = CGGeneric(
|
||||
"done = (failed = !%s.TrySetTo%s(cx, ${val}, tryNext)) || !tryNext;\n" %
|
||||
"done = (failed = !%s.TrySetTo%s(cx, ${val}, tryNext, ${passedToJSImpl})) || !tryNext;\n" %
|
||||
(unionArgumentObj, name))
|
||||
names.append(name)
|
||||
else:
|
||||
@ -4151,7 +4169,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
|
||||
memberType = callbackMemberTypes[0]
|
||||
name = getUnionMemberName(memberType)
|
||||
callbackObject = CGGeneric(
|
||||
"done = (failed = !%s.TrySetTo%s(cx, ${val}, tryNext)) || !tryNext;\n" %
|
||||
"done = (failed = !%s.TrySetTo%s(cx, ${val}, tryNext, ${passedToJSImpl})) || !tryNext;\n" %
|
||||
(unionArgumentObj, name))
|
||||
names.append(name)
|
||||
else:
|
||||
@ -4162,7 +4180,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
|
||||
assert len(dictionaryMemberTypes) == 1
|
||||
name = getUnionMemberName(dictionaryMemberTypes[0])
|
||||
setDictionary = CGGeneric(
|
||||
"done = (failed = !%s.TrySetTo%s(cx, ${val}, tryNext)) || !tryNext;\n" %
|
||||
"done = (failed = !%s.TrySetTo%s(cx, ${val}, tryNext, ${passedToJSImpl})) || !tryNext;\n" %
|
||||
(unionArgumentObj, name))
|
||||
names.append(name)
|
||||
else:
|
||||
@ -4173,7 +4191,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
|
||||
assert len(mozMapMemberTypes) == 1
|
||||
name = getUnionMemberName(mozMapMemberTypes[0])
|
||||
mozMapObject = CGGeneric(
|
||||
"done = (failed = !%s.TrySetTo%s(cx, ${val}, tryNext)) || !tryNext;\n" %
|
||||
"done = (failed = !%s.TrySetTo%s(cx, ${val}, tryNext, ${passedToJSImpl})) || !tryNext;\n" %
|
||||
(unionArgumentObj, name))
|
||||
names.append(name)
|
||||
else:
|
||||
@ -4185,8 +4203,10 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
|
||||
# Very important to NOT construct a temporary Rooted here, since the
|
||||
# SetToObject call can call a Rooted constructor and we need to keep
|
||||
# stack discipline for Rooted.
|
||||
object = CGGeneric("%s.SetToObject(cx, &${val}.toObject());\n"
|
||||
"done = true;\n" % unionArgumentObj)
|
||||
object = CGGeneric("if (!%s.SetToObject(cx, &${val}.toObject(), ${passedToJSImpl})) {\n"
|
||||
"%s"
|
||||
"}\n"
|
||||
"done = true;\n" % (unionArgumentObj, indent(exceptionCode)))
|
||||
names.append(objectMemberTypes[0].name)
|
||||
else:
|
||||
object = None
|
||||
@ -4425,7 +4445,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
|
||||
if descriptor.nativeType == 'JSObject':
|
||||
# XXXbz Workers code does this sometimes
|
||||
assert descriptor.workers
|
||||
return handleJSObjectType(type, isMember, failureCode)
|
||||
return handleJSObjectType(type, isMember, failureCode, exceptionCode, sourceDescription)
|
||||
|
||||
if descriptor.interface.isCallback():
|
||||
name = descriptor.interface.identifier.name
|
||||
@ -4507,7 +4527,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
|
||||
isCallbackReturnValue,
|
||||
firstCap(sourceDescription)))
|
||||
elif descriptor.workers:
|
||||
return handleJSObjectType(type, isMember, failureCode)
|
||||
return handleJSObjectType(type, isMember, failureCode, exceptionCode, sourceDescription)
|
||||
else:
|
||||
# Either external, or new-binding non-castable. We always have a
|
||||
# holder for these, because we don't actually know whether we have
|
||||
@ -4826,6 +4846,19 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
|
||||
|
||||
assert not isOptional
|
||||
templateBody = "${declName} = ${val};\n"
|
||||
|
||||
# For JS-implemented APIs, we refuse to allow passing objects that the
|
||||
# API consumer does not subsume.
|
||||
if not isinstance(descriptorProvider, Descriptor) or descriptorProvider.interface.isJSImplemented():
|
||||
templateBody = fill("""
|
||||
if ($${passedToJSImpl} && !CallerSubsumes($${val})) {
|
||||
ThrowErrorMessage(cx, MSG_PERMISSION_DENIED_TO_PASS_ARG, "${sourceDescription}");
|
||||
$*{exceptionCode}
|
||||
}
|
||||
""",
|
||||
sourceDescription=sourceDescription,
|
||||
exceptionCode=exceptionCode) + templateBody
|
||||
|
||||
# We may not have a default value if we're being converted for
|
||||
# a setter, say.
|
||||
if defaultValue:
|
||||
@ -4841,7 +4874,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
|
||||
|
||||
if type.isObject():
|
||||
assert not isEnforceRange and not isClamp
|
||||
return handleJSObjectType(type, isMember, failureCode)
|
||||
return handleJSObjectType(type, isMember, failureCode, exceptionCode, sourceDescription)
|
||||
|
||||
if type.isDictionary():
|
||||
# There are no nullable dictionaries
|
||||
@ -4891,7 +4924,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
|
||||
if type.nullable():
|
||||
dictLoc += ".SetValue()"
|
||||
|
||||
template += ('if (!%s.Init(cx, %s, "%s")) {\n'
|
||||
template += ('if (!%s.Init(cx, %s, "%s", ${passedToJSImpl})) {\n'
|
||||
"%s"
|
||||
"}\n" % (dictLoc, val, firstCap(sourceDescription),
|
||||
exceptionCodeIndented.define()))
|
||||
@ -5167,7 +5200,8 @@ class CGArgumentConverter(CGThing):
|
||||
self.replacementVariables = {
|
||||
"declName": "arg%d" % index,
|
||||
"holderName": ("arg%d" % index) + "_holder",
|
||||
"obj": "obj"
|
||||
"obj": "obj",
|
||||
"passedToJSImpl": toStringBool(isJSImplementedDescriptor(descriptorProvider))
|
||||
}
|
||||
self.replacementVariables["val"] = string.Template(
|
||||
"args[${index}]").substitute(replacer)
|
||||
@ -5245,7 +5279,8 @@ class CGArgumentConverter(CGThing):
|
||||
# conversion even when forceOwningType ends up true.
|
||||
"holderName": "tempHolder",
|
||||
# Use the same ${obj} as for the variadic arg itself
|
||||
"obj": replacer["obj"]
|
||||
"obj": replacer["obj"],
|
||||
"passedToJSImpl": toStringBool(isJSImplementedDescriptor(self.descriptorProvider))
|
||||
}), 4)
|
||||
|
||||
variadicConversion += (" }\n"
|
||||
@ -6741,7 +6776,8 @@ class CGMethodCall(CGThing):
|
||||
"holderName": ("arg%d" % distinguishingIndex) + "_holder",
|
||||
"val": distinguishingArg,
|
||||
"obj": "obj",
|
||||
"haveValue": "args.hasDefined(%d)" % distinguishingIndex
|
||||
"haveValue": "args.hasDefined(%d)" % distinguishingIndex,
|
||||
"passedToJSImpl": toStringBool(isJSImplementedDescriptor(descriptor))
|
||||
},
|
||||
checkForValue=argIsOptional)
|
||||
caseBody.append(CGIndenter(testCode, indent))
|
||||
@ -8316,9 +8352,22 @@ def getUnionTypeTemplateVars(unionType, type, descriptorProvider,
|
||||
mUnion.mValue.mObject.SetValue(cx, obj);
|
||||
mUnion.mType = mUnion.eObject;
|
||||
""")
|
||||
setter = ClassMethod("SetToObject", "void",
|
||||
|
||||
# It's a bit sketchy to do the security check after setting the value,
|
||||
# but it keeps the code cleaner and lets us avoid rooting |obj| over the
|
||||
# call to CallerSubsumes().
|
||||
body = body + dedent("""
|
||||
if (passedToJSImpl && !CallerSubsumes(obj)) {
|
||||
ThrowErrorMessage(cx, MSG_PERMISSION_DENIED_TO_PASS_ARG, "%s");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
""")
|
||||
|
||||
setter = ClassMethod("SetToObject", "bool",
|
||||
[Argument("JSContext*", "cx"),
|
||||
Argument("JSObject*", "obj")],
|
||||
Argument("JSObject*", "obj"),
|
||||
Argument("bool", "passedToJSImpl", default="false")],
|
||||
inline=True, bodyInHeader=True,
|
||||
body=body)
|
||||
|
||||
@ -8338,7 +8387,8 @@ def getUnionTypeTemplateVars(unionType, type, descriptorProvider,
|
||||
val="value",
|
||||
declName="memberSlot",
|
||||
holderName=(holderName if ownsMembers else "%s.ref()" % holderName),
|
||||
destroyHolder=destroyHolder)
|
||||
destroyHolder=destroyHolder,
|
||||
passedToJSImpl="passedToJSImpl")
|
||||
|
||||
jsConversion = fill(
|
||||
"""
|
||||
@ -8357,7 +8407,8 @@ def getUnionTypeTemplateVars(unionType, type, descriptorProvider,
|
||||
setter = ClassMethod("TrySetTo" + name, "bool",
|
||||
[Argument("JSContext*", "cx"),
|
||||
Argument("JS::Handle<JS::Value>", "value"),
|
||||
Argument("bool&", "tryNext")],
|
||||
Argument("bool&", "tryNext"),
|
||||
Argument("bool", "passedToJSImpl", default="false")],
|
||||
inline=not ownsMembers,
|
||||
bodyInHeader=not ownsMembers,
|
||||
body=jsConversion)
|
||||
@ -9463,7 +9514,8 @@ class CGProxySpecialOperation(CGPerSignatureCall):
|
||||
"declName": argument.identifier.name,
|
||||
"holderName": argument.identifier.name + "_holder",
|
||||
"val": argumentMutableValue,
|
||||
"obj": "obj"
|
||||
"obj": "obj",
|
||||
"passedToJSImpl": "false"
|
||||
}
|
||||
self.cgRoot.prepend(instantiateJSToNativeConversion(info, templateValues))
|
||||
elif operation.isGetter() or operation.isDeleter():
|
||||
@ -11087,7 +11139,8 @@ class CGDictionary(CGThing):
|
||||
return ClassMethod("Init", "bool", [
|
||||
Argument('JSContext*', 'cx'),
|
||||
Argument('JS::Handle<JS::Value>', 'val'),
|
||||
Argument('const char*', 'sourceDescription', default='"Value"')
|
||||
Argument('const char*', 'sourceDescription', default='"Value"'),
|
||||
Argument('bool', 'passedToJSImpl', default='false')
|
||||
], body=body)
|
||||
|
||||
def initFromJSONMethod(self):
|
||||
@ -11322,7 +11375,8 @@ class CGDictionary(CGThing):
|
||||
# We need a holder name for external interfaces, but
|
||||
# it's scoped down to the conversion so we can just use
|
||||
# anything we want.
|
||||
"holderName": "holder"
|
||||
"holderName": "holder",
|
||||
"passedToJSImpl": "passedToJSImpl"
|
||||
}
|
||||
# We can't handle having a holderType here
|
||||
assert conversionInfo.holderType is None
|
||||
@ -11458,6 +11512,11 @@ class CGDictionary(CGThing):
|
||||
trace = CGGeneric('%s.TraceSelf(trc);\n' % memberData)
|
||||
if type.nullable():
|
||||
trace = CGIfWrapper(trace, "!%s.IsNull()" % memberNullable)
|
||||
elif type.isMozMap():
|
||||
# If you implement this, add a MozMap<object> to
|
||||
# TestInterfaceJSDictionary and test it in test_bug1036214.html
|
||||
# to make sure we end up with the correct security properties.
|
||||
assert False
|
||||
else:
|
||||
assert False # unknown type
|
||||
|
||||
@ -13389,7 +13448,8 @@ class CallbackMember(CGNativeMember):
|
||||
# We actually want to pass in a null scope object here, because
|
||||
# wrapping things into our current compartment (that of mCallback)
|
||||
# is what we want.
|
||||
"obj": "nullptr"
|
||||
"obj": "nullptr",
|
||||
"passedToJSImpl": "false"
|
||||
}
|
||||
|
||||
if isJSImplementedDescriptor(self.descriptorProvider):
|
||||
|
@ -58,3 +58,4 @@ MSG_DEF(MSG_HEADERS_IMMUTABLE, 0, "Headers are immutable and cannot be modified.
|
||||
MSG_DEF(MSG_INVALID_HEADER_NAME, 1, "{0} is an invalid header name.")
|
||||
MSG_DEF(MSG_INVALID_HEADER_VALUE, 1, "{0} is an invalid header value.")
|
||||
MSG_DEF(MSG_INVALID_HEADER_SEQUENCE, 0, "Headers require name/value tuples when being initialized by a sequence.")
|
||||
MSG_DEF(MSG_PERMISSION_DENIED_TO_PASS_ARG, 1, "Permission denied to pass cross-origin object as {0}.")
|
||||
|
Loading…
Reference in New Issue
Block a user