mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Backout bug 754202 (all patches, rather than just patches 3-7).
This commit is contained in:
parent
9aae70bdc5
commit
c9bf4416ea
@ -9,7 +9,7 @@
|
||||
interface nsIURI;
|
||||
interface nsIChannel;
|
||||
|
||||
[scriptable, uuid(cdb27711-492b-4973-938b-de81ac124658)]
|
||||
[scriptable, uuid(3708aa92-e2d9-4fd1-9e46-edfa3eb5ebf5)]
|
||||
interface nsIScriptSecurityManager : nsIXPCSecurityManager
|
||||
{
|
||||
///////////////// Security Checks //////////////////
|
||||
@ -260,6 +260,29 @@ interface nsIScriptSecurityManager : nsIXPCSecurityManager
|
||||
[noscript,notxpcom] nsIPrincipal getCxSubjectPrincipal(in JSContextPtr cx);
|
||||
[noscript,notxpcom] nsIPrincipal getCxSubjectPrincipalAndFrame(in JSContextPtr cx,
|
||||
out JSStackFramePtr fp);
|
||||
|
||||
/**
|
||||
* If no scripted code is running "above" (or called from) fp, then
|
||||
* instead of looking at cx->globalObject, we will return |principal|.
|
||||
* This function only affects |cx|. If someone pushes another context onto
|
||||
* the context stack, then it supersedes this call.
|
||||
* NOTE: If |fp| is non-null popContextPrincipal must be called before fp
|
||||
* has finished executing.
|
||||
*
|
||||
* @param cx The context to clamp.
|
||||
* @param fp The frame pointer to clamp at. May be 'null'.
|
||||
* @param principal The principal to clamp to.
|
||||
*/
|
||||
[noscript] void pushContextPrincipal(in JSContextPtr cx,
|
||||
in JSStackFramePtr fp,
|
||||
in nsIPrincipal principal);
|
||||
|
||||
/**
|
||||
* Removes a clamp set by pushContextPrincipal from cx. This must be
|
||||
* called in a stack-like fashion (e.g., given two contexts |a| and |b|,
|
||||
* it is not legal to do: push(a) push(b) pop(a)).
|
||||
*/
|
||||
[noscript] void popContextPrincipal(in JSContextPtr cx);
|
||||
};
|
||||
|
||||
%{C++
|
||||
|
@ -403,11 +403,12 @@ private:
|
||||
|
||||
// Returns null if a principal cannot be found; generally callers
|
||||
// should error out at that point.
|
||||
static nsIPrincipal* doGetObjectPrincipal(JSObject *obj);
|
||||
#ifdef DEBUG
|
||||
static nsIPrincipal*
|
||||
old_doGetObjectPrincipal(JSObject *obj, bool aAllowShortCircuit = true);
|
||||
doGetObjectPrincipal(JSObject *obj
|
||||
#ifdef DEBUG
|
||||
, bool aAllowShortCircuit = true
|
||||
#endif
|
||||
);
|
||||
|
||||
// Returns null if a principal cannot be found. Note that rv can be NS_OK
|
||||
// when this happens -- this means that there was no JS running.
|
||||
@ -553,6 +554,17 @@ private:
|
||||
PrintPolicyDB();
|
||||
#endif
|
||||
|
||||
struct ContextPrincipal {
|
||||
ContextPrincipal(ContextPrincipal *next, JSContext *cx,
|
||||
JSStackFrame *fp, nsIPrincipal *principal)
|
||||
: mNext(next), mCx(cx), mFp(fp), mPrincipal(principal) {}
|
||||
|
||||
ContextPrincipal *mNext;
|
||||
JSContext *mCx;
|
||||
JSStackFrame *mFp;
|
||||
nsCOMPtr<nsIPrincipal> mPrincipal;
|
||||
};
|
||||
|
||||
// JS strings we need to clean up on shutdown
|
||||
static jsid sEnabledID;
|
||||
|
||||
@ -565,6 +577,7 @@ private:
|
||||
|
||||
nsCOMPtr<nsIPrincipal> mSystemPrincipal;
|
||||
nsCOMPtr<nsIPrincipal> mSystemCertificate;
|
||||
ContextPrincipal *mContextPrincipals;
|
||||
nsInterfaceHashtable<PrincipalKey, nsIPrincipal> mPrincipals;
|
||||
bool mPrefInitialized;
|
||||
bool mIsJavaScriptEnabled;
|
||||
|
@ -162,6 +162,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);
|
||||
@ -366,6 +404,34 @@ nsScriptSecurityManager::GetCxSubjectPrincipalAndFrame(JSContext *cx, JSStackFra
|
||||
return principal;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsScriptSecurityManager::PushContextPrincipal(JSContext *cx,
|
||||
JSStackFrame *fp,
|
||||
nsIPrincipal *principal)
|
||||
{
|
||||
NS_ASSERTION(principal, "Must pass a non-null principal");
|
||||
|
||||
ContextPrincipal *cp = new ContextPrincipal(mContextPrincipals, cx, fp,
|
||||
principal);
|
||||
if (!cp)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
mContextPrincipals = cp;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsScriptSecurityManager::PopContextPrincipal(JSContext *cx)
|
||||
{
|
||||
NS_ASSERTION(mContextPrincipals->mCx == cx, "Mismatched push/pop");
|
||||
|
||||
ContextPrincipal *next = mContextPrincipals->mNext;
|
||||
delete mContextPrincipals;
|
||||
mContextPrincipals = next;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
////////////////////
|
||||
// Policy Storage //
|
||||
////////////////////
|
||||
@ -2237,10 +2303,24 @@ nsScriptSecurityManager::GetPrincipalAndFrame(JSContext *cx,
|
||||
|
||||
if (cx)
|
||||
{
|
||||
JSStackFrame *target = nsnull;
|
||||
nsIPrincipal *targetPrincipal = nsnull;
|
||||
for (ContextPrincipal *cp = mContextPrincipals; cp; cp = cp->mNext)
|
||||
{
|
||||
if (cp->mCx == cx)
|
||||
{
|
||||
target = cp->mFp;
|
||||
targetPrincipal = cp->mPrincipal;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Get principals from innermost JavaScript frame.
|
||||
JSStackFrame *fp = nsnull; // tell JS_FrameIterator to start at innermost
|
||||
for (fp = JS_FrameIterator(cx, &fp); fp; fp = JS_FrameIterator(cx, &fp))
|
||||
{
|
||||
if (fp == target)
|
||||
break;
|
||||
nsIPrincipal* result = GetFramePrincipal(cx, fp, rv);
|
||||
if (result)
|
||||
{
|
||||
@ -2250,6 +2330,25 @@ nsScriptSecurityManager::GetPrincipalAndFrame(JSContext *cx,
|
||||
}
|
||||
}
|
||||
|
||||
// If targetPrincipal is non-null, then it means that someone wants to
|
||||
// clamp the principals on this context to this principal. Note that
|
||||
// fp might not equal target here (fp might be null) because someone
|
||||
// could have set aside the frame chain in the meantime.
|
||||
if (targetPrincipal)
|
||||
{
|
||||
if (fp && fp == target)
|
||||
{
|
||||
*frameResult = fp;
|
||||
}
|
||||
else
|
||||
{
|
||||
JSStackFrame *inner = nsnull;
|
||||
*frameResult = JS_FrameIterator(cx, &inner);
|
||||
}
|
||||
|
||||
return targetPrincipal;
|
||||
}
|
||||
|
||||
nsIScriptContextPrincipal* scp =
|
||||
GetScriptContextPrincipalFromJSContext(cx);
|
||||
if (scp)
|
||||
@ -2280,15 +2379,9 @@ nsIPrincipal*
|
||||
nsScriptSecurityManager::GetSubjectPrincipal(JSContext *cx,
|
||||
nsresult* rv)
|
||||
{
|
||||
*rv = NS_OK;
|
||||
JSCompartment *compartment = js::GetContextCompartment(cx);
|
||||
|
||||
// The context should always be in a compartment, either one it has entered
|
||||
// or the one associated with its global.
|
||||
MOZ_ASSERT(!!compartment);
|
||||
|
||||
JSPrincipals *principals = JS_GetCompartmentPrincipals(compartment);
|
||||
return nsJSPrincipals::get(principals);
|
||||
NS_PRECONDITION(rv, "Null out param");
|
||||
JSStackFrame *fp;
|
||||
return GetPrincipalAndFrame(cx, &fp, rv);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
@ -2304,33 +2397,19 @@ nsScriptSecurityManager::GetObjectPrincipal(JSContext *aCx, JSObject *aObj,
|
||||
|
||||
// static
|
||||
nsIPrincipal*
|
||||
nsScriptSecurityManager::doGetObjectPrincipal(JSObject *aObj)
|
||||
{
|
||||
JSCompartment *compartment = js::GetObjectCompartment(aObj);
|
||||
JSPrincipals *principals = JS_GetCompartmentPrincipals(compartment);
|
||||
nsIPrincipal *principal = nsJSPrincipals::get(principals);
|
||||
|
||||
// We leave the old code in for a little while to make sure that pulling
|
||||
// object principals directly off the compartment always gives an equivalent
|
||||
// result (from a security perspective).
|
||||
nsScriptSecurityManager::doGetObjectPrincipal(JSObject *aObj
|
||||
#ifdef DEBUG
|
||||
nsIPrincipal *old = old_doGetObjectPrincipal(aObj);
|
||||
MOZ_ASSERT(NS_SUCCEEDED(CheckSameOriginPrincipal(principal, old)));
|
||||
, bool aAllowShortCircuit
|
||||
#endif
|
||||
|
||||
return principal;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
// static
|
||||
nsIPrincipal*
|
||||
nsScriptSecurityManager::old_doGetObjectPrincipal(JSObject *aObj,
|
||||
bool aAllowShortCircuit)
|
||||
)
|
||||
{
|
||||
NS_ASSERTION(aObj, "Bad call to doGetObjectPrincipal()!");
|
||||
nsIPrincipal* result = nsnull;
|
||||
|
||||
#ifdef DEBUG
|
||||
JSObject* origObj = aObj;
|
||||
#endif
|
||||
|
||||
js::Class *jsClass = js::GetObjectClass(aObj);
|
||||
|
||||
// A common case seen in this code is that we enter this function
|
||||
@ -2364,7 +2443,12 @@ nsScriptSecurityManager::old_doGetObjectPrincipal(JSObject *aObj,
|
||||
|
||||
if (IS_WRAPPER_CLASS(jsClass)) {
|
||||
result = sXPConnect->GetPrincipal(aObj,
|
||||
aAllowShortCircuit);
|
||||
#ifdef DEBUG
|
||||
aAllowShortCircuit
|
||||
#else
|
||||
true
|
||||
#endif
|
||||
);
|
||||
if (result) {
|
||||
break;
|
||||
}
|
||||
@ -2380,6 +2464,7 @@ nsScriptSecurityManager::old_doGetObjectPrincipal(JSObject *aObj,
|
||||
priv = nsnull;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
if (aAllowShortCircuit) {
|
||||
nsCOMPtr<nsIXPConnectWrappedNative> xpcWrapper =
|
||||
do_QueryInterface(priv);
|
||||
@ -2389,6 +2474,7 @@ nsScriptSecurityManager::old_doGetObjectPrincipal(JSObject *aObj,
|
||||
"Uh, an nsIXPConnectWrappedNative with the "
|
||||
"wrong JSClass or getObjectOps hooks!");
|
||||
}
|
||||
#endif
|
||||
|
||||
nsCOMPtr<nsIScriptObjectPrincipal> objPrin =
|
||||
do_QueryInterface(priv);
|
||||
@ -2410,8 +2496,9 @@ nsScriptSecurityManager::old_doGetObjectPrincipal(JSObject *aObj,
|
||||
jsClass = js::GetObjectClass(aObj);
|
||||
} while (1);
|
||||
|
||||
#ifdef DEBUG
|
||||
if (aAllowShortCircuit) {
|
||||
nsIPrincipal *principal = old_doGetObjectPrincipal(origObj, false);
|
||||
nsIPrincipal *principal = doGetObjectPrincipal(origObj, false);
|
||||
|
||||
// Because of inner window reuse, we can have objects with one principal
|
||||
// living in a scope with a different (but same-origin) principal. So
|
||||
@ -2419,10 +2506,10 @@ nsScriptSecurityManager::old_doGetObjectPrincipal(JSObject *aObj,
|
||||
NS_ASSERTION(NS_SUCCEEDED(CheckSameOriginPrincipal(result, principal)),
|
||||
"Principal mismatch. Not good");
|
||||
}
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
#endif /* DEBUG */
|
||||
|
||||
///////////////// Capabilities API /////////////////////
|
||||
NS_IMETHODIMP
|
||||
@ -2434,11 +2521,27 @@ nsScriptSecurityManager::IsCapabilityEnabled(const char *capability,
|
||||
JSContext *cx = GetCurrentJSContext();
|
||||
fp = cx ? JS_FrameIterator(cx, &fp) : nsnull;
|
||||
|
||||
JSStackFrame *target = nsnull;
|
||||
nsIPrincipal *targetPrincipal = nsnull;
|
||||
for (ContextPrincipal *cp = mContextPrincipals; cp; cp = cp->mNext)
|
||||
{
|
||||
if (cp->mCx == cx)
|
||||
{
|
||||
target = cp->mFp;
|
||||
targetPrincipal = cp->mPrincipal;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!fp)
|
||||
{
|
||||
// No script code on stack. We don't have enough information and have
|
||||
// to allow execution.
|
||||
*result = true;
|
||||
// No script code on stack. If we had a principal pushed for this
|
||||
// context and fp is null, then we use that principal. Otherwise, we
|
||||
// don't have enough information and have to allow execution.
|
||||
|
||||
*result = (targetPrincipal && !target)
|
||||
? (targetPrincipal == mSystemPrincipal)
|
||||
: true;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
@ -2482,7 +2585,7 @@ nsScriptSecurityManager::IsCapabilityEnabled(const char *capability,
|
||||
// the JS engine via JS_EvaluateScript or similar APIs.
|
||||
if (JS_IsGlobalFrame(cx, fp))
|
||||
break;
|
||||
} while ((fp = JS_FrameIterator(cx, &fp)) != nsnull);
|
||||
} while (fp != target && (fp = JS_FrameIterator(cx, &fp)) != nsnull);
|
||||
|
||||
if (!previousPrincipal)
|
||||
{
|
||||
@ -2966,6 +3069,7 @@ nsScriptSecurityManager::nsScriptSecurityManager(void)
|
||||
: mOriginToPolicyMap(nsnull),
|
||||
mDefaultPolicy(nsnull),
|
||||
mCapabilities(nsnull),
|
||||
mContextPrincipals(nsnull),
|
||||
mPrefInitialized(false),
|
||||
mIsJavaScriptEnabled(false),
|
||||
mIsWritingPrefs(false),
|
||||
@ -3026,7 +3130,9 @@ nsresult nsScriptSecurityManager::Init()
|
||||
CheckObjectAccess,
|
||||
nsJSPrincipals::Subsume,
|
||||
ObjectPrincipalFinder,
|
||||
ContentSecurityPolicyPermitsJSAction
|
||||
ContentSecurityPolicyPermitsJSAction,
|
||||
PushPrincipalCallback,
|
||||
PopPrincipalCallback
|
||||
};
|
||||
|
||||
MOZ_ASSERT(!JS_GetSecurityCallbacks(sRuntime));
|
||||
@ -3045,6 +3151,7 @@ jsid nsScriptSecurityManager::sEnabledID = JSID_VOID;
|
||||
nsScriptSecurityManager::~nsScriptSecurityManager(void)
|
||||
{
|
||||
Preferences::RemoveObservers(this, kObservedPrefs);
|
||||
NS_ASSERTION(!mContextPrincipals, "Leaking mContextPrincipals");
|
||||
delete mOriginToPolicyMap;
|
||||
if(mDefaultPolicy)
|
||||
mDefaultPolicy->Drop();
|
||||
|
@ -1198,29 +1198,27 @@ nsJSContext::EvaluateStringWithValue(const nsAString& aScript,
|
||||
xpc_UnmarkGrayObject(aScopeObject);
|
||||
nsAutoMicroTask mt;
|
||||
|
||||
// Ignore the principal that was passed in, and just assert that it matches
|
||||
// the one we pull off the global.
|
||||
nsCOMPtr<nsIPrincipal> principal;
|
||||
nsCOMPtr<nsIScriptObjectPrincipal> objPrincipal = do_QueryInterface(GetGlobalObject());
|
||||
if (!objPrincipal)
|
||||
return NS_ERROR_FAILURE;
|
||||
principal = objPrincipal->GetPrincipal();
|
||||
if (!principal)
|
||||
return NS_ERROR_FAILURE;
|
||||
#ifdef DEBUG
|
||||
bool equal = false;
|
||||
principal->Equals(aPrincipal, &equal);
|
||||
MOZ_ASSERT(equal);
|
||||
nsIPrincipal *scopeObjectPrincipal =
|
||||
nsJSPrincipals::get(JS_GetCompartmentPrincipals(js::GetObjectCompartment(aScopeObject)));
|
||||
equal = false;
|
||||
principal->Equals(scopeObjectPrincipal, &equal);
|
||||
MOZ_ASSERT(equal);
|
||||
#endif
|
||||
// Safety first: get an object representing the script's principals, i.e.,
|
||||
// the entities who signed this script, or the fully-qualified-domain-name
|
||||
// or "codebase" from which it was loaded.
|
||||
nsCOMPtr<nsIPrincipal> principal = aPrincipal;
|
||||
nsresult rv;
|
||||
if (!aPrincipal) {
|
||||
nsIScriptGlobalObject *global = GetGlobalObject();
|
||||
if (!global)
|
||||
return NS_ERROR_FAILURE;
|
||||
nsCOMPtr<nsIScriptObjectPrincipal> objPrincipal =
|
||||
do_QueryInterface(global, &rv);
|
||||
if (NS_FAILED(rv))
|
||||
return NS_ERROR_FAILURE;
|
||||
principal = objPrincipal->GetPrincipal();
|
||||
if (!principal)
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
bool ok = false;
|
||||
|
||||
nsresult rv = sSecurityManager->CanExecuteScripts(mContext, principal, &ok);
|
||||
rv = sSecurityManager->CanExecuteScripts(mContext, principal, &ok);
|
||||
if (NS_FAILED(rv)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
@ -1237,6 +1235,9 @@ nsJSContext::EvaluateStringWithValue(const nsAString& aScript,
|
||||
|
||||
jsval val;
|
||||
|
||||
rv = sSecurityManager->PushContextPrincipal(mContext, nsnull, principal);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsJSContext::TerminationFuncHolder holder(this);
|
||||
|
||||
// SecurityManager said "ok", but don't compile if aVersion is unknown.
|
||||
@ -1292,6 +1293,8 @@ nsJSContext::EvaluateStringWithValue(const nsAString& aScript,
|
||||
}
|
||||
}
|
||||
|
||||
sSecurityManager->PopContextPrincipal(mContext);
|
||||
|
||||
// Pop here, after JS_ValueToString and any other possible evaluation.
|
||||
if (NS_FAILED(stack->Pop(nsnull)))
|
||||
rv = NS_ERROR_FAILURE;
|
||||
@ -1397,25 +1400,19 @@ nsJSContext::EvaluateString(const nsAString& aScript,
|
||||
|
||||
xpc_UnmarkGrayObject(aScopeObject);
|
||||
|
||||
// Ignore the principal that was passed in, and just assert that it matches
|
||||
// the one we pull off the global.
|
||||
nsCOMPtr<nsIPrincipal> principal;
|
||||
nsCOMPtr<nsIScriptObjectPrincipal> objPrincipal = do_QueryInterface(GetGlobalObject());
|
||||
if (!objPrincipal)
|
||||
return NS_ERROR_FAILURE;
|
||||
principal = objPrincipal->GetPrincipal();
|
||||
if (!principal)
|
||||
return NS_ERROR_FAILURE;
|
||||
#ifdef DEBUG
|
||||
bool equal = false;
|
||||
principal->Equals(aPrincipal, &equal);
|
||||
MOZ_ASSERT(equal);
|
||||
nsIPrincipal *scopeObjectPrincipal =
|
||||
nsJSPrincipals::get(JS_GetCompartmentPrincipals(js::GetObjectCompartment(aScopeObject)));
|
||||
equal = false;
|
||||
principal->Equals(scopeObjectPrincipal, &equal);
|
||||
MOZ_ASSERT(equal);
|
||||
#endif
|
||||
// Safety first: get an object representing the script's principals, i.e.,
|
||||
// the entities who signed this script, or the fully-qualified-domain-name
|
||||
// or "codebase" from which it was loaded.
|
||||
nsCOMPtr<nsIPrincipal> principal = aPrincipal;
|
||||
if (!aPrincipal) {
|
||||
nsCOMPtr<nsIScriptObjectPrincipal> objPrincipal =
|
||||
do_QueryInterface(GetGlobalObject());
|
||||
if (!objPrincipal)
|
||||
return NS_ERROR_FAILURE;
|
||||
principal = objPrincipal->GetPrincipal();
|
||||
if (!principal)
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
bool ok = false;
|
||||
|
||||
@ -1440,6 +1437,9 @@ nsJSContext::EvaluateString(const nsAString& aScript,
|
||||
jsval val = JSVAL_VOID;
|
||||
jsval* vp = aRetValue ? &val : NULL;
|
||||
|
||||
rv = sSecurityManager->PushContextPrincipal(mContext, nsnull, principal);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsJSContext::TerminationFuncHolder holder(this);
|
||||
|
||||
++mExecuteDepth;
|
||||
@ -1491,6 +1491,8 @@ nsJSContext::EvaluateString(const nsAString& aScript,
|
||||
|
||||
--mExecuteDepth;
|
||||
|
||||
sSecurityManager->PopContextPrincipal(mContext);
|
||||
|
||||
// Pop here, after JS_ValueToString and any other possible evaluation.
|
||||
if (NS_FAILED(stack->Pop(nsnull)))
|
||||
rv = NS_ERROR_FAILURE;
|
||||
@ -1588,6 +1590,15 @@ nsJSContext::ExecuteScript(JSScript* aScriptObject,
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIPrincipal> principal;
|
||||
rv = sSecurityManager->GetObjectPrincipal(mContext,
|
||||
JS_GetGlobalFromScript(aScriptObject),
|
||||
getter_AddRefs(principal));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = sSecurityManager->PushContextPrincipal(mContext, nsnull, principal);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsJSContext::TerminationFuncHolder holder(this);
|
||||
XPCAutoRequest ar(mContext);
|
||||
++mExecuteDepth;
|
||||
@ -1614,6 +1625,8 @@ nsJSContext::ExecuteScript(JSScript* aScriptObject,
|
||||
|
||||
--mExecuteDepth;
|
||||
|
||||
sSecurityManager->PopContextPrincipal(mContext);
|
||||
|
||||
// Pop here, after JS_ValueToString and any other possible evaluation.
|
||||
if (NS_FAILED(stack->Pop(nsnull)))
|
||||
rv = NS_ERROR_FAILURE;
|
||||
@ -1854,12 +1867,24 @@ nsJSContext::CallEventHandler(nsISupports* aTarget, JSObject* aScope,
|
||||
jsval *argv = nsnull;
|
||||
|
||||
JSObject *funobj = aHandler;
|
||||
nsCOMPtr<nsIPrincipal> principal;
|
||||
rv = sSecurityManager->GetObjectPrincipal(mContext, funobj,
|
||||
getter_AddRefs(principal));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
JSStackFrame *currentfp = nsnull;
|
||||
rv = sSecurityManager->PushContextPrincipal(mContext,
|
||||
JS_FrameIterator(mContext, ¤tfp),
|
||||
principal);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
jsval funval = OBJECT_TO_JSVAL(funobj);
|
||||
JSAutoEnterCompartment ac;
|
||||
js::ForceFrame ff(mContext, funobj);
|
||||
if (!ac.enter(mContext, funobj) || !ff.enter() ||
|
||||
!JS_WrapObject(mContext, &target)) {
|
||||
ReportPendingException();
|
||||
sSecurityManager->PopContextPrincipal(mContext);
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
@ -1902,6 +1927,8 @@ nsJSContext::CallEventHandler(nsISupports* aTarget, JSObject* aScope,
|
||||
// nested calls through XPConnect.
|
||||
if (NS_FAILED(rv))
|
||||
ReportPendingException();
|
||||
|
||||
sSecurityManager->PopContextPrincipal(mContext);
|
||||
}
|
||||
|
||||
pusher.Pop();
|
||||
|
@ -177,15 +177,32 @@ nsJSON::EncodeFromJSVal(JS::Value *value, JSContext *cx, nsAString &result)
|
||||
JSAutoRequest ar(cx);
|
||||
|
||||
JSAutoEnterCompartment ac;
|
||||
nsIScriptSecurityManager *ssm = nsnull;
|
||||
if (value->isObject()) {
|
||||
JSObject *obj = &value->toObject();
|
||||
if (!ac.enter(cx, obj)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIPrincipal> principal;
|
||||
ssm = nsContentUtils::GetSecurityManager();
|
||||
nsresult rv = ssm->GetObjectPrincipal(cx, obj, getter_AddRefs(principal));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
JSStackFrame *fp = nsnull;
|
||||
rv = ssm->PushContextPrincipal(cx, JS_FrameIterator(cx, &fp), principal);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
nsJSONWriter writer;
|
||||
if (!JS_Stringify(cx, value, NULL, JSVAL_NULL, WriteCallback, &writer)) {
|
||||
JSBool ok = JS_Stringify(cx, value, NULL, JSVAL_NULL,
|
||||
WriteCallback, &writer);
|
||||
|
||||
if (ssm) {
|
||||
ssm->PopContextPrincipal(cx);
|
||||
}
|
||||
|
||||
if (!ok) {
|
||||
return NS_ERROR_XPC_BAD_CONVERT_JS;
|
||||
}
|
||||
|
||||
|
@ -37,7 +37,9 @@
|
||||
|
||||
function respond(msg)
|
||||
{
|
||||
SpecialPowers.wrap(window).parent.postMessage(msg, "*");
|
||||
// ...so get privileges and test that this works with privileges
|
||||
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
|
||||
window.parent.postMessage(msg, "*");
|
||||
}
|
||||
|
||||
window.addEventListener("message", receiveMessage, false);
|
||||
|
@ -93,6 +93,10 @@ function chromePathIsSet(evt)
|
||||
function receiveContent(evt)
|
||||
{
|
||||
is(evt.isTrusted, true, "should have sent a trusted event");
|
||||
is(evt.origin, "http://example.org", "content response event has wrong URI");
|
||||
is(evt.source, window.frames.contentDomain,
|
||||
"wrong source for same-domain message!");
|
||||
|
||||
finish();
|
||||
}
|
||||
|
||||
|
@ -880,6 +880,20 @@ FullTrustSecMan::GetCxSubjectPrincipalAndFrame(JSContext *cx,
|
||||
return mSystemPrincipal;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
FullTrustSecMan::PushContextPrincipal(JSContext *cx,
|
||||
JSStackFrame *fp,
|
||||
nsIPrincipal *principal)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
FullTrustSecMan::PopContextPrincipal(JSContext *cx)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(nsrefcnt)
|
||||
XPCShellDirProvider::AddRef()
|
||||
{
|
||||
|
@ -1671,6 +1671,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
|
||||
@ -4339,6 +4349,8 @@ struct JSSecurityCallbacks {
|
||||
JSSubsumePrincipalsOp subsumePrincipals;
|
||||
JSObjectPrincipalsFinder findObjectPrincipals;
|
||||
JSCSPEvalChecker contentSecurityPolicyAllows;
|
||||
JSPushContextPrincipalOp pushContextPrincipal;
|
||||
JSPopContextPrincipalOp popContextPrincipal;
|
||||
};
|
||||
|
||||
extern JS_PUBLIC_API(void)
|
||||
|
@ -472,6 +472,37 @@ 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;
|
||||
if (cb->pushContextPrincipal)
|
||||
return cb->pushContextPrincipal(cx, target->principals(cx));
|
||||
return true;
|
||||
};
|
||||
|
||||
~AutoEnterCompartmentAndPushPrincipal() {
|
||||
// Pop the principal if necessary.
|
||||
if (state == STATE_OTHER_COMPARTMENT) {
|
||||
AutoCompartment *ac = getAutoCompartment();
|
||||
const JSSecurityCallbacks *cb = ac->context->runtime->securityCallbacks;
|
||||
if (cb->popContextPrincipal)
|
||||
cb->popContextPrincipal(ac->context);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
bool
|
||||
JSStructuredCloneWriter::startWrite(const Value &v)
|
||||
{
|
||||
@ -498,7 +529,7 @@ JSStructuredCloneWriter::startWrite(const 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;
|
||||
|
||||
@ -543,7 +574,7 @@ JSStructuredCloneWriter::write(const Value &v)
|
||||
RootedObject obj(context(), &objs.back().toObject());
|
||||
|
||||
// The objects in |obj| can live in other compartments.
|
||||
JSAutoEnterCompartment ac;
|
||||
AutoEnterCompartmentAndPushPrincipal ac;
|
||||
if (!ac.enter(context(), obj))
|
||||
return false;
|
||||
|
||||
|
@ -1395,6 +1395,20 @@ FullTrustSecMan::GetSubjectPrincipal(nsIPrincipal **_retval)
|
||||
return *_retval ? NS_OK : NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
/* [noscript] void pushContextPrincipal (in JSContextPtr cx, in JSStackFramePtr fp, in nsIPrincipal principal); */
|
||||
NS_IMETHODIMP
|
||||
FullTrustSecMan::PushContextPrincipal(JSContext * cx, JSStackFrame * fp, nsIPrincipal *principal)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* [noscript] void popContextPrincipal (in JSContextPtr cx); */
|
||||
NS_IMETHODIMP
|
||||
FullTrustSecMan::PopContextPrincipal(JSContext * cx)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* [noscript] nsIPrincipal getSystemPrincipal (); */
|
||||
NS_IMETHODIMP
|
||||
FullTrustSecMan::GetSystemPrincipal(nsIPrincipal **_retval)
|
||||
|
@ -1116,6 +1116,17 @@ nsXPCWrappedJSClass::CheckForException(XPCCallContext & ccx,
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
class ContextPrincipalGuard
|
||||
{
|
||||
nsIScriptSecurityManager *ssm;
|
||||
XPCCallContext &ccx;
|
||||
public:
|
||||
ContextPrincipalGuard(XPCCallContext &ccx)
|
||||
: ssm(nsnull), ccx(ccx) {}
|
||||
void principalPushed(nsIScriptSecurityManager *ssm) { this->ssm = ssm; }
|
||||
~ContextPrincipalGuard() { if (ssm) ssm->PopContextPrincipal(ccx); }
|
||||
};
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXPCWrappedJSClass::CallMethod(nsXPCWrappedJS* wrapper, uint16_t methodIndex,
|
||||
const XPTMethodDescriptor* info,
|
||||
@ -1159,6 +1170,7 @@ nsXPCWrappedJSClass::CallMethod(nsXPCWrappedJS* wrapper, uint16_t methodIndex,
|
||||
|
||||
JS::AutoValueVector args(cx);
|
||||
AutoScriptEvaluate scriptEval(cx);
|
||||
ContextPrincipalGuard principalGuard(ccx);
|
||||
|
||||
// XXX ASSUMES that retval is last arg. The xpidl compiler ensures this.
|
||||
uint8_t paramCount = info->num_args;
|
||||
@ -1172,6 +1184,28 @@ nsXPCWrappedJSClass::CallMethod(nsXPCWrappedJS* wrapper, uint16_t methodIndex,
|
||||
xpcc->SetException(nsnull);
|
||||
ccx.GetThreadData()->SetException(nsnull);
|
||||
|
||||
if (XPCPerThreadData::IsMainThread(ccx)) {
|
||||
// TODO Remove me in favor of security wrappers.
|
||||
nsIScriptSecurityManager *ssm = XPCWrapper::GetSecurityManager();
|
||||
if (ssm) {
|
||||
nsIPrincipal *objPrincipal =
|
||||
xpc::AccessCheck::getPrincipal(js::GetObjectCompartment(obj));
|
||||
if (objPrincipal) {
|
||||
JSStackFrame* fp = nsnull;
|
||||
nsresult rv =
|
||||
ssm->PushContextPrincipal(ccx, JS_FrameIterator(ccx, &fp),
|
||||
objPrincipal);
|
||||
if (NS_FAILED(rv)) {
|
||||
JS_ReportOutOfMemory(ccx);
|
||||
retval = NS_ERROR_OUT_OF_MEMORY;
|
||||
goto pre_call_clean_up;
|
||||
}
|
||||
|
||||
principalGuard.principalPushed(ssm);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We use js_Invoke so that the gcthings we use as args will be rooted by
|
||||
// the engine as we do conversions and prepare to do the function call.
|
||||
|
||||
|
@ -15,7 +15,15 @@
|
||||
|
||||
namespace xpc {
|
||||
|
||||
CrossOriginWrapper::CrossOriginWrapper(unsigned flags) : js::CrossCompartmentWrapper(flags)
|
||||
NoWaiverWrapper::NoWaiverWrapper(unsigned flags) : js::CrossCompartmentWrapper(flags)
|
||||
{
|
||||
}
|
||||
|
||||
NoWaiverWrapper::~NoWaiverWrapper()
|
||||
{
|
||||
}
|
||||
|
||||
CrossOriginWrapper::CrossOriginWrapper(unsigned flags) : NoWaiverWrapper(flags)
|
||||
{
|
||||
}
|
||||
|
||||
@ -62,4 +70,36 @@ CrossOriginWrapper::construct(JSContext *cx, JSObject *wrapper,
|
||||
WrapperFactory::WaiveXrayAndWrap(cx, rval);
|
||||
}
|
||||
|
||||
bool
|
||||
NoWaiverWrapper::enter(JSContext *cx, JSObject *wrapper, jsid id, Action act, bool *bp)
|
||||
{
|
||||
*bp = true; // always allowed
|
||||
nsIScriptSecurityManager *ssm = XPCWrapper::GetSecurityManager();
|
||||
if (!ssm) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Note: By the time enter is called here, CrossCompartmentWrapper has
|
||||
// already pushed the fake stack frame onto cx. Because of this, the frame
|
||||
// that we're clamping is the one that we want (the one in our compartment).
|
||||
JSStackFrame *fp = NULL;
|
||||
nsIPrincipal *principal = GetCompartmentPrincipal(js::GetObjectCompartment(wrappedObject(wrapper)));
|
||||
nsresult rv = ssm->PushContextPrincipal(cx, JS_FrameIterator(cx, &fp), principal);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("Not allowing call because we're out of memory");
|
||||
JS_ReportOutOfMemory(cx);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
NoWaiverWrapper::leave(JSContext *cx, JSObject *wrapper)
|
||||
{
|
||||
nsIScriptSecurityManager *ssm = XPCWrapper::GetSecurityManager();
|
||||
if (ssm) {
|
||||
ssm->PopContextPrincipal(cx);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -15,7 +15,18 @@
|
||||
|
||||
namespace xpc {
|
||||
|
||||
class CrossOriginWrapper : public js::CrossCompartmentWrapper {
|
||||
class NoWaiverWrapper : public js::CrossCompartmentWrapper {
|
||||
public:
|
||||
NoWaiverWrapper(unsigned flags);
|
||||
virtual ~NoWaiverWrapper();
|
||||
|
||||
virtual bool enter(JSContext *cx, JSObject *wrapper, jsid id, Action act, bool *bp) MOZ_OVERRIDE;
|
||||
virtual void leave(JSContext *cx, JSObject *wrapper) MOZ_OVERRIDE;
|
||||
|
||||
static NoWaiverWrapper singleton;
|
||||
};
|
||||
|
||||
class CrossOriginWrapper : public NoWaiverWrapper {
|
||||
public:
|
||||
CrossOriginWrapper(unsigned flags);
|
||||
virtual ~CrossOriginWrapper();
|
||||
|
@ -31,6 +31,13 @@ namespace xpc {
|
||||
// we know to not apply an X-ray wrapper.
|
||||
Wrapper WaiveXrayWrapperWrapper(WrapperFactory::WAIVE_XRAY_WRAPPER_FLAG);
|
||||
|
||||
// Objects that haven't been explicitly waived, but have been exposed
|
||||
// to chrome don't want a CrossOriginWrapper, since that deeply-waives
|
||||
// but need the transparent behavior of a CrossOriginWrapper. The
|
||||
// NoWaiverWrapper is like a CrossOriginWrapper that can also hand out
|
||||
// XrayWrappers as return values.
|
||||
NoWaiverWrapper NoWaiverWrapper::singleton(0);
|
||||
|
||||
// When objects for which we waived the X-ray wrapper cross into
|
||||
// chrome, we wrap them into a special cross-compartment wrapper
|
||||
// that transitively extends the waiver to all properties we get
|
||||
@ -334,7 +341,7 @@ WrapperFactory::Rewrap(JSContext *cx, JSObject *obj, JSObject *wrappedProto, JSO
|
||||
usingXray = true;
|
||||
wrapper = &Xray::singleton;
|
||||
} else {
|
||||
wrapper = &CrossCompartmentWrapper::singleton;
|
||||
wrapper = &NoWaiverWrapper::singleton;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user