Backout 5853df66d488, e8fadd906232, d787279d282c, 8c1ed6327355, 94cfcf5da7c8, 87aa103d7e87 (bug 585922) for failures in test_bug411236.html

This commit is contained in:
Ed Morley 2012-09-07 09:15:34 +01:00
parent dc77cb5f0a
commit f66e09e47d
11 changed files with 113 additions and 74 deletions

View File

@ -2176,7 +2176,7 @@ bool
nsDOMClassInfo::ObjectIsNativeWrapper(JSContext* cx, JSObject* obj)
{
return xpc::WrapperFactory::IsXrayWrapper(obj) &&
xpc::AccessCheck::isChrome(obj);
!xpc::WrapperFactory::IsPartiallyTransparent(obj);
}
nsDOMClassInfo::nsDOMClassInfo(nsDOMClassInfoData* aData) : mData(aData)

View File

@ -7,9 +7,7 @@
#include "XPCWrapper.h"
#include "AccessCheck.h"
#include "WrapperFactory.h"
#include "AccessCheck.h"
using namespace xpc;
namespace XPCNativeWrapper {
static inline
@ -39,7 +37,8 @@ UnwrapNW(JSContext *cx, unsigned argc, jsval *vp)
return true;
}
if (WrapperFactory::IsXrayWrapper(obj) && AccessCheck::isChrome(obj)) {
if (xpc::WrapperFactory::IsXrayWrapper(obj) &&
!xpc::WrapperFactory::IsPartiallyTransparent(obj)) {
return JS_GetProperty(cx, obj, "wrappedJSObject", vp);
}

View File

@ -4380,21 +4380,16 @@ GetCompartmentPrivate(JSObject *object)
return GetCompartmentPrivate(compartment);
}
inline bool IsUniversalXPConnectEnabled(JSCompartment *compartment)
{
CompartmentPrivate *priv =
static_cast<CompartmentPrivate*>(JS_GetCompartmentPrivate(compartment));
if (!priv)
return false;
return priv->universalXPConnectEnabled;
}
inline bool IsUniversalXPConnectEnabled(JSContext *cx)
{
JSCompartment *compartment = js::GetContextCompartment(cx);
if (!compartment)
return false;
return IsUniversalXPConnectEnabled(compartment);
CompartmentPrivate *priv =
static_cast<CompartmentPrivate*>(JS_GetCompartmentPrivate(compartment));
if (!priv)
return false;
return priv->universalXPConnectEnabled;
}
inline void EnableUniversalXPConnect(JSContext *cx)
@ -4407,13 +4402,6 @@ inline void EnableUniversalXPConnect(JSContext *cx)
if (!priv)
return;
priv->universalXPConnectEnabled = true;
// Recompute all the cross-compartment wrappers leaving the newly-privileged
// compartment.
mozilla::DebugOnly<bool> rv;
rv = js::RecomputeWrappers(cx, js::SingleCompartment(compartment),
js::AllCompartments());
MOZ_ASSERT(rv);
}
}

View File

