Bug 1122238 part 3. Drop all the DOMException-cloning and sanitization gunk we added in bug 1107592 and bug 1107953 and bug 1117242 . r=bholley

This commit is contained in:
Boris Zbarsky 2015-03-06 01:08:06 -05:00
parent 6db6b887fb
commit f22da41d9f
8 changed files with 4 additions and 164 deletions

View File

@ -723,31 +723,5 @@ DOMException::Create(nsresult aRv)
return inst.forget();
}
bool
DOMException::Sanitize(JSContext* aCx,
JS::MutableHandle<JS::Value> aSanitizedValue)
{
nsRefPtr<DOMException> retval = this;
if (mLocation && !mLocation->CallerSubsumes(aCx)) {
nsString message;
GetMessageMoz(message);
nsString name;
GetName(name);
retval = new dom::DOMException(nsresult(Result()),
NS_ConvertUTF16toUTF8(message),
NS_ConvertUTF16toUTF8(name),
Code());
// Now it's possible that the stack on retval still starts with
// stuff aCx is not supposed to touch; it depends on what's on the
// stack right this second. Walk past all of that.
nsCOMPtr<nsIStackFrame> stack;
nsresult rv = retval->mLocation->GetSanitized(aCx, getter_AddRefs(stack));
NS_ENSURE_SUCCESS(rv, false);
retval->mLocation.swap(stack);
}
return ToJSValue(aCx, retval, aSanitizedValue);
}
} // namespace dom
} // namespace mozilla

View File

@ -156,15 +156,6 @@ public:
static already_AddRefed<DOMException>
Create(nsresult aRv);
// Sanitize() is a workaround for the fact that DOMExceptions can leak stack
// information for the first stackframe to callers that should not have access
// to it. To prevent this, we check whether aCx subsumes our first stackframe
// and if not hand out a JS::Value for a clone of ourselves. Otherwise we
// hand out a JS::Value for ourselves.
//
// If the return value is false, an exception was thrown on aCx.
bool Sanitize(JSContext* aCx, JS::MutableHandle<JS::Value> aSanitizedValue);
protected:
virtual ~DOMException() {}

View File

@ -250,26 +250,6 @@ ErrorResult::ReportJSExceptionFromJSImplementation(JSContext* aCx)
nsresult rv =
UNWRAP_OBJECT(DOMException, &mJSException.toObject(), domException);
if (NS_SUCCEEDED(rv)) {
// We may have to create a new DOMException object, because the one we
// have has a stack that includes the chrome code that threw it, and in
// particular has the wrong file/line/column information.
JS::Rooted<JS::Value> reflector(aCx);
if (!domException->Sanitize(aCx, &reflector)) {
// Well, that threw _an_ exception. Let's forget ours. We can just
// unroot and not change the value, since mJSException is completely
// ignored if mResult is not NS_ERROR_DOM_JS_EXCEPTION and we plan to
// change mResult to a different value.
js::RemoveRawValueRoot(aCx, &mJSException);
// We no longer have a useful exception but we do want to signal that an
// error occured.
mResult = NS_ERROR_FAILURE;
// But do make sure to not ReportJSException here, since we don't have one.
return;
}
mJSException = reflector;
ReportJSException(aCx);
return;
}
@ -308,17 +288,6 @@ ErrorResult::StealJSException(JSContext* cx,
value.set(mJSException);
js::RemoveRawValueRoot(cx, &mJSException);
mResult = NS_OK;
if (value.isObject()) {
// If it's a DOMException we may need to sanitize it.
dom::DOMException* domException;
nsresult rv =
UNWRAP_OBJECT(DOMException, &value.toObject(), domException);
if (NS_SUCCEEDED(rv) && !domException->Sanitize(cx, value)) {
JS_GetPendingException(cx, value);
JS_ClearPendingException(cx);
}
}
}
void

View File

@ -107,8 +107,7 @@ public:
// StealJSException steals the JS Exception from the object. This method must
// be called only if IsJSException() returns true. This method also resets the
// ErrorCode() to NS_OK. The value will be ensured to be sanitized wrt to the
// current compartment of cx if it happens to be a DOMException.
// ErrorCode() to NS_OK.
void StealJSException(JSContext* cx, JS::MutableHandle<JS::Value> value);
void MOZ_ALWAYS_INLINE MightThrowJSException()

View File

