mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1051224 - Add an opt-out for cross-origin argument checking. r=gabor
This commit is contained in:
parent
eee8b5ab2e
commit
89f2ba9b62
@ -83,8 +83,12 @@ StackScopedCloneRead(JSContext *cx, JSStructuredCloneReader *reader, uint32_t ta
|
|||||||
if (!JS_WrapObject(cx, &obj))
|
if (!JS_WrapObject(cx, &obj))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
if (!xpc::NewFunctionForwarder(cx, JSID_VOIDHANDLE, obj, &functionValue))
|
FunctionForwarderOptions forwarderOptions;
|
||||||
|
if (!xpc::NewFunctionForwarder(cx, JSID_VOIDHANDLE, obj, forwarderOptions,
|
||||||
|
&functionValue))
|
||||||
|
{
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
return &functionValue.toObject();
|
return &functionValue.toObject();
|
||||||
}
|
}
|
||||||
@ -200,8 +204,13 @@ StackScopedClone(JSContext *cx, StackScopedCloneOptions &options,
|
|||||||
// Note - This function mirrors the logic of CheckPassToChrome in
|
// Note - This function mirrors the logic of CheckPassToChrome in
|
||||||
// ChromeObjectWrapper.cpp.
|
// ChromeObjectWrapper.cpp.
|
||||||
static bool
|
static bool
|
||||||
CheckSameOriginArg(JSContext *cx, HandleValue v)
|
CheckSameOriginArg(JSContext *cx, FunctionForwarderOptions &options, HandleValue v)
|
||||||
{
|
{
|
||||||
|
// Consumers can explicitly opt out of this security check. This is used in
|
||||||
|
// the web console to allow the utility functions to accept cross-origin Windows.
|
||||||
|
if (options.allowCrossOriginArguments)
|
||||||
|
return true;
|
||||||
|
|
||||||
// Primitives are fine.
|
// Primitives are fine.
|
||||||
if (!v.isObject())
|
if (!v.isObject())
|
||||||
return true;
|
return true;
|
||||||
@ -232,6 +241,13 @@ FunctionForwarder(JSContext *cx, unsigned argc, Value *vp)
|
|||||||
{
|
{
|
||||||
CallArgs args = CallArgsFromVp(argc, vp);
|
CallArgs args = CallArgsFromVp(argc, vp);
|
||||||
|
|
||||||
|
// Grab the options from the reserved slot.
|
||||||
|
RootedObject optionsObj(cx, &js::GetFunctionNativeReserved(&args.callee(), 1).toObject());
|
||||||
|
FunctionForwarderOptions options(cx, optionsObj);
|
||||||
|
if (!options.Parse())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Grab and unwrap the underlying callable.
|
||||||
RootedValue v(cx, js::GetFunctionNativeReserved(&args.callee(), 0));
|
RootedValue v(cx, js::GetFunctionNativeReserved(&args.callee(), 0));
|
||||||
RootedObject unwrappedFun(cx, js::UncheckedUnwrap(&v.toObject()));
|
RootedObject unwrappedFun(cx, js::UncheckedUnwrap(&v.toObject()));
|
||||||
|
|
||||||
@ -247,11 +263,11 @@ FunctionForwarder(JSContext *cx, unsigned argc, Value *vp)
|
|||||||
JSAutoCompartment ac(cx, unwrappedFun);
|
JSAutoCompartment ac(cx, unwrappedFun);
|
||||||
|
|
||||||
RootedValue thisVal(cx, ObjectValue(*thisObj));
|
RootedValue thisVal(cx, ObjectValue(*thisObj));
|
||||||
if (!CheckSameOriginArg(cx, thisVal) || !JS_WrapObject(cx, &thisObj))
|
if (!CheckSameOriginArg(cx, options, thisVal) || !JS_WrapObject(cx, &thisObj))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
for (size_t n = 0; n < args.length(); ++n) {
|
for (size_t n = 0; n < args.length(); ++n) {
|
||||||
if (!CheckSameOriginArg(cx, args[n]) || !JS_WrapValue(cx, args[n]))
|
if (!CheckSameOriginArg(cx, options, args[n]) || !JS_WrapValue(cx, args[n]))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -266,7 +282,7 @@ FunctionForwarder(JSContext *cx, unsigned argc, Value *vp)
|
|||||||
|
|
||||||
bool
|
bool
|
||||||
NewFunctionForwarder(JSContext *cx, HandleId idArg, HandleObject callable,
|
NewFunctionForwarder(JSContext *cx, HandleId idArg, HandleObject callable,
|
||||||
MutableHandleValue vp)
|
FunctionForwarderOptions &options, MutableHandleValue vp)
|
||||||
{
|
{
|
||||||
RootedId id(cx, idArg);
|
RootedId id(cx, idArg);
|
||||||
if (id == JSID_VOIDHANDLE)
|
if (id == JSID_VOIDHANDLE)
|
||||||
@ -277,8 +293,17 @@ NewFunctionForwarder(JSContext *cx, HandleId idArg, HandleObject callable,
|
|||||||
if (!fun)
|
if (!fun)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
JSObject *funobj = JS_GetFunctionObject(fun);
|
// Stash the callable in slot 0.
|
||||||
|
AssertSameCompartment(cx, callable);
|
||||||
|
RootedObject funobj(cx, JS_GetFunctionObject(fun));
|
||||||
js::SetFunctionNativeReserved(funobj, 0, ObjectValue(*callable));
|
js::SetFunctionNativeReserved(funobj, 0, ObjectValue(*callable));
|
||||||
|
|
||||||
|
// Stash the options in slot 1.
|
||||||
|
RootedObject optionsObj(cx, options.ToJSObject(cx));
|
||||||
|
if (!optionsObj)
|
||||||
|
return false;
|
||||||
|
js::SetFunctionNativeReserved(funobj, 1, ObjectValue(*optionsObj));
|
||||||
|
|
||||||
vp.setObject(*funobj);
|
vp.setObject(*funobj);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -349,7 +374,9 @@ ExportFunction(JSContext *cx, HandleValue vfunction, HandleValue vscope, HandleV
|
|||||||
|
|
||||||
// And now, let's create the forwarder function in the target compartment
|
// And now, let's create the forwarder function in the target compartment
|
||||||
// for the function the be exported.
|
// for the function the be exported.
|
||||||
if (!NewFunctionForwarder(cx, id, funObj, rval)) {
|
FunctionForwarderOptions forwarderOptions;
|
||||||
|
forwarderOptions.allowCrossOriginArguments = options.allowCrossOriginArguments;
|
||||||
|
if (!NewFunctionForwarder(cx, id, funObj, forwarderOptions, rval)) {
|
||||||
JS_ReportError(cx, "Exporting function failed");
|
JS_ReportError(cx, "Exporting function failed");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -3071,7 +3071,8 @@ nsXPCComponents_Utils::MakeObjectPropsNormal(HandleValue vobj, JSContext *cx)
|
|||||||
if (!js::IsWrapper(propobj) || !JS_ObjectIsCallable(cx, propobj))
|
if (!js::IsWrapper(propobj) || !JS_ObjectIsCallable(cx, propobj))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!NewFunctionForwarder(cx, id, propobj, &v) ||
|
FunctionForwarderOptions forwarderOptions;
|
||||||
|
if (!NewFunctionForwarder(cx, id, propobj, forwarderOptions, &v) ||
|
||||||
!JS_SetPropertyById(cx, obj, id, v))
|
!JS_SetPropertyById(cx, obj, id, v))
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
@ -3363,9 +3363,10 @@ Btoa(JSContext *cx, unsigned argc, jsval *vp);
|
|||||||
|
|
||||||
// Helper function that creates a JSFunction that wraps a native function that
|
// Helper function that creates a JSFunction that wraps a native function that
|
||||||
// forwards the call to the original 'callable'.
|
// forwards the call to the original 'callable'.
|
||||||
|
class FunctionForwarderOptions;
|
||||||
bool
|
bool
|
||||||
NewFunctionForwarder(JSContext *cx, JS::HandleId id, JS::HandleObject callable,
|
NewFunctionForwarder(JSContext *cx, JS::HandleId id, JS::HandleObject callable,
|
||||||
JS::MutableHandleValue vp);
|
FunctionForwarderOptions &options, JS::MutableHandleValue vp);
|
||||||
|
|
||||||
// Old fashioned xpc error reporter. Try to use JS_ReportError instead.
|
// Old fashioned xpc error reporter. Try to use JS_ReportError instead.
|
||||||
nsresult
|
nsresult
|
||||||
@ -3479,13 +3480,46 @@ public:
|
|||||||
JSObject* options = nullptr)
|
JSObject* options = nullptr)
|
||||||
: OptionsBase(cx, options)
|
: OptionsBase(cx, options)
|
||||||
, defineAs(cx, JSID_VOID)
|
, defineAs(cx, JSID_VOID)
|
||||||
|
, allowCrossOriginArguments(false)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
virtual bool Parse() {
|
virtual bool Parse() {
|
||||||
return ParseId("defineAs", &defineAs);
|
return ParseId("defineAs", &defineAs) &&
|
||||||
|
ParseBoolean("allowCrossOriginArguments", &allowCrossOriginArguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
JS::RootedId defineAs;
|
JS::RootedId defineAs;
|
||||||
|
bool allowCrossOriginArguments;
|
||||||
|
};
|
||||||
|
|
||||||
|
class MOZ_STACK_CLASS FunctionForwarderOptions : public OptionsBase {
|
||||||
|
public:
|
||||||
|
explicit FunctionForwarderOptions(JSContext *cx = xpc_GetSafeJSContext(),
|
||||||
|
JSObject* options = nullptr)
|
||||||
|
: OptionsBase(cx, options)
|
||||||
|
, allowCrossOriginArguments(false)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
JSObject *ToJSObject(JSContext *cx) {
|
||||||
|
JS::RootedObject global(cx, JS::CurrentGlobalOrNull(cx));
|
||||||
|
JS::RootedObject obj(cx, JS_NewObjectWithGivenProto(cx, nullptr, JS::NullPtr(), global));
|
||||||
|
if (!obj)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
JS::RootedValue val(cx);
|
||||||
|
unsigned attrs = JSPROP_READONLY | JSPROP_PERMANENT;
|
||||||
|
val = JS::BooleanValue(allowCrossOriginArguments);
|
||||||
|
if (!JS_DefineProperty(cx, obj, "allowCrossOriginArguments", val, attrs))
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool Parse() {
|
||||||
|
return ParseBoolean("allowCrossOriginArguments", &allowCrossOriginArguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool allowCrossOriginArguments;
|
||||||
};
|
};
|
||||||
|
|
||||||
class MOZ_STACK_CLASS StackScopedCloneOptions : public OptionsBase {
|
class MOZ_STACK_CLASS StackScopedCloneOptions : public OptionsBase {
|
||||||
|
@ -35,6 +35,7 @@ function run_test() {
|
|||||||
wasCalled = false;
|
wasCalled = false;
|
||||||
}
|
}
|
||||||
exportFunction(funToExport, subsb, { defineAs: "imported", allowCallbacks: true });
|
exportFunction(funToExport, subsb, { defineAs: "imported", allowCallbacks: true });
|
||||||
|
exportFunction((x) => x, subsb, { defineAs: "echoAllowXO", allowCallbacks: true, allowCrossOriginArguments: true });
|
||||||
}.toSource() + ")()", epsb);
|
}.toSource() + ")()", epsb);
|
||||||
|
|
||||||
subsb.xrayed = Cu.evalInSandbox("(" + function () {
|
subsb.xrayed = Cu.evalInSandbox("(" + function () {
|
||||||
@ -64,6 +65,15 @@ function run_test() {
|
|||||||
do_check_true(/denied|insecure/.test(e));
|
do_check_true(/denied|insecure/.test(e));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Callers can opt-out of the above.
|
||||||
|
subsb.xoNative = Cu.evalInSandbox('new XMLHttpRequest()', xorigsb);
|
||||||
|
try {
|
||||||
|
do_check_eq(Cu.evalInSandbox('echoAllowXO(xoNative)', subsb), subsb.xoNative);
|
||||||
|
do_check_true(true);
|
||||||
|
} catch (e) {
|
||||||
|
do_check_true(false);
|
||||||
|
}
|
||||||
|
|
||||||
// Apply should work and |this| should carry over appropriately.
|
// Apply should work and |this| should carry over appropriately.
|
||||||
Cu.evalInSandbox("(" + function() {
|
Cu.evalInSandbox("(" + function() {
|
||||||
var someThis = {};
|
var someThis = {};
|
||||||
|
Loading…
Reference in New Issue
Block a user