From 30d5135f6276c7bdf4ac78f67150a761e89dc4ff Mon Sep 17 00:00:00 2001 From: Jan de Mooij Date: Sat, 21 Jul 2018 14:34:58 +0200 Subject: [PATCH] Bug 1475559 part 6 - Add principals argument to SavedFrame APIs and do frame filtering based on it. r=bz This removes AutoMaybeEnterFrameRealm. Most places pass cx->realm->principals: it preserves behavior when the (possibly wrapped) SavedFrame and cx are same-compartment. The main exception is the JSStackFrame DOM bindings code where we have to be a bit smarter about which principals to use. --- .../DeserializedStackFrameUbiStackFrames.cpp | 11 +- dom/base/ChromeUtils.cpp | 7 +- dom/bindings/Exceptions.cpp | 71 +++++-- dom/bindings/nsScriptErrorWithStack.cpp | 11 +- js/src/jsapi-tests/testSavedStacks.cpp | 37 ++-- js/src/jsapi.cpp | 8 +- js/src/jsapi.h | 52 +++-- js/src/jsexn.cpp | 2 +- js/src/shell/js.cpp | 3 +- js/src/vm/ErrorObject.cpp | 6 +- js/src/vm/SavedStacks.cpp | 182 ++++++++---------- js/src/vm/SavedStacks.h | 2 +- js/xpconnect/src/XPCComponents.cpp | 6 +- 13 files changed, 226 insertions(+), 172 deletions(-) diff --git a/devtools/shared/heapsnapshot/tests/gtest/DeserializedStackFrameUbiStackFrames.cpp b/devtools/shared/heapsnapshot/tests/gtest/DeserializedStackFrameUbiStackFrames.cpp index 72e3639346c0..e1e46e7416ec 100644 --- a/devtools/shared/heapsnapshot/tests/gtest/DeserializedStackFrameUbiStackFrames.cpp +++ b/devtools/shared/heapsnapshot/tests/gtest/DeserializedStackFrameUbiStackFrames.cpp @@ -52,16 +52,21 @@ DEF_TEST(DeserializedStackFrameUbiStackFrames, { JS::RootedObject savedFrame(cx); EXPECT_TRUE(ubiFrame.constructSavedFrameStack(cx, &savedFrame)); + JSPrincipals* principals = JS::GetRealmPrincipals(js::GetContextRealm(cx)); + uint32_t frameLine; - ASSERT_EQ(JS::SavedFrameResult::Ok, JS::GetSavedFrameLine(cx, savedFrame, &frameLine)); + ASSERT_EQ(JS::SavedFrameResult::Ok, + JS::GetSavedFrameLine(cx, principals, savedFrame, &frameLine)); EXPECT_EQ(line, frameLine); uint32_t frameColumn; - ASSERT_EQ(JS::SavedFrameResult::Ok, JS::GetSavedFrameColumn(cx, savedFrame, &frameColumn)); + ASSERT_EQ(JS::SavedFrameResult::Ok, + JS::GetSavedFrameColumn(cx, principals, savedFrame, &frameColumn)); EXPECT_EQ(column, frameColumn); JS::RootedObject parent(cx); - ASSERT_EQ(JS::SavedFrameResult::Ok, JS::GetSavedFrameParent(cx, savedFrame, &parent)); + ASSERT_EQ(JS::SavedFrameResult::Ok, + JS::GetSavedFrameParent(cx, principals, savedFrame, &parent)); EXPECT_EQ(nullptr, parent); ASSERT_EQ(NS_strlen(source), 21U); diff --git a/dom/base/ChromeUtils.cpp b/dom/base/ChromeUtils.cpp index b3e20253ef42..0da7b43bf909 100644 --- a/dom/base/ChromeUtils.cpp +++ b/dom/base/ChromeUtils.cpp @@ -732,9 +732,10 @@ ChromeUtils::CreateError(const GlobalObject& aGlobal, const nsAString& aMessage, stack = UncheckedUnwrap(aStack); ar.emplace(cx, stack); - if (JS::GetSavedFrameLine(cx, stack, &line) != JS::SavedFrameResult::Ok || - JS::GetSavedFrameColumn(cx, stack, &column) != JS::SavedFrameResult::Ok || - JS::GetSavedFrameSource(cx, stack, &fileName) != JS::SavedFrameResult::Ok) { + JSPrincipals* principals = JS::GetRealmPrincipals(js::GetContextRealm(cx)); + if (JS::GetSavedFrameLine(cx, principals, stack, &line) != JS::SavedFrameResult::Ok || + JS::GetSavedFrameColumn(cx, principals, stack, &column) != JS::SavedFrameResult::Ok || + JS::GetSavedFrameSource(cx, principals, stack, &fileName) != JS::SavedFrameResult::Ok) { return; } } diff --git a/dom/bindings/Exceptions.cpp b/dom/bindings/Exceptions.cpp index 93bd57f24be1..9a641934d9ac 100644 --- a/dom/bindings/Exceptions.cpp +++ b/dom/bindings/Exceptions.cpp @@ -287,9 +287,54 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(JSStackFrame) NS_INTERFACE_MAP_ENTRY(nsISupports) NS_INTERFACE_MAP_END +// Helper method to determine the JSPrincipals* to pass to JS SavedFrame APIs. +// +// @argument aStack the stack we're working with; must be non-null. +// @argument [out] aCanCache whether we can use cached JSStackFrame values. +static JSPrincipals* +GetPrincipalsForStackGetter(JSContext* aCx, JS::Handle aStack, + bool* aCanCache) +{ + MOZ_ASSERT(JS::IsUnwrappedSavedFrame(aStack)); + + JSPrincipals* currentPrincipals = + JS::GetRealmPrincipals(js::GetContextRealm(aCx)); + JSPrincipals* stackPrincipals = + JS::GetRealmPrincipals(js::GetNonCCWObjectRealm(aStack)); + + // Fast path for when the principals are equal. This check is also necessary + // for workers: no nsIPrincipal there so we can't use the code below. + if (currentPrincipals == stackPrincipals) { + *aCanCache = true; + return stackPrincipals; + } + + MOZ_ASSERT(NS_IsMainThread()); + + if (nsJSPrincipals::get(currentPrincipals)->Subsumes( + nsJSPrincipals::get(stackPrincipals))) { + // The current principals subsume the stack's principals. In this case use + // the stack's principals: the idea is that this way devtools code that's + // asking an exception object for a stack to display will end up with the + // stack the web developer would see via doing .stack in a web page, with + // Firefox implementation details excluded. + + // Because we use the stack's principals and don't rely on the current + // context realm, we can use cached values. + *aCanCache = true; + return stackPrincipals; + } + + // The stack was captured in more-privileged code, so use the less privileged + // principals. Don't use cached values because we don't want these values to + // depend on the current realm/principals. + *aCanCache = false; + return currentPrincipals; +} + // Helper method to get the value of a stack property, if it's not already -// cached. This will make sure we skip the cache if the access is happening -// over Xrays. +// cached. This will make sure we skip the cache if the property value depends +// on the (current) context's realm/principals. // // @argument aStack the stack we're working with; must be non-null. // @argument aPropGetter the getter function to call. @@ -302,6 +347,7 @@ template static void GetValueIfNotCached(JSContext* aCx, const JS::Heap& aStack, JS::SavedFrameResult (*aPropGetter)(JSContext*, + JSPrincipals*, JS::Handle, GetterOutParamType, JS::SavedFrameSelfHosted), @@ -309,11 +355,11 @@ GetValueIfNotCached(JSContext* aCx, const JS::Heap& aStack, ReturnType aValue) { MOZ_ASSERT(aStack); + MOZ_ASSERT(JS::IsUnwrappedSavedFrame(aStack)); JS::Rooted stack(aCx, aStack); - // Allow caching if aCx and stack are same-compartment. Otherwise take the - // slow path. - *aCanCache = js::GetContextCompartment(aCx) == js::GetObjectCompartment(stack); + + JSPrincipals* principals = GetPrincipalsForStackGetter(aCx, stack, aCanCache); if (*aCanCache && aIsCached) { *aUseCachedValue = true; return; @@ -321,7 +367,8 @@ GetValueIfNotCached(JSContext* aCx, const JS::Heap& aStack, *aUseCachedValue = false; - aPropGetter(aCx, stack, aValue, JS::SavedFrameSelfHosted::Exclude); + aPropGetter(aCx, principals, stack, aValue, + JS::SavedFrameSelfHosted::Exclude); } NS_IMETHODIMP JSStackFrame::GetFilenameXPCOM(JSContext* aCx, nsAString& aFilename) @@ -613,19 +660,17 @@ JSStackFrame::GetFormattedStack(JSContext* aCx, nsAString& aStack) // make the templates more complicated to deal, but in the meantime // let's just inline GetValueIfNotCached here. - // Allow caching if aCx and stack are same-compartment. Otherwise take the - // slow path. - bool canCache = - js::GetContextCompartment(aCx) == js::GetObjectCompartment(mStack); + JS::Rooted stack(aCx, mStack); + + bool canCache; + JSPrincipals* principals = GetPrincipalsForStackGetter(aCx, stack, &canCache); if (canCache && mFormattedStackInitialized) { aStack = mFormattedStack; return; } - JS::Rooted stack(aCx, mStack); - JS::Rooted formattedStack(aCx); - if (!JS::BuildStackString(aCx, stack, &formattedStack)) { + if (!JS::BuildStackString(aCx, principals, stack, &formattedStack)) { JS_ClearPendingException(aCx); aStack.Truncate(); return; diff --git a/dom/bindings/nsScriptErrorWithStack.cpp b/dom/bindings/nsScriptErrorWithStack.cpp index 02bc5b005de7..f0b496a1b9aa 100644 --- a/dom/bindings/nsScriptErrorWithStack.cpp +++ b/dom/bindings/nsScriptErrorWithStack.cpp @@ -22,10 +22,10 @@ using namespace mozilla::dom; namespace { static nsCString -FormatStackString(JSContext* cx, JS::HandleObject aStack) { +FormatStackString(JSContext* cx, JSPrincipals* aPrincipals, JS::HandleObject aStack) +{ JS::RootedString formattedStack(cx); - - if (!JS::BuildStackString(cx, aStack, &formattedStack)) { + if (!JS::BuildStackString(cx, aPrincipals, aStack, &formattedStack)) { return nsCString(); } @@ -106,9 +106,12 @@ nsScriptErrorWithStack::ToString(nsACString& /*UTF8*/ aResult) return NS_ERROR_FAILURE; } + JSPrincipals* principals = + JS::GetRealmPrincipals(js::GetNonCCWObjectRealm(mStackGlobal)); + JSContext* cx = jsapi.cx(); JS::RootedObject stack(cx, mStack); - nsCString stackString = FormatStackString(cx, stack); + nsCString stackString = FormatStackString(cx, principals, stack); nsCString combined = message + NS_LITERAL_CSTRING("\n") + stackString; aResult.Assign(combined); diff --git a/js/src/jsapi-tests/testSavedStacks.cpp b/js/src/jsapi-tests/testSavedStacks.cpp index b7244acbba1b..b7c437af0551 100644 --- a/js/src/jsapi-tests/testSavedStacks.cpp +++ b/js/src/jsapi-tests/testSavedStacks.cpp @@ -27,37 +27,39 @@ BEGIN_TEST(testSavedStacks_ApiDefaultValues) { js::RootedSavedFrame savedFrame(cx, nullptr); + JSPrincipals* principals = cx->realm()->principals(); + // Source JS::RootedString str(cx); - JS::SavedFrameResult result = JS::GetSavedFrameSource(cx, savedFrame, &str); + JS::SavedFrameResult result = JS::GetSavedFrameSource(cx, principals, savedFrame, &str); CHECK(result == JS::SavedFrameResult::AccessDenied); CHECK(str.get() == cx->runtime()->emptyString); // Line uint32_t line = 123; - result = JS::GetSavedFrameLine(cx, savedFrame, &line); + result = JS::GetSavedFrameLine(cx, principals, savedFrame, &line); CHECK(result == JS::SavedFrameResult::AccessDenied); CHECK(line == 0); // Column uint32_t column = 123; - result = JS::GetSavedFrameColumn(cx, savedFrame, &column); + result = JS::GetSavedFrameColumn(cx, principals, savedFrame, &column); CHECK(result == JS::SavedFrameResult::AccessDenied); CHECK(column == 0); // Function display name - result = JS::GetSavedFrameFunctionDisplayName(cx, savedFrame, &str); + result = JS::GetSavedFrameFunctionDisplayName(cx, principals, savedFrame, &str); CHECK(result == JS::SavedFrameResult::AccessDenied); CHECK(str.get() == nullptr); // Parent JS::RootedObject parent(cx); - result = JS::GetSavedFrameParent(cx, savedFrame, &parent); + result = JS::GetSavedFrameParent(cx, principals, savedFrame, &parent); CHECK(result == JS::SavedFrameResult::AccessDenied); CHECK(parent.get() == nullptr); // Stack string - CHECK(JS::BuildStackString(cx, savedFrame, &str)); + CHECK(JS::BuildStackString(cx, principals, savedFrame, &str)); CHECK(str.get() == cx->runtime()->emptyString); return true; @@ -114,7 +116,8 @@ BEGIN_TEST(testSavedStacks_RangeBasedForLoops) auto CheckStacks = [&]() { for (auto& expectation : expectations) { JS::RootedString str(cx); - CHECK(JS::BuildStackString(cx, savedFrame, &str, 0, expectation.format)); + JSPrincipals* principals = cx->realm()->principals(); + CHECK(JS::BuildStackString(cx, principals, savedFrame, &str, 0, expectation.format)); JSLinearString* lin = str->ensureLinear(cx); CHECK(lin); CHECK(js::StringEqualsAscii(lin, expectation.expected)); @@ -225,9 +228,11 @@ BEGIN_TEST(testSavedStacks_selfHostedFrames) JS::Rooted selfHostedFrame(cx, savedFrame->getParent()); CHECK(selfHostedFrame->isSelfHosted(cx)); + JSPrincipals* principals = cx->realm()->principals(); + // Source JS::RootedString str(cx); - JS::SavedFrameResult result = JS::GetSavedFrameSource(cx, selfHostedFrame, &str, + JS::SavedFrameResult result = JS::GetSavedFrameSource(cx, principals, selfHostedFrame, &str, JS::SavedFrameSelfHosted::Exclude); CHECK(result == JS::SavedFrameResult::Ok); JSLinearString* lin = str->ensureLinear(cx); @@ -235,7 +240,8 @@ BEGIN_TEST(testSavedStacks_selfHostedFrames) CHECK(js::StringEqualsAscii(lin, "filename.js")); // Source, including self-hosted frames - result = JS::GetSavedFrameSource(cx, selfHostedFrame, &str, JS::SavedFrameSelfHosted::Include); + result = JS::GetSavedFrameSource(cx, principals, selfHostedFrame, &str, + JS::SavedFrameSelfHosted::Include); CHECK(result == JS::SavedFrameResult::Ok); lin = str->ensureLinear(cx); CHECK(lin); @@ -243,19 +249,20 @@ BEGIN_TEST(testSavedStacks_selfHostedFrames) // Line uint32_t line = 123; - result = JS::GetSavedFrameLine(cx, selfHostedFrame, &line, JS::SavedFrameSelfHosted::Exclude); + result = JS::GetSavedFrameLine(cx, principals, selfHostedFrame, &line, + JS::SavedFrameSelfHosted::Exclude); CHECK(result == JS::SavedFrameResult::Ok); CHECK_EQUAL(line, 3U); // Column uint32_t column = 123; - result = JS::GetSavedFrameColumn(cx, selfHostedFrame, &column, + result = JS::GetSavedFrameColumn(cx, principals, selfHostedFrame, &column, JS::SavedFrameSelfHosted::Exclude); CHECK(result == JS::SavedFrameResult::Ok); CHECK_EQUAL(column, 5U); // Function display name - result = JS::GetSavedFrameFunctionDisplayName(cx, selfHostedFrame, &str, + result = JS::GetSavedFrameFunctionDisplayName(cx, principals, selfHostedFrame, &str, JS::SavedFrameSelfHosted::Exclude); CHECK(result == JS::SavedFrameResult::Ok); lin = str->ensureLinear(cx); @@ -264,7 +271,8 @@ BEGIN_TEST(testSavedStacks_selfHostedFrames) // Parent JS::RootedObject parent(cx); - result = JS::GetSavedFrameParent(cx, savedFrame, &parent, JS::SavedFrameSelfHosted::Exclude); + result = JS::GetSavedFrameParent(cx, principals, savedFrame, &parent, + JS::SavedFrameSelfHosted::Exclude); CHECK(result == JS::SavedFrameResult::Ok); // JS::GetSavedFrameParent does this super funky and potentially unexpected // thing where it doesn't return the next subsumed parent but any next @@ -277,7 +285,8 @@ BEGIN_TEST(testSavedStacks_selfHostedFrames) // here is the selfHostedFrame's parent (because, as just explained, it // isn't) and instead check that asking for the source property gives us the // expected value. - result = JS::GetSavedFrameSource(cx, parent, &str, JS::SavedFrameSelfHosted::Exclude); + result = JS::GetSavedFrameSource(cx, principals, parent, &str, + JS::SavedFrameSelfHosted::Exclude); CHECK(result == JS::SavedFrameResult::Ok); lin = str->ensureLinear(cx); CHECK(lin); diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 0bb84150bbc4..65322f7243b7 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -5117,7 +5117,9 @@ JS_PUBLIC_API(void) JS::DumpPromiseAllocationSite(JSContext* cx, JS::HandleObject promise) { RootedObject stack(cx, promise->as().allocationSite()); - UniqueChars stackStr(reinterpret_cast(BuildUTF8StackString(cx, stack).get())); + JSPrincipals* principals = cx->realm()->principals(); + UniqueChars stackStr( + reinterpret_cast(BuildUTF8StackString(cx, principals, stack).get())); if (stackStr.get()) fputs(stackStr.get(), stderr); } @@ -5126,7 +5128,9 @@ JS_PUBLIC_API(void) JS::DumpPromiseResolutionSite(JSContext* cx, JS::HandleObject promise) { RootedObject stack(cx, promise->as().resolutionSite()); - UniqueChars stackStr(reinterpret_cast(BuildUTF8StackString(cx, stack).get())); + JSPrincipals* principals = cx->realm()->principals(); + UniqueChars stackStr( + reinterpret_cast(BuildUTF8StackString(cx, principals, stack).get())); if (stackStr.get()) fputs(stackStr.get(), stderr); } diff --git a/js/src/jsapi.h b/js/src/jsapi.h index a6b14833e4e0..44c4506ee259 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -6243,23 +6243,24 @@ CopyAsyncStack(JSContext* cx, HandleObject asyncStack, * and the object is not the SavedFrame.prototype object. * * Each of these functions will find the first SavedFrame object in the chain - * whose underlying stack frame principals are subsumed by the cx's current - * compartment's principals, and operate on that SavedFrame object. This - * prevents leaking information about privileged frames to un-privileged - * callers. As a result, the SavedFrame in parameters do _NOT_ need to be in the - * same compartment as the cx, and the various out parameters are _NOT_ - * guaranteed to be in the same compartment as cx. + * whose underlying stack frame principals are subsumed by the given + * |principals|, and operate on that SavedFrame object. This prevents leaking + * information about privileged frames to un-privileged callers + * + * The SavedFrame in parameters do _NOT_ need to be in the same compartment as + * the cx, and the various out parameters are _NOT_ guaranteed to be in the same + * compartment as cx. * * You may consider or skip over self-hosted frames by passing * `SavedFrameSelfHosted::Include` or `SavedFrameSelfHosted::Exclude` * respectively. * * Additionally, it may be the case that there is no such SavedFrame object - * whose captured frame's principals are subsumed by the caller's compartment's - * principals! If the `HandleObject savedFrame` argument is null, or the - * caller's principals do not subsume any of the chained SavedFrame object's - * principals, `SavedFrameResult::AccessDenied` is returned and a (hopefully) - * sane default value is chosen for the out param. + * whose captured frame's principals are subsumed by |principals|! If the + * `HandleObject savedFrame` argument is null, or the |principals| do not + * subsume any of the chained SavedFrame object's principals, + * `SavedFrameResult::AccessDenied` is returned and a (hopefully) sane default + * value is chosen for the out param. * * See also `js/src/doc/SavedFrame/SavedFrame.md`. */ @@ -6279,21 +6280,24 @@ enum class SavedFrameSelfHosted { * string. */ extern JS_PUBLIC_API(SavedFrameResult) -GetSavedFrameSource(JSContext* cx, HandleObject savedFrame, MutableHandleString sourcep, +GetSavedFrameSource(JSContext* cx, JSPrincipals* principals, HandleObject savedFrame, + MutableHandleString sourcep, SavedFrameSelfHosted selfHosted = SavedFrameSelfHosted::Include); /** * Given a SavedFrame JSObject, get its line property. Defaults to 0. */ extern JS_PUBLIC_API(SavedFrameResult) -GetSavedFrameLine(JSContext* cx, HandleObject savedFrame, uint32_t* linep, +GetSavedFrameLine(JSContext* cx, JSPrincipals* principals, HandleObject savedFrame, + uint32_t* linep, SavedFrameSelfHosted selfHosted = SavedFrameSelfHosted::Include); /** * Given a SavedFrame JSObject, get its column property. Defaults to 0. */ extern JS_PUBLIC_API(SavedFrameResult) -GetSavedFrameColumn(JSContext* cx, HandleObject savedFrame, uint32_t* columnp, +GetSavedFrameColumn(JSContext* cx, JSPrincipals* principals, HandleObject savedFrame, + uint32_t* columnp, SavedFrameSelfHosted selfHosted = SavedFrameSelfHosted::Include); /** @@ -6302,14 +6306,16 @@ GetSavedFrameColumn(JSContext* cx, HandleObject savedFrame, uint32_t* columnp, * function. Defaults to nullptr. */ extern JS_PUBLIC_API(SavedFrameResult) -GetSavedFrameFunctionDisplayName(JSContext* cx, HandleObject savedFrame, MutableHandleString namep, +GetSavedFrameFunctionDisplayName(JSContext* cx, JSPrincipals* principals, HandleObject savedFrame, + MutableHandleString namep, SavedFrameSelfHosted selfHosted = SavedFrameSelfHosted::Include); /** * Given a SavedFrame JSObject, get its asyncCause string. Defaults to nullptr. */ extern JS_PUBLIC_API(SavedFrameResult) -GetSavedFrameAsyncCause(JSContext* cx, HandleObject savedFrame, MutableHandleString asyncCausep, +GetSavedFrameAsyncCause(JSContext* cx, JSPrincipals* principals, HandleObject savedFrame, + MutableHandleString asyncCausep, SavedFrameSelfHosted selfHosted = SavedFrameSelfHosted::Include); /** @@ -6318,8 +6324,9 @@ GetSavedFrameAsyncCause(JSContext* cx, HandleObject savedFrame, MutableHandleStr * guaranteed to be in the cx's compartment. Defaults to nullptr. */ extern JS_PUBLIC_API(SavedFrameResult) -GetSavedFrameAsyncParent(JSContext* cx, HandleObject savedFrame, MutableHandleObject asyncParentp, - SavedFrameSelfHosted selfHosted = SavedFrameSelfHosted::Include); +GetSavedFrameAsyncParent(JSContext* cx, JSPrincipals* principals, HandleObject savedFrame, + MutableHandleObject asyncParentp, + SavedFrameSelfHosted selfHosted = SavedFrameSelfHosted::Include); /** * Given a SavedFrame JSObject, get its parent SavedFrame object or nullptr if @@ -6327,7 +6334,8 @@ GetSavedFrameAsyncParent(JSContext* cx, HandleObject savedFrame, MutableHandleOb * guaranteed to be in the cx's compartment. Defaults to nullptr. */ extern JS_PUBLIC_API(SavedFrameResult) -GetSavedFrameParent(JSContext* cx, HandleObject savedFrame, MutableHandleObject parentp, +GetSavedFrameParent(JSContext* cx, JSPrincipals* principals, HandleObject savedFrame, + MutableHandleObject parentp, SavedFrameSelfHosted selfHosted = SavedFrameSelfHosted::Include); /** @@ -6338,13 +6346,15 @@ GetSavedFrameParent(JSContext* cx, HandleObject savedFrame, MutableHandleObject * The same notes above about SavedFrame accessors applies here as well: cx * doesn't need to be in stack's compartment, and stack can be null, a * SavedFrame object, or a wrapper (CCW or Xray) around a SavedFrame object. + * SavedFrames not subsumed by |principals| are skipped. * * Optional indent parameter specifies the number of white spaces to indent * each line. */ extern JS_PUBLIC_API(bool) -BuildStackString(JSContext* cx, HandleObject stack, MutableHandleString stringp, - size_t indent = 0, js::StackFormat stackFormat = js::StackFormat::Default); +BuildStackString(JSContext* cx, JSPrincipals* principals, HandleObject stack, + MutableHandleString stringp, size_t indent = 0, + js::StackFormat stackFormat = js::StackFormat::Default); /** * Return true iff the given object is either a SavedFrame object or wrapper diff --git a/js/src/jsexn.cpp b/js/src/jsexn.cpp index 6560c94d2cd0..200065049d06 100644 --- a/js/src/jsexn.cpp +++ b/js/src/jsexn.cpp @@ -379,7 +379,7 @@ js::ComputeStackString(JSContext* cx) return nullptr; RootedString str(cx); - if (!BuildStackString(cx, stack, &str)) + if (!BuildStackString(cx, cx->realm()->principals(), stack, &str)) return nullptr; return str.get(); diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index 783916b9b7ec..8e0daad965b3 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -7686,8 +7686,9 @@ PrintStackTrace(JSContext* cx, HandleValue exn) if (!stackObj) return true; + JSPrincipals* principals = exnObj->as().realm()->principals(); RootedString stackStr(cx); - if (!BuildStackString(cx, stackObj, &stackStr, 2)) + if (!BuildStackString(cx, principals, stackObj, &stackStr, 2)) return false; UniqueChars stack(JS_EncodeStringToUTF8(cx, stackStr)); diff --git a/js/src/vm/ErrorObject.cpp b/js/src/vm/ErrorObject.cpp index 307ac897ec80..abd1418c995d 100644 --- a/js/src/vm/ErrorObject.cpp +++ b/js/src/vm/ErrorObject.cpp @@ -236,9 +236,13 @@ js::ErrorObject::getStack_impl(JSContext* cx, const CallArgs& args) return true; } + // Do frame filtering based on the ErrorObject's principals. This ensures we + // don't see chrome frames when chrome code accesses .stack over Xrays. + JSPrincipals* principals = obj->as().realm()->principals(); + RootedObject savedFrameObj(cx, obj->as().stack()); RootedString stackString(cx); - if (!BuildStackString(cx, savedFrameObj, &stackString)) + if (!BuildStackString(cx, principals, savedFrameObj, &stackString)) return false; if (cx->runtime()->stackFormat() == js::StackFormat::V8) { diff --git a/js/src/vm/SavedStacks.cpp b/js/src/vm/SavedStacks.cpp index df1776110a5e..2b3fcb252bff 100644 --- a/js/src/vm/SavedStacks.cpp +++ b/js/src/vm/SavedStacks.cpp @@ -607,14 +607,13 @@ SavedFrame::construct(JSContext* cx, unsigned argc, Value* vp) } static bool -SavedFrameSubsumedByCaller(JSContext* cx, HandleSavedFrame frame) +SavedFrameSubsumedByPrincipals(JSContext* cx, JSPrincipals* principals, HandleSavedFrame frame) { auto subsumes = cx->runtime()->securityCallbacks->subsumes; if (!subsumes) return true; - auto currentRealmPrincipals = cx->realm()->principals(); - MOZ_ASSERT(!ReconstructedSavedFramePrincipals::is(currentRealmPrincipals)); + MOZ_ASSERT(!ReconstructedSavedFramePrincipals::is(principals)); auto framePrincipals = frame->getPrincipals(); @@ -625,7 +624,7 @@ SavedFrameSubsumedByCaller(JSContext* cx, HandleSavedFrame frame) if (framePrincipals == &ReconstructedSavedFramePrincipals::IsNotSystem) return true; - return subsumes(currentRealmPrincipals, framePrincipals); + return subsumes(principals, framePrincipals); } // Return the first SavedFrame in the chain that starts with |frame| whose @@ -634,7 +633,7 @@ SavedFrameSubsumedByCaller(JSContext* cx, HandleSavedFrame frame) // had the |asyncCause| property set, otherwise it is explicitly set to false. template static SavedFrame* -GetFirstMatchedFrame(JSContext* cx, Matcher& matches, +GetFirstMatchedFrame(JSContext* cx, JSPrincipals* principals, Matcher& matches, HandleSavedFrame frame, JS::SavedFrameSelfHosted selfHosted, bool& skippedAsync) { @@ -644,7 +643,7 @@ GetFirstMatchedFrame(JSContext* cx, Matcher& matches, while (rootedFrame) { if ((selfHosted == JS::SavedFrameSelfHosted::Include || !rootedFrame->isSelfHosted(cx)) && - matches(cx, rootedFrame)) + matches(cx, principals, rootedFrame)) { return rootedFrame; } @@ -659,15 +658,16 @@ GetFirstMatchedFrame(JSContext* cx, Matcher& matches, } // Return the first SavedFrame in the chain that starts with |frame| whose -// principals are subsumed by the principals of the context's current -// compartment, according to |subsumes|. If there is no such frame, return -// nullptr. |skippedAsync| is set to true if any of the skipped frames had the -// |asyncCause| property set, otherwise it is explicitly set to false. +// principals are subsumed by |principals|, according to |subsumes|. If there is +// no such frame, return nullptr. |skippedAsync| is set to true if any of the +// skipped frames had the |asyncCause| property set, otherwise it is explicitly +// set to false. static SavedFrame* -GetFirstSubsumedFrame(JSContext* cx, HandleSavedFrame frame, JS::SavedFrameSelfHosted selfHosted, - bool& skippedAsync) +GetFirstSubsumedFrame(JSContext* cx, JSPrincipals* principals, HandleSavedFrame frame, + JS::SavedFrameSelfHosted selfHosted, bool& skippedAsync) { - return GetFirstMatchedFrame(cx, SavedFrameSubsumedByCaller, frame, selfHosted, skippedAsync); + return GetFirstMatchedFrame(cx, principals, SavedFrameSubsumedByPrincipals, frame, selfHosted, + skippedAsync); } JS_FRIEND_API(JSObject*) @@ -682,13 +682,14 @@ GetFirstSubsumedSavedFrame(JSContext* cx, JSPrincipals* principals, if (!subsumes) return nullptr; - auto matcher = [&](JSContext* cx, HandleSavedFrame frame) -> bool { + auto matcher = + [subsumes](JSContext* cx, JSPrincipals* principals, HandleSavedFrame frame) -> bool { return subsumes(principals, frame->getPrincipals()); }; bool skippedAsync; RootedSavedFrame frame(cx, &savedFrame->as()); - return GetFirstMatchedFrame(cx, matcher, frame, selfHosted, skippedAsync); + return GetFirstMatchedFrame(cx, principals, matcher, frame, selfHosted, skippedAsync); } static MOZ_MUST_USE bool @@ -748,56 +749,9 @@ SavedFrame_checkThis(JSContext* cx, CallArgs& args, const char* fnName, namespace JS { -namespace { - -// It's possible that our caller is privileged (and hence would see the entire -// stack) but we're working with an SavedFrame object that was captured in -// unprivileged code. If so, drop privileges down to its level. The idea is -// that this way devtools code that's asking an exception object for a stack to -// display will end up with the stack the web developer would see via doing -// .stack in a web page, with Firefox implementation details excluded. -// -// We want callers to pass us the object they were actually passed, not an -// unwrapped form of it. That way Xray access to SavedFrame objects should not -// be affected by AutoMaybeEnterFrameRealm and the only things that will -// be affected will be cases in which privileged code works with some C++ object -// that then pokes at an unprivileged StackFrame it has on hand. -class MOZ_STACK_CLASS AutoMaybeEnterFrameRealm -{ -public: - AutoMaybeEnterFrameRealm(JSContext* cx, - HandleObject obj - MOZ_GUARD_OBJECT_NOTIFIER_PARAM) - { - MOZ_GUARD_OBJECT_NOTIFIER_INIT; - - MOZ_RELEASE_ASSERT(cx->realm()); - if (obj) - MOZ_RELEASE_ASSERT(obj->deprecatedRealm()); - - // Note that obj might be null here, since we're doing this before - // UnwrapSavedFrame. - if (obj && cx->realm() != obj->deprecatedRealm()) - { - JSSubsumesOp subsumes = cx->runtime()->securityCallbacks->subsumes; - if (subsumes && subsumes(cx->realm()->principals(), - obj->deprecatedRealm()->principals())) - { - ar_.emplace(cx, obj); - } - } - } - - private: - Maybe ar_; - MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER -}; - -} // namespace - static inline js::SavedFrame* -UnwrapSavedFrame(JSContext* cx, HandleObject obj, SavedFrameSelfHosted selfHosted, - bool& skippedAsync) +UnwrapSavedFrame(JSContext* cx, JSPrincipals* principals, HandleObject obj, + SavedFrameSelfHosted selfHosted, bool& skippedAsync) { if (!obj) return nullptr; @@ -808,11 +762,12 @@ UnwrapSavedFrame(JSContext* cx, HandleObject obj, SavedFrameSelfHosted selfHoste MOZ_RELEASE_ASSERT(js::SavedFrame::isSavedFrameAndNotProto(*savedFrameObj)); js::RootedSavedFrame frame(cx, &savedFrameObj->as()); - return GetFirstSubsumedFrame(cx, frame, selfHosted, skippedAsync); + return GetFirstSubsumedFrame(cx, principals, frame, selfHosted, skippedAsync); } JS_PUBLIC_API(SavedFrameResult) -GetSavedFrameSource(JSContext* cx, HandleObject savedFrame, MutableHandleString sourcep, +GetSavedFrameSource(JSContext* cx, JSPrincipals* principals, HandleObject savedFrame, + MutableHandleString sourcep, SavedFrameSelfHosted selfHosted /* = SavedFrameSelfHosted::Include */) { js::AssertHeapIsIdle(); @@ -820,9 +775,9 @@ GetSavedFrameSource(JSContext* cx, HandleObject savedFrame, MutableHandleString MOZ_RELEASE_ASSERT(cx->realm()); { - AutoMaybeEnterFrameRealm ar(cx, savedFrame); bool skippedAsync; - js::RootedSavedFrame frame(cx, UnwrapSavedFrame(cx, savedFrame, selfHosted, skippedAsync)); + js::RootedSavedFrame frame(cx, UnwrapSavedFrame(cx, principals, savedFrame, selfHosted, + skippedAsync)); if (!frame) { sourcep.set(cx->runtime()->emptyString); return SavedFrameResult::AccessDenied; @@ -835,7 +790,8 @@ GetSavedFrameSource(JSContext* cx, HandleObject savedFrame, MutableHandleString } JS_PUBLIC_API(SavedFrameResult) -GetSavedFrameLine(JSContext* cx, HandleObject savedFrame, uint32_t* linep, +GetSavedFrameLine(JSContext* cx, JSPrincipals* principals, HandleObject savedFrame, + uint32_t* linep, SavedFrameSelfHosted selfHosted /* = SavedFrameSelfHosted::Include */) { js::AssertHeapIsIdle(); @@ -843,9 +799,9 @@ GetSavedFrameLine(JSContext* cx, HandleObject savedFrame, uint32_t* linep, MOZ_RELEASE_ASSERT(cx->realm()); MOZ_ASSERT(linep); - AutoMaybeEnterFrameRealm ar(cx, savedFrame); bool skippedAsync; - js::RootedSavedFrame frame(cx, UnwrapSavedFrame(cx, savedFrame, selfHosted, skippedAsync)); + js::RootedSavedFrame frame(cx, UnwrapSavedFrame(cx, principals, savedFrame, selfHosted, + skippedAsync)); if (!frame) { *linep = 0; return SavedFrameResult::AccessDenied; @@ -855,7 +811,8 @@ GetSavedFrameLine(JSContext* cx, HandleObject savedFrame, uint32_t* linep, } JS_PUBLIC_API(SavedFrameResult) -GetSavedFrameColumn(JSContext* cx, HandleObject savedFrame, uint32_t* columnp, +GetSavedFrameColumn(JSContext* cx, JSPrincipals* principals, HandleObject savedFrame, + uint32_t* columnp, SavedFrameSelfHosted selfHosted /* = SavedFrameSelfHosted::Include */) { js::AssertHeapIsIdle(); @@ -863,9 +820,9 @@ GetSavedFrameColumn(JSContext* cx, HandleObject savedFrame, uint32_t* columnp, MOZ_RELEASE_ASSERT(cx->realm()); MOZ_ASSERT(columnp); - AutoMaybeEnterFrameRealm ar(cx, savedFrame); bool skippedAsync; - js::RootedSavedFrame frame(cx, UnwrapSavedFrame(cx, savedFrame, selfHosted, skippedAsync)); + js::RootedSavedFrame frame(cx, UnwrapSavedFrame(cx, principals, savedFrame, selfHosted, + skippedAsync)); if (!frame) { *columnp = 0; return SavedFrameResult::AccessDenied; @@ -875,7 +832,8 @@ GetSavedFrameColumn(JSContext* cx, HandleObject savedFrame, uint32_t* columnp, } JS_PUBLIC_API(SavedFrameResult) -GetSavedFrameFunctionDisplayName(JSContext* cx, HandleObject savedFrame, MutableHandleString namep, +GetSavedFrameFunctionDisplayName(JSContext* cx, JSPrincipals* principals, HandleObject savedFrame, + MutableHandleString namep, SavedFrameSelfHosted selfHosted /* = SavedFrameSelfHosted::Include */) { js::AssertHeapIsIdle(); @@ -883,9 +841,9 @@ GetSavedFrameFunctionDisplayName(JSContext* cx, HandleObject savedFrame, Mutable MOZ_RELEASE_ASSERT(cx->realm()); { - AutoMaybeEnterFrameRealm ar(cx, savedFrame); bool skippedAsync; - js::RootedSavedFrame frame(cx, UnwrapSavedFrame(cx, savedFrame, selfHosted, skippedAsync)); + js::RootedSavedFrame frame(cx, UnwrapSavedFrame(cx, principals, savedFrame, selfHosted, + skippedAsync)); if (!frame) { namep.set(nullptr); return SavedFrameResult::AccessDenied; @@ -898,7 +856,8 @@ GetSavedFrameFunctionDisplayName(JSContext* cx, HandleObject savedFrame, Mutable } JS_PUBLIC_API(SavedFrameResult) -GetSavedFrameAsyncCause(JSContext* cx, HandleObject savedFrame, MutableHandleString asyncCausep, +GetSavedFrameAsyncCause(JSContext* cx, JSPrincipals* principals, HandleObject savedFrame, + MutableHandleString asyncCausep, SavedFrameSelfHosted unused_ /* = SavedFrameSelfHosted::Include */) { js::AssertHeapIsIdle(); @@ -906,14 +865,14 @@ GetSavedFrameAsyncCause(JSContext* cx, HandleObject savedFrame, MutableHandleStr MOZ_RELEASE_ASSERT(cx->realm()); { - AutoMaybeEnterFrameRealm ar(cx, savedFrame); bool skippedAsync; // This function is always called with self-hosted frames excluded by // GetValueIfNotCached in dom/bindings/Exceptions.cpp. However, we want // to include them because our Promise implementation causes us to have // the async cause on a self-hosted frame. So we just ignore the // parameter and always include self-hosted frames. - js::RootedSavedFrame frame(cx, UnwrapSavedFrame(cx, savedFrame, SavedFrameSelfHosted::Include, + js::RootedSavedFrame frame(cx, UnwrapSavedFrame(cx, principals, savedFrame, + SavedFrameSelfHosted::Include, skippedAsync)); if (!frame) { asyncCausep.set(nullptr); @@ -929,16 +888,17 @@ GetSavedFrameAsyncCause(JSContext* cx, HandleObject savedFrame, MutableHandleStr } JS_PUBLIC_API(SavedFrameResult) -GetSavedFrameAsyncParent(JSContext* cx, HandleObject savedFrame, MutableHandleObject asyncParentp, +GetSavedFrameAsyncParent(JSContext* cx, JSPrincipals* principals, HandleObject savedFrame, + MutableHandleObject asyncParentp, SavedFrameSelfHosted selfHosted /* = SavedFrameSelfHosted::Include */) { js::AssertHeapIsIdle(); CHECK_REQUEST(cx); MOZ_RELEASE_ASSERT(cx->realm()); - AutoMaybeEnterFrameRealm ar(cx, savedFrame); bool skippedAsync; - js::RootedSavedFrame frame(cx, UnwrapSavedFrame(cx, savedFrame, selfHosted, skippedAsync)); + js::RootedSavedFrame frame(cx, UnwrapSavedFrame(cx, principals, savedFrame, selfHosted, + skippedAsync)); if (!frame) { asyncParentp.set(nullptr); return SavedFrameResult::AccessDenied; @@ -948,8 +908,8 @@ GetSavedFrameAsyncParent(JSContext* cx, HandleObject savedFrame, MutableHandleOb // The current value of |skippedAsync| is not interesting, because we are // interested in whether we would cross any async parents to get from here // to the first subsumed parent frame instead. - js::RootedSavedFrame subsumedParent(cx, GetFirstSubsumedFrame(cx, parent, selfHosted, - skippedAsync)); + js::RootedSavedFrame subsumedParent(cx, GetFirstSubsumedFrame(cx, principals, parent, + selfHosted, skippedAsync)); // Even if |parent| is not subsumed, we still want to return a pointer to it // rather than |subsumedParent| so it can pick up any |asyncCause| from the @@ -962,16 +922,17 @@ GetSavedFrameAsyncParent(JSContext* cx, HandleObject savedFrame, MutableHandleOb } JS_PUBLIC_API(SavedFrameResult) -GetSavedFrameParent(JSContext* cx, HandleObject savedFrame, MutableHandleObject parentp, +GetSavedFrameParent(JSContext* cx, JSPrincipals* principals, HandleObject savedFrame, + MutableHandleObject parentp, SavedFrameSelfHosted selfHosted /* = SavedFrameSelfHosted::Include */) { js::AssertHeapIsIdle(); CHECK_REQUEST(cx); MOZ_RELEASE_ASSERT(cx->realm()); - AutoMaybeEnterFrameRealm ar(cx, savedFrame); bool skippedAsync; - js::RootedSavedFrame frame(cx, UnwrapSavedFrame(cx, savedFrame, selfHosted, skippedAsync)); + js::RootedSavedFrame frame(cx, UnwrapSavedFrame(cx, principals, savedFrame, selfHosted, + skippedAsync)); if (!frame) { parentp.set(nullptr); return SavedFrameResult::AccessDenied; @@ -981,8 +942,8 @@ GetSavedFrameParent(JSContext* cx, HandleObject savedFrame, MutableHandleObject // The current value of |skippedAsync| is not interesting, because we are // interested in whether we would cross any async parents to get from here // to the first subsumed parent frame instead. - js::RootedSavedFrame subsumedParent(cx, GetFirstSubsumedFrame(cx, parent, selfHosted, - skippedAsync)); + js::RootedSavedFrame subsumedParent(cx, GetFirstSubsumedFrame(cx, principals, parent, + selfHosted, skippedAsync)); // Even if |parent| is not subsumed, we still want to return a pointer to it // rather than |subsumedParent| so it can pick up any |asyncCause| from the @@ -1068,8 +1029,8 @@ FormatV8StackFrame(JSContext* cx, js::StringBuffer& sb, } JS_PUBLIC_API(bool) -BuildStackString(JSContext* cx, HandleObject stack, MutableHandleString stringp, - size_t indent, js::StackFormat format) +BuildStackString(JSContext* cx, JSPrincipals* principals, HandleObject stack, + MutableHandleString stringp, size_t indent, js::StackFormat format) { js::AssertHeapIsIdle(); CHECK_REQUEST(cx); @@ -1086,9 +1047,9 @@ BuildStackString(JSContext* cx, HandleObject stack, MutableHandleString stringp, // the cx's original compartment, and fulfill our contract with callers to // place the output string in the cx's current realm. { - AutoMaybeEnterFrameRealm ar(cx, stack); bool skippedAsync; - js::RootedSavedFrame frame(cx, UnwrapSavedFrame(cx, stack, SavedFrameSelfHosted::Exclude, + js::RootedSavedFrame frame(cx, UnwrapSavedFrame(cx, principals, stack, + SavedFrameSelfHosted::Exclude, skippedAsync)); if (!frame) { stringp.set(cx->runtime()->emptyString); @@ -1097,12 +1058,12 @@ BuildStackString(JSContext* cx, HandleObject stack, MutableHandleString stringp, js::RootedSavedFrame parent(cx); do { - MOZ_ASSERT(SavedFrameSubsumedByCaller(cx, frame)); + MOZ_ASSERT(SavedFrameSubsumedByPrincipals(cx, principals, frame)); MOZ_ASSERT(!frame->isSelfHosted(cx)); parent = frame->getParent(); bool skippedNextAsync; - js::RootedSavedFrame nextFrame(cx, js::GetFirstSubsumedFrame(cx, parent, + js::RootedSavedFrame nextFrame(cx, js::GetFirstSubsumedFrame(cx, principals, parent, SavedFrameSelfHosted::Exclude, skippedNextAsync)); switch (format) { @@ -1154,8 +1115,9 @@ namespace js { SavedFrame::sourceProperty(JSContext* cx, unsigned argc, Value* vp) { THIS_SAVEDFRAME(cx, argc, vp, "(get source)", args, frame); + JSPrincipals* principals = cx->realm()->principals(); RootedString source(cx); - if (JS::GetSavedFrameSource(cx, frame, &source) == JS::SavedFrameResult::Ok) { + if (JS::GetSavedFrameSource(cx, principals, frame, &source) == JS::SavedFrameResult::Ok) { if (!cx->compartment()->wrap(cx, &source)) return false; args.rval().setString(source); @@ -1169,8 +1131,9 @@ SavedFrame::sourceProperty(JSContext* cx, unsigned argc, Value* vp) SavedFrame::lineProperty(JSContext* cx, unsigned argc, Value* vp) { THIS_SAVEDFRAME(cx, argc, vp, "(get line)", args, frame); + JSPrincipals* principals = cx->realm()->principals(); uint32_t line; - if (JS::GetSavedFrameLine(cx, frame, &line) == JS::SavedFrameResult::Ok) + if (JS::GetSavedFrameLine(cx, principals, frame, &line) == JS::SavedFrameResult::Ok) args.rval().setNumber(line); else args.rval().setNull(); @@ -1181,8 +1144,9 @@ SavedFrame::lineProperty(JSContext* cx, unsigned argc, Value* vp) SavedFrame::columnProperty(JSContext* cx, unsigned argc, Value* vp) { THIS_SAVEDFRAME(cx, argc, vp, "(get column)", args, frame); + JSPrincipals* principals = cx->realm()->principals(); uint32_t column; - if (JS::GetSavedFrameColumn(cx, frame, &column) == JS::SavedFrameResult::Ok) + if (JS::GetSavedFrameColumn(cx, principals, frame, &column) == JS::SavedFrameResult::Ok) args.rval().setNumber(column); else args.rval().setNull(); @@ -1193,8 +1157,10 @@ SavedFrame::columnProperty(JSContext* cx, unsigned argc, Value* vp) SavedFrame::functionDisplayNameProperty(JSContext* cx, unsigned argc, Value* vp) { THIS_SAVEDFRAME(cx, argc, vp, "(get functionDisplayName)", args, frame); + JSPrincipals* principals = cx->realm()->principals(); RootedString name(cx); - JS::SavedFrameResult result = JS::GetSavedFrameFunctionDisplayName(cx, frame, &name); + JS::SavedFrameResult result = + JS::GetSavedFrameFunctionDisplayName(cx, principals, frame, &name); if (result == JS::SavedFrameResult::Ok && name) { if (!cx->compartment()->wrap(cx, &name)) return false; @@ -1209,8 +1175,9 @@ SavedFrame::functionDisplayNameProperty(JSContext* cx, unsigned argc, Value* vp) SavedFrame::asyncCauseProperty(JSContext* cx, unsigned argc, Value* vp) { THIS_SAVEDFRAME(cx, argc, vp, "(get asyncCause)", args, frame); + JSPrincipals* principals = cx->realm()->principals(); RootedString asyncCause(cx); - JS::SavedFrameResult result = JS::GetSavedFrameAsyncCause(cx, frame, &asyncCause); + JS::SavedFrameResult result = JS::GetSavedFrameAsyncCause(cx, principals, frame, &asyncCause); if (result == JS::SavedFrameResult::Ok && asyncCause) { if (!cx->compartment()->wrap(cx, &asyncCause)) return false; @@ -1225,8 +1192,9 @@ SavedFrame::asyncCauseProperty(JSContext* cx, unsigned argc, Value* vp) SavedFrame::asyncParentProperty(JSContext* cx, unsigned argc, Value* vp) { THIS_SAVEDFRAME(cx, argc, vp, "(get asyncParent)", args, frame); + JSPrincipals* principals = cx->realm()->principals(); RootedObject asyncParent(cx); - (void) JS::GetSavedFrameAsyncParent(cx, frame, &asyncParent); + (void) JS::GetSavedFrameAsyncParent(cx, principals, frame, &asyncParent); if (!cx->compartment()->wrap(cx, &asyncParent)) return false; args.rval().setObjectOrNull(asyncParent); @@ -1237,8 +1205,9 @@ SavedFrame::asyncParentProperty(JSContext* cx, unsigned argc, Value* vp) SavedFrame::parentProperty(JSContext* cx, unsigned argc, Value* vp) { THIS_SAVEDFRAME(cx, argc, vp, "(get parent)", args, frame); + JSPrincipals* principals = cx->realm()->principals(); RootedObject parent(cx); - (void) JS::GetSavedFrameParent(cx, frame, &parent); + (void) JS::GetSavedFrameParent(cx, principals, frame, &parent); if (!cx->compartment()->wrap(cx, &parent)) return false; args.rval().setObjectOrNull(parent); @@ -1249,8 +1218,9 @@ SavedFrame::parentProperty(JSContext* cx, unsigned argc, Value* vp) SavedFrame::toStringMethod(JSContext* cx, unsigned argc, Value* vp) { THIS_SAVEDFRAME(cx, argc, vp, "toString", args, frame); + JSPrincipals* principals = cx->realm()->principals(); RootedString string(cx); - if (!JS::BuildStackString(cx, frame, &string)) + if (!JS::BuildStackString(cx, principals, frame, &string)) return false; args.rval().setString(string); return true; @@ -1860,10 +1830,10 @@ const SavedStacks::MetadataBuilder SavedStacks::metadataBuilder; /* static */ ReconstructedSavedFramePrincipals ReconstructedSavedFramePrincipals::IsNotSystem; UTF8CharsZ -BuildUTF8StackString(JSContext* cx, HandleObject stack) +BuildUTF8StackString(JSContext* cx, JSPrincipals* principals, HandleObject stack) { RootedString stackStr(cx); - if (!JS::BuildStackString(cx, stack, &stackStr)) + if (!JS::BuildStackString(cx, principals, stack, &stackStr)) return UTF8CharsZ(); char* chars = JS_EncodeStringToUTF8(cx, stackStr); diff --git a/js/src/vm/SavedStacks.h b/js/src/vm/SavedStacks.h index 687802fc1279..571dbd65ecfa 100644 --- a/js/src/vm/SavedStacks.h +++ b/js/src/vm/SavedStacks.h @@ -323,7 +323,7 @@ struct MutableWrappedPtrOperations }; UTF8CharsZ -BuildUTF8StackString(JSContext* cx, HandleObject stack); +BuildUTF8StackString(JSContext* cx, JSPrincipals* principals, HandleObject stack); uint32_t FixupColumnForDisplay(uint32_t column); diff --git a/js/xpconnect/src/XPCComponents.cpp b/js/xpconnect/src/XPCComponents.cpp index ddb951ad1cde..3074181fffe1 100644 --- a/js/xpconnect/src/XPCComponents.cpp +++ b/js/xpconnect/src/XPCComponents.cpp @@ -2063,13 +2063,15 @@ nsXPCComponents_Utils::ReportError(HandleValue error, HandleValue stack, JSConte stackGlobal = JS::CurrentGlobalOrNull(cx); js::AssertSameCompartment(stackObj, stackGlobal); - if (GetSavedFrameLine(cx, stackObj, &lineNo) != SavedFrameResult::Ok) { + JSPrincipals* principals = JS::GetRealmPrincipals(js::GetContextRealm(cx)); + + if (GetSavedFrameLine(cx, principals, stackObj, &lineNo) != SavedFrameResult::Ok) { JS_ClearPendingException(cx); } RootedString source(cx); nsAutoJSString str; - if (GetSavedFrameSource(cx, stackObj, &source) == SavedFrameResult::Ok && + if (GetSavedFrameSource(cx, principals, stackObj, &source) == SavedFrameResult::Ok && str.init(cx, source)) { fileName = str; } else {