Bug 924905 - Do a subsumes check inside the stack iterator. r=jandem

--HG--
extra : rebase_source : ff8407c4f79fd3e2264470379470c526a751e45f
This commit is contained in:
Luke Wagner 2014-01-03 10:32:56 -06:00
parent 43fccf2aec
commit 2e804616e4
7 changed files with 61 additions and 16 deletions

View File

@ -117,11 +117,14 @@ private:
CheckObjectAccess(JSContext *cx, JS::Handle<JSObject*> obj,
JS::Handle<jsid> id, JSAccessMode mode,
JS::MutableHandle<JS::Value> vp);
// Decides, based on CSP, whether or not eval() and stuff can be executed.
static bool
ContentSecurityPolicyPermitsJSAction(JSContext *cx);
static bool
JSPrincipalsSubsume(JSPrincipals *first, JSPrincipals *second);
// Returns null if a principal cannot be found; generally callers
// should error out at that point.
static nsIPrincipal* doGetObjectPrincipal(JSObject* obj);

View File

@ -412,7 +412,6 @@ nsScriptSecurityManager::ContentSecurityPolicyPermitsJSAction(JSContext *cx)
return evalOK;
}
bool
nsScriptSecurityManager::CheckObjectAccess(JSContext *cx, JS::Handle<JSObject*> obj,
JS::Handle<jsid> id, JSAccessMode mode,
@ -450,6 +449,15 @@ nsScriptSecurityManager::CheckObjectAccess(JSContext *cx, JS::Handle<JSObject*>
return true;
}
// static
bool
nsScriptSecurityManager::JSPrincipalsSubsume(JSPrincipals *first,
JSPrincipals *second)
{
return nsJSPrincipals::get(first)->Subsumes(nsJSPrincipals::get(second));
}
NS_IMETHODIMP
nsScriptSecurityManager::CheckPropertyAccess(JSContext* cx,
JSObject* aJSObject,
@ -1791,7 +1799,8 @@ nsresult nsScriptSecurityManager::Init()
static const JSSecurityCallbacks securityCallbacks = {
CheckObjectAccess,
ContentSecurityPolicyPermitsJSAction
ContentSecurityPolicyPermitsJSAction,
JSPrincipalsSubsume,
};
MOZ_ASSERT(!JS_GetSecurityCallbacks(sRuntime));

View File

@ -272,6 +272,12 @@ typedef bool
(* JSCheckAccessOp)(JSContext *cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
JSAccessMode mode, JS::MutableHandle<JS::Value> vp);
// Return whether the first principal subsumes the second. The exact meaning of
// 'subsumes' is left up to the browser. Subsumption is checked inside the JS
// engine when determining, e.g., which stack frames to display in a backtrace.
typedef bool
(* JSSubsumesOp)(JSPrincipals *first, JSPrincipals *second);
// Check whether v is an instance of obj. Return false on error or exception,
// true on success with true in *bp if v is an instance of obj, false in
// *bp otherwise.

View File

@ -3194,6 +3194,7 @@ JS_DropPrincipals(JSRuntime *rt, JSPrincipals *principals);
struct JSSecurityCallbacks {
JSCheckAccessOp checkObjectAccess;
JSCSPEvalChecker contentSecurityPolicyAllows;
JSSubsumesOp subsumes;
};
extern JS_PUBLIC_API(void)

View File

@ -1317,7 +1317,11 @@ JSAbstractFramePtr::evaluateUCInStackFrame(JSContext *cx,
JSBrokenFrameIterator::JSBrokenFrameIterator(JSContext *cx)
{
NonBuiltinScriptFrameIter iter(cx);
// Show all frames on the stack whose principal is subsumed by the current principal.
NonBuiltinScriptFrameIter iter(cx,
ScriptFrameIter::ALL_CONTEXTS,
ScriptFrameIter::GO_THROUGH_SAVED,
cx->compartment()->principals);
data_ = iter.copyData();
}

View File

@ -521,6 +521,18 @@ ScriptFrameIter::settleOnActivation()
continue;
}
// If the caller supplied principals, only show activations which are subsumed (of the same
// origin or of an origin accessible) by these principals.
if (data_.principals_) {
if (JSSubsumesOp subsumes = data_.cx_->runtime()->securityCallbacks->subsumes) {
JS::AutoAssertNoGC nogc;
if (!subsumes(data_.principals_, activation->compartment()->principals)) {
++data_.activations_;
continue;
}
}
}
#ifdef JS_ION
if (activation->isJit()) {
data_.ionFrames_ = jit::IonFrameIterator(data_.activations_);
@ -565,11 +577,12 @@ ScriptFrameIter::settleOnActivation()
}
ScriptFrameIter::Data::Data(JSContext *cx, PerThreadData *perThread, SavedOption savedOption,
ContextOption contextOption)
ContextOption contextOption, JSPrincipals *principals)
: perThread_(perThread),
cx_(cx),
savedOption_(savedOption),
contextOption_(contextOption),
principals_(principals),
pc_(nullptr),
interpFrames_(nullptr),
activations_(cx->runtime())
@ -584,6 +597,7 @@ ScriptFrameIter::Data::Data(const ScriptFrameIter::Data &other)
cx_(other.cx_),
savedOption_(other.savedOption_),
contextOption_(other.contextOption_),
principals_(other.principals_),
state_(other.state_),
pc_(other.pc_),
interpFrames_(other.interpFrames_),
@ -595,7 +609,7 @@ ScriptFrameIter::Data::Data(const ScriptFrameIter::Data &other)
}
ScriptFrameIter::ScriptFrameIter(JSContext *cx, SavedOption savedOption)
: data_(cx, &cx->runtime()->mainThread, savedOption, CURRENT_CONTEXT)
: data_(cx, &cx->runtime()->mainThread, savedOption, CURRENT_CONTEXT, nullptr)
#ifdef JS_ION
, ionInlineFrames_(cx, (js::jit::IonFrameIterator*) nullptr)
#endif
@ -603,8 +617,9 @@ ScriptFrameIter::ScriptFrameIter(JSContext *cx, SavedOption savedOption)
settleOnActivation();
}
ScriptFrameIter::ScriptFrameIter(JSContext *cx, ContextOption contextOption, SavedOption savedOption)
: data_(cx, &cx->runtime()->mainThread, savedOption, contextOption)
ScriptFrameIter::ScriptFrameIter(JSContext *cx, ContextOption contextOption,
SavedOption savedOption, JSPrincipals *principals)
: data_(cx, &cx->runtime()->mainThread, savedOption, contextOption, principals)
#ifdef JS_ION
, ionInlineFrames_(cx, (js::jit::IonFrameIterator*) nullptr)
#endif