@ -307,9 +307,6 @@ public:
NS_IMETHOD GetName(nsAString& aFunction) MOZ_OVERRIDE;
NS_IMETHOD GetCaller(nsIStackFrame** aCaller) MOZ_OVERRIDE;
NS_IMETHOD GetFormattedStack(nsAString& aStack) MOZ_OVERRIDE;
virtual bool CallerSubsumes(JSContext* aCx) MOZ_OVERRIDE;
NS_IMETHOD GetSanitized(JSContext* aCx,
nsIStackFrame** aSanitized) MOZ_OVERRIDE;
protected:
virtual bool IsJSFrame() const MOZ_OVERRIDE {
@ -581,35 +578,6 @@ NS_IMETHODIMP StackFrame::GetSourceLine(nsACString& aSourceLine)
return NS_OK;
}
/* [noscript] readonly attribute nsIStackFrame sanitized */
NS_IMETHODIMP StackFrame::GetSanitized(JSContext*, nsIStackFrame** aSanitized)
{
NS_ADDREF(*aSanitized = this);
return NS_OK;
}
/* [noscript] readonly attribute nsIStackFrame sanitized */
NS_IMETHODIMP JSStackFrame::GetSanitized(JSContext* aCx, nsIStackFrame** aSanitized)
{
// NB: Do _not_ enter the compartment of the SavedFrame object here, because
// we are checking against the caller's compartment's principals in
// GetFirstSubsumedSavedFrame.
JS::RootedObject savedFrame(aCx, mStack);
JS::ExposeObjectToActiveJS(mStack);
savedFrame = js::GetFirstSubsumedSavedFrame(aCx, savedFrame);
nsCOMPtr<nsIStackFrame> stackFrame;
if (savedFrame) {
stackFrame = new JSStackFrame(savedFrame);
} else {
stackFrame = new StackFrame();
}
stackFrame.forget(aSanitized);
return NS_OK;
}
/* readonly attribute nsIStackFrame caller; */
NS_IMETHODIMP JSStackFrame::GetCaller(nsIStackFrame** aCaller)
{
@ -731,37 +699,6 @@ NS_IMETHODIMP StackFrame::ToString(nsACString& _retval)
return NS_OK;
}
/* virtual */ bool
StackFrame::CallerSubsumes(JSContext* aCx)
{
return true;
}
/* virtual */ bool
JSStackFrame::CallerSubsumes(JSContext* aCx)
{
if (!NS_IsMainThread()) {
return true;
}
if (!mStack) {
// No problem here, there's no data to leak.
return true;
}
nsIPrincipal* callerPrincipal = nsContentUtils::SubjectPrincipal();
JS::Rooted<JSObject*> unwrappedStack(aCx, js::CheckedUnwrap(mStack));
if (!unwrappedStack) {
// We can't leak data here either.
return true;
}
nsIPrincipal* stackPrincipal =
nsJSPrincipals::get(js::GetSavedFramePrincipals(unwrappedStack));
return callerPrincipal->SubsumesConsideringDomain(stackPrincipal);
}
/* static */ already_AddRefed<nsIStackFrame>
JSStackFrame::CreateStack(JSContext* aCx, int32_t aMaxDepth)
{

View File

@ -212,11 +212,6 @@ protected:
if (rv.Failed()) {
JS::Rooted<JS::Value> exn(cx);
if (rv.IsJSException()) {
// Enter the compartment of mPromise before stealing the JS exception,
// since the StealJSException call will use the current compartment for
// a security check that determines how much of the stack we're allowed
// to see and we'll be exposing that stack to consumers of mPromise.
JSAutoCompartment ac(cx, mPromise->GlobalJSObject());
rv.StealJSException(cx, &exn);
} else {
// Convert the ErrorResult to a JS exception object that we can reject
@ -610,14 +605,7 @@ Promise::CallInitFunction(const GlobalObject& aGlobal,
if (aRv.IsJSException()) {
JS::Rooted<JS::Value> value(cx);
{ // scope for ac
// Enter the compartment of our global before stealing the JS exception,
// since the StealJSException call will use the current compartment for
// a security check that determines how much of the stack we're allowed
// to see, and we'll be exposing that stack to consumers of this promise.
JSAutoCompartment ac(cx, GlobalJSObject());
aRv.StealJSException(cx, &value);
}
aRv.StealJSException(cx, &value);
// we want the same behavior as this JS implementation:
// function Promise(arg) { try { arg(a, b); } catch (e) { this.reject(e); }}

View File

@ -214,15 +214,7 @@ WrapperPromiseCallback::Call(JSContext* aCx,
if (rv.Failed()) {
JS::Rooted<JS::Value> value(aCx);
if (rv.IsJSException()) {
{ // scope for ac
// Enter the compartment of mNextPromise before stealing the JS
// exception, since the StealJSException call will use the current
// compartment for a security check that determines how much of the
// stack we're allowed to see and we'll be exposing that stack to
// consumers of mPromise.
JSAutoCompartment ac(aCx, mNextPromise->GlobalJSObject());
rv.StealJSException(aCx, &value);
}
rv.StealJSException(aCx, &value);
if (!JS_WrapValue(aCx, &value)) {
NS_WARNING("Failed to wrap value into the right compartment.");

View File

@ -10,9 +10,7 @@
#include "nsISupports.idl"
[ptr] native JSContext(JSContext);
[scriptable, uuid(4ed5cd87-401a-425a-8d8d-c28fbc1e88b2)]
[scriptable, uuid(8272a3d5-2a94-40c0-8ab6-be76583a0221)]
interface nsIStackFrame : nsISupports
{
// see nsIProgrammingLanguage for list of language consts
@ -26,20 +24,12 @@ interface nsIStackFrame : nsISupports
readonly attribute AUTF8String sourceLine;
readonly attribute nsIStackFrame caller;
// Returns the first frame whose principals are subsumed by the caller's
// principals.
[noscript, implicit_jscontext] readonly attribute nsIStackFrame sanitized;
// Returns a formatted stack string that looks like the sort of
// string that would be returned by .stack on JS Error objects.
// Only works on JS-language stack frames.
readonly attribute AString formattedStack;
AUTF8String toString();
// Return whether this stack frame can be accessed by the caller. This is
// safe to call on non-main threads, but will always report "yes" there.
[noscript, notxpcom, nostdcall] boolean callerSubsumes(in JSContext aCx);
};
[scriptable, uuid(1caf1461-be1d-4b79-a552-5292b6bf3c35)]