Components.classesにアクセスできない理由

Componentsはnativeコードで実装されているのでXPCWrapperdNativeというクラスを介してアクセスされる。
javascriptからのアクセスはXPCWrapperdNative::CallMethodを通して行われる。このCallMethodの中でセキュリティチェックが行われる。

#0 0x0f2f8569 in nsScriptSecurityManager::CheckPropertyAccessImpl at nsScriptSecurityManager.cpp:759
#1 0x0f2f8f47 in nsScriptSecurityManager::CanAccess at nsScriptSecurityManager.cpp:3040
#2 0x0aa44360 in XPCWrappedNative::CallMethod at xpcwrappednative.cpp:1935
#3 0x0aa80ebd in XPCWrappedNative::GetAttribute at xpcwrappednativejsops.cpp:2117

CanAccessはCheckPropertyAccessImplをよんでるだけ。

nsresult
nsScriptSecurityManager::CheckPropertyAccessImpl(PRUint32 aAction,
                                                 nsIXPCNativeCallContext* aCallContext,
                                                 JSContext* cx, JSObject* aJSObject,
                                                 nsISupports* aObj, nsIURI* aTargetURI,
                                                 nsIClassInfo* aClassInfo,
                                                 const char* aClassName, jsval aProperty,
                                                 void** aCachedClassPolicy)
{
    nsresult rv;
    nsIPrincipal* subjectPrincipal = GetSubjectPrincipal(cx, &rv);
    if (NS_FAILED(rv))
        return rv;

    if (!subjectPrincipal || subjectPrincipal == mSystemPrincipal)
        // We have native code or the system principal: just allow access
        return NS_OK;

    // Hold the class info data here so we don't have to go back to virtual
    // methods all the time
    ClassInfoData classInfoData(aClassInfo, aClassName);
#ifdef DEBUG_CAPS_CheckPropertyAccessImpl
    nsCAutoString propertyName;
    propertyName.AssignWithConversion((PRUnichar*)JSValIDToString(cx, aProperty));
    printf("### CanAccess(%s.%s, %i) ", classInfoData.GetName(),
           propertyName.get(), aAction);
#endif

    //-- Look up the security policy for this class and subject domain
    SecurityLevel securityLevel;
    rv = LookupPolicy(subjectPrincipal, classInfoData, aProperty, aAction,
                      (ClassPolicy**)aCachedClassPolicy, &securityLevel);
    if (NS_FAILED(rv))
        return rv;

ふつうの、スクリプトで定義したオブジェクトにアクセスするだけのときはここには来ない。
はじめに述べたとおり、ここはXPCOMコンポーネントから生成されたオブジェクトのメソッドを呼び出すときにアクセスするときに呼び出されるものなので、スクリプトで定義されたオブジェクトのプロパティを読み出すときには通らない。
身近なものではwindow.alertやwindow.openを呼んだ時にネイティブコードがオブジェクトのプロパティを参照するためここを通る。

ほとんどの場合Firefox内部からの呼び出しで、はじめの10行でreturnする。
Componentsのときはsubjectのprincipalのcodebaseは開いているウインドウのuriになっていた。systemじゃなかった。
LookupPolicyではuser_prefで設定したりするポリシーが参照される。よくわかりません。
ドメインポリシー、クラスポリシー、プロパティーポリシーとかチェック。Componentsの場合全部ひっかからなくてNS_OKになる。

そのあとでひっかかる。
securityLevel.level == SCRIPT_SECURITY_UNDEFINED_ACCESS になっていてDOMクラスかどうかチェックされるけどComponentsはDOMクラスじゃないのでNG.
SCRIPT_SECURITY_NO_ACCESSが設定されます。

    if (securityLevel.level == SCRIPT_SECURITY_UNDEFINED_ACCESS)
    {   
        // No policy found for this property so use the default of last resort.
        // If we were called from somewhere other than XPConnect
        // (no XPC call context), assume this is a DOM class. Otherwise,
        // ask the ClassInfo.
        if (!aCallContext || classInfoData.IsDOMClass())
            securityLevel.level = SCRIPT_SECURITY_SAME_ORIGIN_ACCESS;
        else
            securityLevel.level = SCRIPT_SECURITY_NO_ACCESS;
    }

    if (SECURITY_ACCESS_LEVEL_FLAG(securityLevel))
    // This flag means securityLevel is allAccess, noAccess, or sameOrigin
    {
        switch (securityLevel.level)
        {
        case SCRIPT_SECURITY_NO_ACCESS:
#ifdef DEBUG_CAPS_CheckPropertyAccessImpl
            printf("noAccess ");
#endif
            rv = NS_ERROR_DOM_PROP_ACCESS_DENIED;
            break;
            

そのあとSecurityCheckedComponent(なんなのか不明)だったらokという敗者復活戦がある。

    //--See if the object advertises a non-default level of access
    //  using nsISecurityCheckedComponent
    nsCOMPtr<nsISecurityCheckedComponent> checkedComponent =
        do_QueryInterface(aObj);

最後にエラー文字列を返しておしまいです。エラーコードではなく文字列を呼び出しもとに返すようになってるようです。

    if (NS_FAILED(rv)) //-- Security tests failed, access is denied, report error
    {
        nsAutoString stringName;
        switch(aAction)
        {
        case nsIXPCSecurityManager::ACCESS_GET_PROPERTY:
            stringName.AssignLiteral("GetPropertyDenied");
            break;

XPCWrapperdNativeであってもDOMのインスタンスであればアクセスができる。というのがミソ。
window.alert()を呼んだときにも同様に securityLevel.level == SCRIPT_SECURITY_UNDEFINED_ACCESS で同じところに来るが、アクセスしているプロパティがDOMのクラスでエラーにならないで済む。


このふたつでどれくらい説明つくか試してみる。
__parent__のほうは誰か賢いひとが助けてくれたらいいな...