eval第二引数permission denied

こっちはわりと素直。

jsobj.c

    /*
     * Script.prototype.compile/exec and Object.prototype.eval all take an
     * optional trailing argument that overrides the scope object.
     */
    if (argc >= 2) {
        if (!js_ValueToObject(cx, argv[1], &scopeobj))
            return JS_FALSE;
        argv[1] = OBJECT_TO_JSVAL(scopeobj);
    }
.....


    /* Ensure we compile this eval with the right object in the scope chain. */
    scopeobj = js_CheckScopeChainValidity(cx, scopeobj, js_eval_str);

evalの第二引数のスコープチェインをたどる。

JSObject *
js_CheckScopeChainValidity(JSContext *cx, JSObject *scopeobj, const char *caller)
{
    JSClass *clasp;
    JSExtendedClass *xclasp;
    JSObject *inner;

    if (!scopeobj)
        goto bad;

    OBJ_TO_INNER_OBJECT(cx, scopeobj);
    if (!scopeobj)
        return NULL;

    inner = scopeobj;

    /* XXX This is an awful gross hack. */
    while (scopeobj) {
        clasp = OBJ_GET_CLASS(cx, scopeobj);
        if (clasp->flags & JSCLASS_IS_EXTENDED) {
            xclasp = (JSExtendedClass*)clasp;
            if (xclasp->innerObject &&
                xclasp->innerObject(cx, scopeobj) != scopeobj) {
                goto bad;
            }
        }

        scopeobj = OBJ_GET_PARENT(cx, scopeobj);
    }

    return inner;

bad:
    JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                         JSMSG_BAD_INDIRECT_CALL, caller);
    return NULL;
}

その途中にJSCLASS_IS_EXTENDEDのクラスがあったらNG.
spidermonkey内部にはJSClassというのとJSExtendedClassというのがあってJSCLASS_IS_EXTENDEDというのは後者のときにセットされているフラグ。
XPCOMコンポーネントなどのXPCWrapperdNativeを通してアクセスされるオブジェクトは、spidermonkeyの中で内部的に生成されるクラスがJSExtendedClassになっている。
第二引数に渡すオブジェクトが、ユーザがスクリプト内で定義したjavascriptのクラスであればJSExtendedClassではなくJSClassなのでチェックをパスできる。が、スクリプトで定義されたものではなくXPCOM由来オブジェクトなどを第二引数に渡すと、ここのチェックにひっかかって JSMSG_BAD_INDIRECT_CALL が出る。(function eval must be called directly, and not by way of a function of another nameってやつ)