@ -52,16 +52,6 @@ AccessCheck::subsumes(JSCompartment *a, JSCompartment *b)
return subsumes;
}
// Does the compartment of the wrapper subsumes the compartment of the wrappee?
bool
AccessCheck::wrapperSubsumes(JSObject *wrapper)
{
MOZ_ASSERT(js::IsWrapper(wrapper));
JSObject *wrapped = js::UnwrapObject(wrapper);
return AccessCheck::subsumes(js::GetObjectCompartment(wrapper),
js::GetObjectCompartment(wrapped));
}
bool
AccessCheck::isLocationObjectSameOrigin(JSContext *cx, JSObject *wrapper)
{
@ -101,12 +91,6 @@ AccessCheck::isChrome(JSCompartment *compartment)
return NS_SUCCEEDED(ssm->IsSystemPrincipal(principal, &privileged)) && privileged;
}
bool
AccessCheck::isChrome(JSObject *obj)
{
return isChrome(js::GetObjectCompartment(obj));
}
bool
AccessCheck::callerIsChrome()
{
@ -221,7 +205,7 @@ AccessCheck::isCrossOriginAccessPermitted(JSContext *cx, JSObject *wrapper, jsid
// PUNCTURE Is always denied for cross-origin access.
if (act == Wrapper::PUNCTURE) {
return false;
return nsContentUtils::CallerHasUniversalXPConnect();
}
const char *name;
@ -286,7 +270,7 @@ AccessCheck::isSystemOnlyAccessPermitted(JSContext *cx)
return true;
}
return false;
return NS_SUCCEEDED(ssm->IsCapabilityEnabled("UniversalXPConnect", &privileged)) && privileged;
}
bool
@ -311,7 +295,18 @@ AccessCheck::isScriptAccessOnly(JSContext *cx, JSObject *wrapper)
if (flags & WrapperFactory::SCRIPT_ACCESS_ONLY_FLAG) {
if (flags & WrapperFactory::SOW_FLAG)
return !isSystemOnlyAccessPermitted(cx);
return true;
if (flags & WrapperFactory::PARTIALLY_TRANSPARENT)
return !XrayUtils::IsTransparent(cx, wrapper);
nsIScriptSecurityManager *ssm = XPCWrapper::GetSecurityManager();
if (!ssm)
return true;
// Bypass script-only status if UniversalXPConnect is enabled.
bool privileged;
return !NS_SUCCEEDED(ssm->IsCapabilityEnabled("UniversalXPConnect", &privileged)) ||
!privileged;
}
// In addition, chrome objects can explicitly opt-in by setting .scriptOnly to true.
@ -361,6 +356,33 @@ Deny(JSContext *cx, jsid id, Wrapper::Action act)
return false;
}
bool
PermitIfUniversalXPConnect(JSContext *cx, jsid id, Wrapper::Action act,
ExposedPropertiesOnly::Permission &perm)
{
// If UniversalXPConnect is enabled, allow access even if __exposedProps__ doesn't
// exists.
nsIScriptSecurityManager *ssm = XPCWrapper::GetSecurityManager();
if (!ssm) {
return false;
}
// Double-check that the subject principal according to CAPS is a content
// principal rather than the system principal. If it isn't, this check is
// meaningless.
NS_ASSERTION(!AccessCheck::callerIsChrome(), "About to do a meaningless security check!");
bool privileged;
if (NS_SUCCEEDED(ssm->IsCapabilityEnabled("UniversalXPConnect", &privileged)) &&
privileged) {
perm = ExposedPropertiesOnly::PermitPropertyAccess;
return true; // Allow
}
// Deny
return Deny(cx, id, act);
}
static bool
IsInSandbox(JSContext *cx, JSObject *obj)
{
@ -382,12 +404,12 @@ ExposedPropertiesOnly::check(JSContext *cx, JSObject *wrapper, jsid id, Wrapper:
perm = DenyAccess;
if (act == Wrapper::PUNCTURE)
return Deny(cx, id, act);
return PermitIfUniversalXPConnect(cx, id, act, perm); // Deny
jsid exposedPropsId = GetRTIdByIndex(cx, XPCJSRuntime::IDX_EXPOSEDPROPS);
// We need to enter the wrappee's compartment to look at __exposedProps__,
// but we want to be in the wrapper's compartment if we call Deny().
// but we need to be in the wrapper's compartment to check UniversalXPConnect.
//
// Unfortunately, |cx| can be in either compartment when we call ::check. :-(
JSAutoCompartment ac(cx, wrappedObject);
@ -429,7 +451,7 @@ ExposedPropertiesOnly::check(JSContext *cx, JSObject *wrapper, jsid id, Wrapper:
perm = PermitPropertyAccess;
return true;
}
return Deny(cx, id, act);
return PermitIfUniversalXPConnect(cx, id, act, perm); // Deny
}
if (id == JSID_VOID) {
@ -444,7 +466,7 @@ ExposedPropertiesOnly::check(JSContext *cx, JSObject *wrapper, jsid id, Wrapper:
if (exposedProps.isNullOrUndefined()) {
JSAutoCompartment wrapperAC(cx, wrapper);
return Deny(cx, id, act);
return PermitIfUniversalXPConnect(cx, id, act, perm); // Deny
}
if (!exposedProps.isObject()) {
@ -463,7 +485,7 @@ ExposedPropertiesOnly::check(JSContext *cx, JSObject *wrapper, jsid id, Wrapper:
}
if (desc.obj == NULL || !(desc.attrs & JSPROP_ENUMERATE)) {
JSAutoCompartment wrapperAC(cx, wrapper);
return Deny(cx, id, act);
return PermitIfUniversalXPConnect(cx, id, act, perm); // Deny
}
if (!JSVAL_IS_STRING(desc.value)) {
@ -509,7 +531,7 @@ ExposedPropertiesOnly::check(JSContext *cx, JSObject *wrapper, jsid id, Wrapper:
if ((act == Wrapper::SET && !(access & WRITE)) ||
(act != Wrapper::SET && !(access & READ))) {
JSAutoCompartment wrapperAC(cx, wrapper);
return Deny(cx, id, act);
return PermitIfUniversalXPConnect(cx, id, act, perm); // Deny
}
perm = PermitPropertyAccess;
@ -536,15 +558,7 @@ ComponentsObjectPolicy::check(JSContext *cx, JSObject *wrapper, jsid id, Wrapper
}
}
// We don't have any way to recompute same-compartment Components wrappers,
// so we need this dynamic check. This can go away when we expose Components
// as SpecialPowers.wrap(Components) during automation.
if (xpc::IsUniversalXPConnectEnabled(cx)) {
perm = PermitPropertyAccess;
return true;
}
return Deny(cx, id, act);
return PermitIfUniversalXPConnect(cx, id, act, perm); // Deny
}
}

View File

@ -19,9 +19,7 @@ namespace xpc {
class AccessCheck {
public:
static bool subsumes(JSCompartment *a, JSCompartment *b);
static bool wrapperSubsumes(JSObject *wrapper);
static bool isChrome(JSCompartment *compartment);
static bool isChrome(JSObject *obj);
static bool callerIsChrome();
static nsIPrincipal *getPrincipal(JSCompartment *compartment);
static bool isCrossOriginAccessPermitted(JSContext *cx, JSObject *obj, jsid id,

View File

@ -125,10 +125,14 @@ template<> SOW SOW::singleton(WrapperFactory::SCRIPT_ACCESS_ONLY_FLAG |
WrapperFactory::SOW_FLAG);
template<> SCSOW SCSOW::singleton(WrapperFactory::SCRIPT_ACCESS_ONLY_FLAG |
WrapperFactory::SOW_FLAG);
template<> XOW XOW::singleton(WrapperFactory::SCRIPT_ACCESS_ONLY_FLAG);
template<> PXOW PXOW::singleton(WrapperFactory::SCRIPT_ACCESS_ONLY_FLAG);
template<> DXOW DXOW::singleton(WrapperFactory::SCRIPT_ACCESS_ONLY_FLAG);
template<> NNXOW NNXOW::singleton(WrapperFactory::SCRIPT_ACCESS_ONLY_FLAG);
template<> XOW XOW::singleton(WrapperFactory::SCRIPT_ACCESS_ONLY_FLAG |
WrapperFactory::PARTIALLY_TRANSPARENT);
template<> PXOW PXOW::singleton(WrapperFactory::SCRIPT_ACCESS_ONLY_FLAG |
WrapperFactory::PARTIALLY_TRANSPARENT);
template<> DXOW DXOW::singleton(WrapperFactory::SCRIPT_ACCESS_ONLY_FLAG |
WrapperFactory::PARTIALLY_TRANSPARENT);
template<> NNXOW NNXOW::singleton(WrapperFactory::SCRIPT_ACCESS_ONLY_FLAG |
WrapperFactory::PARTIALLY_TRANSPARENT);
template<> LW LW::singleton(WrapperFactory::SHADOWING_FORBIDDEN);
template<> XLW XLW::singleton(WrapperFactory::SHADOWING_FORBIDDEN);

View File

@ -349,8 +349,6 @@ WrapperFactory::Rewrap(JSContext *cx, JSObject *obj, JSObject *wrappedProto, JSO
}
}
}
} else if (xpc::IsUniversalXPConnectEnabled(target)) {
wrapper = &CrossCompartmentWrapper::singleton;
} else if (AccessCheck::isChrome(origin)) {
JSFunction *fun = JS_GetObjectFunction(obj);
if (fun) {

View File

@ -18,7 +18,8 @@ class WrapperFactory {
enum { WAIVE_XRAY_WRAPPER_FLAG = js::Wrapper::LAST_USED_FLAG << 1,
IS_XRAY_WRAPPER_FLAG = WAIVE_XRAY_WRAPPER_FLAG << 1,
SCRIPT_ACCESS_ONLY_FLAG = IS_XRAY_WRAPPER_FLAG << 1,
SOW_FLAG = SCRIPT_ACCESS_ONLY_FLAG << 1,
PARTIALLY_TRANSPARENT = SCRIPT_ACCESS_ONLY_FLAG << 1,
SOW_FLAG = PARTIALLY_TRANSPARENT << 1,
// Prevent scripts from shadowing native properties.
// NB: Applies only to Xray wrappers.
@ -37,6 +38,10 @@ class WrapperFactory {
return HasWrapperFlag(wrapper, IS_XRAY_WRAPPER_FLAG);
}
static bool IsPartiallyTransparent(JSObject *wrapper) {
return HasWrapperFlag(wrapper, PARTIALLY_TRANSPARENT);
}
static bool HasWaiveXrayFlag(JSObject *wrapper) {
return HasWrapperFlag(wrapper, WAIVE_XRAY_WRAPPER_FLAG);
}

View File

@ -910,6 +910,23 @@ nodePrincipal_getter(JSContext *cx, JSHandleObject wrapper, JSHandleId id, JSMut
return true;
}
static bool
ContentScriptHasUniversalXPConnect()
{
nsIScriptSecurityManager *ssm = XPCWrapper::GetSecurityManager();
if (ssm) {
// Double-check that the subject principal according to CAPS is a content
// principal rather than the system principal. If it is, this check is
// meaningless.
NS_ASSERTION(!AccessCheck::callerIsChrome(), "About to do a meaningless security check!");
bool privileged;
if (NS_SUCCEEDED(ssm->IsCapabilityEnabled("UniversalXPConnect", &privileged)) && privileged)
return true;
}
return false;
}
bool
XPCWrappedNativeXrayTraits::resolveOwnProperty(JSContext *cx, js::Wrapper &jsWrapper,
JSObject *wrapper, JSObject *holder, jsid id,
@ -919,12 +936,13 @@ XPCWrappedNativeXrayTraits::resolveOwnProperty(JSContext *cx, js::Wrapper &jsWra
// in the wrapper's compartment here, not the wrappee.
MOZ_ASSERT(js::IsObjectInContextCompartment(wrapper, cx));
XPCJSRuntime* rt = nsXPConnect::GetRuntimeInstance();
if (AccessCheck::isChrome(wrapper) &&
if (!WrapperFactory::IsPartiallyTransparent(wrapper) &&
(((id == rt->GetStringID(XPCJSRuntime::IDX_BASEURIOBJECT) ||
id == rt->GetStringID(XPCJSRuntime::IDX_NODEPRINCIPAL)) &&
Is<nsINode>(wrapper)) ||
(id == rt->GetStringID(XPCJSRuntime::IDX_DOCUMENTURIOBJECT) &&
Is<nsIDocument>(wrapper)))) {
Is<nsIDocument>(wrapper))) &&
(AccessCheck::callerIsChrome() || ContentScriptHasUniversalXPConnect())) {
bool status;
Wrapper::Action action = set ? Wrapper::SET : Wrapper::GET;
desc->obj = NULL; // default value
@ -1280,7 +1298,16 @@ namespace XrayUtils {
bool
IsTransparent(JSContext *cx, JSObject *wrapper)
{
return WrapperFactory::HasWaiveXrayFlag(wrapper);
if (WrapperFactory::HasWaiveXrayFlag(wrapper))
return true;
if (!WrapperFactory::IsPartiallyTransparent(wrapper))
return false;
// Redirect access straight to the wrapper if UniversalXPConnect is enabled.
// We don't need to check for system principal here, because only content
// scripts have Partially Transparent wrappers.
return ContentScriptHasUniversalXPConnect();
}
JSObject *
@ -1387,11 +1414,10 @@ XrayWrapper<Base, Traits>::getPropertyDescriptor(JSContext *cx, JSObject *wrappe
if (!holder)
return false;
// Only chrome wrappers and same-origin xrays (used by jetpack sandboxes)
// get .wrappedJSObject. We can check this by determining if the compartment
// of the wrapper subsumes that of the wrappee.
// Partially transparent wrappers (which used to be known as XOWs) don't
// have a .wrappedJSObject property.
XPCJSRuntime* rt = nsXPConnect::GetRuntimeInstance();
if (AccessCheck::wrapperSubsumes(wrapper) &&
if (!WrapperFactory::IsPartiallyTransparent(wrapper) &&
id == rt->GetStringID(XPCJSRuntime::IDX_WRAPPED_JSOBJECT)) {
bool status;
Wrapper::Action action = set ? Wrapper::SET : Wrapper::GET;
@ -1582,7 +1608,7 @@ XrayWrapper<Base, Traits>::enumerate(JSContext *cx, JSObject *wrapper, unsigned
return js::GetPropertyNames(cx, obj, flags, &props);
}
if (!AccessCheck::isChrome(wrapper)) {
if (WrapperFactory::IsPartiallyTransparent(wrapper)) {
JS_ReportError(cx, "Not allowed to enumerate cross origin objects");
return false;
}

View File

@ -7,10 +7,13 @@
<input type=text>
<script>
function doTest() {
netscape.security.PrivilegeManager.enablePrivilege(
"UniversalXPConnect");
var d = document.querySelector("input");
d.value = "b";
d.focus();
var editor = SpecialPowers.wrap(d).QueryInterface(Components.interfaces.nsIDOMNSEditableElement).editor;
var editor = d.QueryInterface(Components.interfaces.nsIDOMNSEditableElement).editor;
var sel = editor.selection;
var t = editor.rootElement.firstChild;
sel.collapse(t, 1); // put the caret at the end of the textbox

View File

@ -7,6 +7,8 @@
<input type=text>
<script>
function doTest() {
netscape.security.PrivilegeManager.enablePrivilege(
"UniversalXPConnect");
function enableCaret(aEnable) {
var selCon = editor.selectionController;
selCon.setCaretEnabled(aEnable);
@ -15,11 +17,13 @@
var d = document.querySelector("input");
d.value = "a";
d.focus();
var editor = SpecialPowers.wrap(d).QueryInterface(Components.interfaces.nsIDOMNSEditableElement).editor;
var editor = d.QueryInterface(Components.interfaces.nsIDOMNSEditableElement).editor;
var sel = editor.selection;
var t = editor.rootElement.firstChild;
sel.collapse(t, 1); // put the caret at the end of the div
setTimeout(function() {
netscape.security.PrivilegeManager.enablePrivilege(
"UniversalXPConnect");
enableCaret(false);enableCaret(true);// force a caret display
enableCaret(false); // hide the caret
t.replaceData(0, 1, "b"); // replace the text node data