Bug 304048 - "xpconnect getters/setters don't have principals until after they pass or fail their security check." Patch by jst, sr=bzbarsky, a=jst.

This commit is contained in:
bent.mozilla@gmail.com 2007-08-28 17:16:21 -07:00
Родитель 7a36d83fa1
Коммит 5f9effcd34
7 изменённых файлов: 149 добавлений и 18 удалений

Просмотреть файл

@ -493,6 +493,12 @@ nsScriptSecurityManager::CheckObjectAccess(JSContext *cx, JSObject *obj,
if (!ssm) if (!ssm)
return JS_FALSE; return JS_FALSE;
nsCOMPtr<nsISupports> native;
nsresult rv =
sXPConnect->GetNativeOfJSObject(cx, obj,
NS_GET_IID(nsISupports),
getter_AddRefs(native));
// Get the object being accessed. We protect these cases: // Get the object being accessed. We protect these cases:
// 1. The Function.prototype.caller property's value, which might lead // 1. The Function.prototype.caller property's value, which might lead
// an attacker up a call-stack to a function or another object from // an attacker up a call-stack to a function or another object from
@ -505,11 +511,13 @@ nsScriptSecurityManager::CheckObjectAccess(JSContext *cx, JSObject *obj,
// Do the same-origin check -- this sets a JS exception if the check fails. // Do the same-origin check -- this sets a JS exception if the check fails.
// Pass the parent object's class name, as we have no class-info for it. // Pass the parent object's class name, as we have no class-info for it.
nsresult rv = rv = ssm->CheckPropertyAccessImpl(( (mode & JSACC_WRITE) ?
ssm->CheckPropertyAccess(cx, target, JS_GetClass(cx, obj)->name, id,
(mode & JSACC_WRITE) ?
nsIXPCSecurityManager::ACCESS_SET_PROPERTY : nsIXPCSecurityManager::ACCESS_SET_PROPERTY :
nsIXPCSecurityManager::ACCESS_GET_PROPERTY); nsIXPCSecurityManager::ACCESS_GET_PROPERTY ),
nsnull, cx, target, native, nsnull,
nsnull, JS_GET_CLASS(cx, obj)->name, id,
nsnull);
if (NS_FAILED(rv)) if (NS_FAILED(rv))
return JS_FALSE; // Security check failed (XXX was an error reported?) return JS_FALSE; // Security check failed (XXX was an error reported?)
@ -771,14 +779,24 @@ nsScriptSecurityManager::CheckPropertyAccessImpl(PRUint32 aAction,
nsXPIDLCString objectSecurityLevel; nsXPIDLCString objectSecurityLevel;
if (checkedComponent) if (checkedComponent)
{ {
const nsIID* objIID = nsnull;
if (aCallContext) {
// If we have a call context, find the wrapper and the IID
// with the member in question to pass to
// nsISecurityCheckedComponent, if not, pass a null IID
// and it's up to the implementation to decide whether or
// not it wants to permit access.
nsCOMPtr<nsIXPConnectWrappedNative> wrapper; nsCOMPtr<nsIXPConnectWrappedNative> wrapper;
nsCOMPtr<nsIInterfaceInfo> interfaceInfo; nsCOMPtr<nsIInterfaceInfo> interfaceInfo;
const nsIID* objIID;
rv = aCallContext->GetCalleeWrapper(getter_AddRefs(wrapper)); rv = aCallContext->GetCalleeWrapper(getter_AddRefs(wrapper));
if (NS_SUCCEEDED(rv)) if (NS_SUCCEEDED(rv))
rv = wrapper->FindInterfaceWithMember(aProperty, getter_AddRefs(interfaceInfo)); rv = wrapper->FindInterfaceWithMember(aProperty, getter_AddRefs(interfaceInfo));
if (NS_SUCCEEDED(rv)) if (NS_SUCCEEDED(rv))
rv = interfaceInfo->GetIIDShared(&objIID); rv = interfaceInfo->GetIIDShared(&objIID);
} else {
rv = NS_OK;
}
if (NS_SUCCEEDED(rv)) if (NS_SUCCEEDED(rv))
{ {
switch (aAction) switch (aAction)

Просмотреть файл

@ -674,6 +674,17 @@ interface nsIXPConnect : nsISupports
*/ */
void flagSystemFilenamePrefix(in string aFilenamePrefix); void flagSystemFilenamePrefix(in string aFilenamePrefix);
/**
* Get a native pointer of type aIID from aJSObject if the object
* is a wrapped native or a wrapped JS object, but never create a
* new wrapper, only use existing ones.
*/
void
getNativeOfJSObject(in JSContextPtr aJSContext,
in JSObjectPtr aJSObj,
in nsIIDRef aIID,
[iid_is(aIID),retval] out nsQIResult result);
/** /**
* Restore an old prototype for wrapped natives of type * Restore an old prototype for wrapped natives of type
* aClassInfo. This should be used only when restoring an old * aClassInfo. This should be used only when restoring an old

Просмотреть файл

@ -331,6 +331,7 @@ JSBool XPCDispConvert::JSToCOM(XPCCallContext& ccx,
obj, obj,
&NSID_IDISPATCH, &NSID_IDISPATCH,
nsnull, nsnull,
PR_TRUE,
&err)) &err))
{ {
// Avoid cleaning up garbage // Avoid cleaning up garbage

Просмотреть файл

@ -1112,7 +1112,7 @@ nsXPConnect::WrapJS(JSContext * aJSContext,
nsresult rv; nsresult rv;
if(!XPCConvert::JSObject2NativeInterface(ccx, result, aJSObj, if(!XPCConvert::JSObject2NativeInterface(ccx, result, aJSObj,
&aIID, nsnull, &rv)) &aIID, nsnull, PR_TRUE, &rv))
return rv; return rv;
return NS_OK; return NS_OK;
} }
@ -1138,7 +1138,7 @@ nsXPConnect::WrapJSAggregatedToNative(nsISupports *aOuter,
nsresult rv; nsresult rv;
if(!XPCConvert::JSObject2NativeInterface(ccx, result, aJSObj, if(!XPCConvert::JSObject2NativeInterface(ccx, result, aJSObj,
&aIID, aOuter, &rv)) &aIID, aOuter, PR_TRUE, &rv))
return rv; return rv;
return NS_OK; return NS_OK;
} }
@ -2097,6 +2097,30 @@ nsXPConnect::OnDispatchedEvent(nsIThreadInternal* aThread)
return NS_ERROR_UNEXPECTED; return NS_ERROR_UNEXPECTED;
} }
/* void getNativeOfJSObject(in JSContextPtr aJSContext, in JSObjectPtr aJSObj, in nsIIDRef aIID, [iid_is(aIID),retval] out nsQIResult result); */
NS_IMETHODIMP
nsXPConnect::GetNativeOfJSObject(JSContext * aJSContext,
JSObject * aJSObj,
const nsIID & aIID,
void * *result)
{
NS_ASSERTION(aJSContext, "bad param");
NS_ASSERTION(aJSObj, "bad param");
NS_ASSERTION(result, "bad param");
*result = nsnull;
XPCCallContext ccx(NATIVE_CALLER, aJSContext);
if(!ccx.IsValid())
return UnexpectedFailure(NS_ERROR_FAILURE);
nsresult rv;
if(!XPCConvert::JSObject2NativeInterface(ccx, result, aJSObj,
&aIID, nsnull, PR_FALSE, &rv))
return rv;
return NS_OK;
}
#ifdef DEBUG #ifdef DEBUG
/* These are here to be callable from a debugger */ /* These are here to be callable from a debugger */
JS_BEGIN_EXTERN_C JS_BEGIN_EXTERN_C

Просмотреть файл

@ -1030,7 +1030,7 @@ XPCConvert::JSData2Native(XPCCallContext& ccx, void* d, jsval s,
} }
return JSObject2NativeInterface(ccx, (void**)d, obj, iid, return JSObject2NativeInterface(ccx, (void**)d, obj, iid,
nsnull, pErr); nsnull, PR_TRUE, pErr);
} }
default: default:
NS_ASSERTION(0, "bad type"); NS_ASSERTION(0, "bad type");
@ -1230,6 +1230,7 @@ XPCConvert::JSObject2NativeInterface(XPCCallContext& ccx,
void** dest, JSObject* src, void** dest, JSObject* src,
const nsID* iid, const nsID* iid,
nsISupports* aOuter, nsISupports* aOuter,
PRBool allowCreateNew,
nsresult* pErr) nsresult* pErr)
{ {
NS_ASSERTION(dest, "bad param"); NS_ASSERTION(dest, "bad param");
@ -1288,8 +1289,15 @@ XPCConvert::JSObject2NativeInterface(XPCCallContext& ccx,
// else... // else...
nsresult rv;
nsXPCWrappedJS* wrapper; nsXPCWrappedJS* wrapper;
nsresult rv = nsXPCWrappedJS::GetNewOrUsed(ccx, src, *iid, aOuter, &wrapper); if (allowCreateNew) {
rv = nsXPCWrappedJS::GetNewOrUsed(ccx, src, *iid, aOuter, &wrapper);
} else {
rv = nsXPCWrappedJS::GetUsedOnly(ccx, src, *iid, aOuter, &wrapper);
}
if(pErr) if(pErr)
*pErr = rv; *pErr = rv;
if(NS_SUCCEEDED(rv) && wrapper) if(NS_SUCCEEDED(rv) && wrapper)

Просмотреть файл

@ -2356,6 +2356,12 @@ public:
REFNSIID aIID, REFNSIID aIID,
nsISupports* aOuter, nsISupports* aOuter,
nsXPCWrappedJS** wrapper); nsXPCWrappedJS** wrapper);
static nsresult
GetUsedOnly(XPCCallContext& ccx,
JSObject* aJSObj,
REFNSIID aIID,
nsISupports* aOuter,
nsXPCWrappedJS** wrapperResult);
nsISomeInterface* GetXPTCStub() { return mXPTCStub; } nsISomeInterface* GetXPTCStub() { return mXPTCStub; }
JSObject* GetJSObject() const {return mJSObj;} JSObject* GetJSObject() const {return mJSObj;}
@ -2531,6 +2537,7 @@ public:
void** dest, JSObject* src, void** dest, JSObject* src,
const nsID* iid, const nsID* iid,
nsISupports* aOuter, nsISupports* aOuter,
PRBool allowCreateNew,
nsresult* pErr); nsresult* pErr);
/** /**

Просмотреть файл

@ -417,6 +417,68 @@ return_wrapper:
return NS_OK; return NS_OK;
} }
// static
nsresult
nsXPCWrappedJS::GetUsedOnly(XPCCallContext& ccx,
JSObject* aJSObj,
REFNSIID aIID,
nsISupports* aOuter,
nsXPCWrappedJS** wrapperResult)
{
JSObject2WrappedJSMap* map;
JSBool hasProp;
JSObject* rootJSObj;
nsXPCWrappedJS* root;
nsXPCWrappedJS* wrapper = nsnull;
nsXPCWrappedJSClass *clazz = nsnull;
XPCJSRuntime* rt = ccx.GetRuntime();
map = rt->GetWrappedJSMap();
if(!map)
{
NS_ASSERTION(map,"bad map");
return NS_ERROR_FAILURE;
}
nsXPCWrappedJSClass::GetNewOrUsed(ccx, aIID, &clazz);
if(!clazz)
return NS_ERROR_FAILURE;
// GetRootJSObject will attempt to call a QueryInterface function on
// aJSObj. If QueryInterface doesn't exist on the object then a strict
// warning will be emitted, so check to make sure that the QueryInterface
// function exists before proceeding.
if(JS_HasProperty(ccx.GetJSContext(), aJSObj,
rt->GetStringName(XPCJSRuntime::IDX_QUERY_INTERFACE),
&hasProp) && hasProp)
rootJSObj = clazz->GetRootJSObject(ccx, aJSObj);
else
rootJSObj = aJSObj;
NS_RELEASE(clazz);
if(!rootJSObj)
return NS_ERROR_FAILURE;
// look for the root wrapper
{ // scoped lock
XPCAutoLock lock(rt->GetMapLock());
root = map->Find(rootJSObj);
}
if(root)
{
if((nsnull != (wrapper = root->Find(aIID))) ||
(nsnull != (wrapper = root->FindInherited(aIID))))
{
NS_ADDREF(wrapper);
}
}
*wrapperResult = wrapper;
return NS_OK;
}
nsXPCWrappedJS::nsXPCWrappedJS(XPCCallContext& ccx, nsXPCWrappedJS::nsXPCWrappedJS(XPCCallContext& ccx,
JSObject* aJSObj, JSObject* aJSObj,
nsXPCWrappedJSClass* aClass, nsXPCWrappedJSClass* aClass,