Bug 739825 - Push principals when entering compartments in structured clone. r=mrbkap

This commit is contained in:
Bobby Holley 2012-04-05 14:02:34 -07:00
parent 4036c3cfb5
commit 403f8c3812
4 changed files with 94 additions and 4 deletions

View File

@ -198,6 +198,44 @@ GetScriptContext(JSContext *cx)
return GetScriptContextFromJSContext(cx);
}
// Callbacks for the JS engine to use to push/pop context principals.
static JSBool
PushPrincipalCallback(JSContext *cx, JSPrincipals *principals)
{
// We should already be in the compartment of the given principal.
MOZ_ASSERT(principals ==
JS_GetCompartmentPrincipals((js::GetContextCompartment(cx))));
// Get the security manager.
nsIScriptSecurityManager *ssm = XPCWrapper::GetSecurityManager();
if (!ssm) {
return true;
}
// Push the principal.
JSStackFrame *fp = NULL;
nsresult rv = ssm->PushContextPrincipal(cx, JS_FrameIterator(cx, &fp),
nsJSPrincipals::get(principals));
if (NS_FAILED(rv)) {
JS_ReportOutOfMemory(cx);
return false;
}
return true;
}
static JSBool
PopPrincipalCallback(JSContext *cx)
{
nsIScriptSecurityManager *ssm = XPCWrapper::GetSecurityManager();
if (ssm) {
ssm->PopContextPrincipal(cx);
}
return true;
}
inline void SetPendingException(JSContext *cx, const char *aMsg)
{
JSAutoRequest ar(cx);
@ -3391,7 +3429,9 @@ nsresult nsScriptSecurityManager::Init()
CheckObjectAccess,
nsJSPrincipals::Subsume,
ObjectPrincipalFinder,
ContentSecurityPolicyPermitsJSAction
ContentSecurityPolicyPermitsJSAction,
PushPrincipalCallback,
PopPrincipalCallback
};
MOZ_ASSERT(!JS_GetSecurityCallbacks(sRuntime));

View File

@ -1437,7 +1437,7 @@ JSAutoEnterCompartment::enterAndIgnoreErrors(JSContext *cx, JSObject *target)
JSAutoEnterCompartment::~JSAutoEnterCompartment()
{
if (state == STATE_OTHER_COMPARTMENT) {
AutoCompartment* ac = reinterpret_cast<AutoCompartment*>(bytes);
AutoCompartment* ac = getAutoCompartment();
CHECK_REQUEST(ac->context);
ac->~AutoCompartment();
}

View File

@ -1580,6 +1580,16 @@ typedef JSPrincipals *
typedef JSBool
(* JSCSPEvalChecker)(JSContext *cx);
/*
* Security callbacks for pushing and popping context principals. These are only
* temporarily necessary and will hopefully be gone again in a matter of weeks.
*/
typedef JSBool
(* JSPushContextPrincipalOp)(JSContext *cx, JSPrincipals *principals);
typedef JSBool
(* JSPopContextPrincipalOp)(JSContext *cx);
/*
* Callback used to ask the embedding for the cross compartment wrapper handler
* that implements the desired prolicy for this kind of object in the
@ -2723,6 +2733,10 @@ js_TransplantObjectWithWrapper(JSContext *cx,
#ifdef __cplusplus
JS_END_EXTERN_C
namespace js {
struct AutoCompartment;
}
class JS_PUBLIC_API(JSAutoEnterCompartment)
{
/*
@ -2735,6 +2749,12 @@ class JS_PUBLIC_API(JSAutoEnterCompartment)
*/
void* bytes[sizeof(void*) == 4 && MOZ_ALIGNOF(uint64_t) == 8 ? 16 : 13];
protected:
js::AutoCompartment *getAutoCompartment() {
JS_ASSERT(state == STATE_OTHER_COMPARTMENT);
return reinterpret_cast<js::AutoCompartment*>(bytes);
}
/*
* This object may be in one of three states. If enter() or
* enterAndIgnoreErrors() hasn't been called, it's in STATE_UNENTERED.
@ -4234,6 +4254,8 @@ struct JSSecurityCallbacks {
JSSubsumePrincipalsOp subsumePrincipals;
JSObjectPrincipalsFinder findObjectPrincipals;
JSCSPEvalChecker contentSecurityPolicyAllows;
JSPushContextPrincipalOp pushContextPrincipal;
JSPopContextPrincipalOp popContextPrincipal;
};
extern JS_PUBLIC_API(void)

View File

@ -510,6 +510,34 @@ JSStructuredCloneWriter::startObject(JSObject *obj)
return out.writePair(obj->isArray() ? SCTAG_ARRAY_OBJECT : SCTAG_OBJECT_OBJECT, 0);
}
class AutoEnterCompartmentAndPushPrincipal : public JSAutoEnterCompartment
{
public:
bool enter(JSContext *cx, JSObject *target) {
// First, enter the compartment.
if (!JSAutoEnterCompartment::enter(cx, target))
return false;
// We only need to push a principal if we changed compartments.
if (state != STATE_OTHER_COMPARTMENT)
return true;
// Push.
const JSSecurityCallbacks *cb = cx->runtime->securityCallbacks;
return cb->pushContextPrincipal(cx, target->principals(cx));
};
~AutoEnterCompartmentAndPushPrincipal() {
// Pop the principal if necessary.
if (state == STATE_OTHER_COMPARTMENT) {
AutoCompartment *ac = getAutoCompartment();
const JSSecurityCallbacks *cb = ac->context->runtime->securityCallbacks;
cb->popContextPrincipal(ac->context);
}
};
};
bool
JSStructuredCloneWriter::startWrite(const js::Value &v)
{
@ -536,7 +564,7 @@ JSStructuredCloneWriter::startWrite(const js::Value &v)
// If we unwrapped above, we'll need to enter the underlying compartment.
// Let the AutoEnterCompartment do the right thing for us.
JSAutoEnterCompartment ac;
AutoEnterCompartmentAndPushPrincipal ac;
if (!ac.enter(context(), obj))
return false;
@ -581,7 +609,7 @@ JSStructuredCloneWriter::write(const Value &v)
JSObject *obj = &objs.back().toObject();
// The objects in |obj| can live in other compartments.
JSAutoEnterCompartment ac;
AutoEnterCompartmentAndPushPrincipal ac;
if (!ac.enter(context(), obj))
return false;