View File

@ -1449,14 +1449,15 @@ class ScriptFrameIter
*/
struct Data
{
PerThreadData *perThread_;
JSContext *cx_;
SavedOption savedOption_;
ContextOption contextOption_;
PerThreadData * perThread_;
JSContext * cx_;
SavedOption savedOption_;
ContextOption contextOption_;
JSPrincipals * principals_;
State state_;
State state_;
jsbytecode *pc_;
jsbytecode * pc_;
InterpreterFrameIterator interpFrames_;
ActivationIterator activations_;
@ -1466,7 +1467,7 @@ class ScriptFrameIter
#endif
Data(JSContext *cx, PerThreadData *perThread, SavedOption savedOption,
ContextOption contextOption);
ContextOption contextOption, JSPrincipals *principals);
Data(const Data &other);
};
@ -1487,7 +1488,7 @@ class ScriptFrameIter
public:
ScriptFrameIter(JSContext *cx, SavedOption = STOP_AT_SAVED);
ScriptFrameIter(JSContext *cx, ContextOption, SavedOption);
ScriptFrameIter(JSContext *cx, ContextOption, SavedOption, JSPrincipals* = nullptr);
ScriptFrameIter(const ScriptFrameIter &iter);
ScriptFrameIter(const Data &data);
ScriptFrameIter(AbstractFramePtr frame);
@ -1612,6 +1613,12 @@ class NonBuiltinScriptFrameIter : public ScriptFrameIter
NonBuiltinScriptFrameIter(JSContext *cx, ScriptFrameIter::SavedOption opt = ScriptFrameIter::STOP_AT_SAVED)
: ScriptFrameIter(cx, opt) { settle(); }
NonBuiltinScriptFrameIter(JSContext *cx,
ScriptFrameIter::ContextOption contextOption,
ScriptFrameIter::SavedOption savedOption,
JSPrincipals *principals = nullptr)
: ScriptFrameIter(cx, contextOption, savedOption, principals) { settle(); }
NonBuiltinScriptFrameIter(const ScriptFrameIter::Data &data)
: ScriptFrameIter(data)
{}