Implement new chrome wrappers (574539, r=mrbkap).

This commit is contained in:
Andreas Gal 2010-06-25 17:58:09 -05:00
parent 11099189c8
commit 6f976ada12
12 changed files with 754 additions and 103 deletions

View File

@ -149,6 +149,22 @@ NewKeyValuePair(JSContext *cx, jsid key, jsval val, jsval *rval)
return true;
}
static bool
IdToIteratorValue(JSContext *cx, JSObject *obj, jsid id, uintN flags, jsval *vp)
{
if (!(flags & JSITER_FOREACH)) {
*vp = ID_TO_VALUE(id);
return true;
}
/* Do the lookup on the original object instead of the prototype. */
if (!obj->getProperty(cx, id, vp))
return false;
if ((flags & JSITER_KEYVALUE) && !NewKeyValuePair(cx, id, *vp, vp))
return false;
return true;
}
static inline bool
Enumerate(JSContext *cx, JSObject *obj, JSObject *pobj, jsid id,
bool enumerable, uintN flags, HashSet<jsid>& ht,
@ -166,17 +182,10 @@ Enumerate(JSContext *cx, JSObject *obj, JSObject *pobj, jsid id,
return false;
}
if (enumerable || (flags & JSITER_HIDDEN)) {
if (!vec.append(ID_TO_VALUE(id)))
if (!vec.append(JSVAL_VOID))
return false;
if (!IdToIteratorValue(cx, obj, id, flags, vec.end() - 1))
return false;
if (flags & JSITER_FOREACH) {
jsval *vp = vec.end() - 1;
/* Do the lookup on the original object instead of the prototype. */
if (!obj->getProperty(cx, id, vp))
return false;
if ((flags & JSITER_KEYVALUE) && !NewKeyValuePair(cx, id, *vp, vp))
return false;
}
}
return true;
}
@ -434,6 +443,16 @@ IdVectorToIterator(JSContext *cx, JSObject *obj, uintN flags, AutoValueVector &p
if (!ni)
return false;
/* If this is a for-each iteration, fetch the values or key/value pairs. */
if (flags & JSITER_FOREACH) {
size_t length = props.length();
for (size_t n = 0; n < length; ++n) {
jsval *vp = &ni->begin()[n];
if (!IdToIteratorValue(cx, obj, *vp, flags, vp))
return false;
}
}
iterobj->setNativeIterator(ni);
RegisterEnumerator(cx, iterobj, ni);

View File

@ -472,14 +472,14 @@ JSCrossCompartmentWrapper::~JSCrossCompartmentWrapper()
{
}
#define PIERCE(cx, proxy, pre, op, post) \
JS_BEGIN_MACRO \
AutoCompartment call(cx, wrappedObject(proxy)); \
if (!call.enter() || !(pre) || !enter(cx, proxy, id) || !(op)) \
return false; \
leave(cx, proxy); \
call.leave(); \
return (post); \
#define PIERCE(cx, proxy, mode, pre, op, post) \
JS_BEGIN_MACRO \
AutoCompartment call(cx, wrappedObject(proxy)); \
if (!call.enter() || !(pre) || !enter(cx, proxy, id, mode) || !(op)) \
return false; \
leave(cx, proxy); \
call.leave(); \
return (post); \
JS_END_MACRO
#define NOTHING (true)
@ -487,7 +487,7 @@ JSCrossCompartmentWrapper::~JSCrossCompartmentWrapper()
bool
JSCrossCompartmentWrapper::getPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, JSPropertyDescriptor *desc)
{
PIERCE(cx, proxy,
PIERCE(cx, proxy, GET,
call.destination->wrapId(cx, &id),
JSWrapper::getPropertyDescriptor(cx, proxy, id, desc),
call.origin->wrap(cx, desc));
@ -496,7 +496,7 @@ JSCrossCompartmentWrapper::getPropertyDescriptor(JSContext *cx, JSObject *proxy,
bool
JSCrossCompartmentWrapper::getOwnPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, JSPropertyDescriptor *desc)
{
PIERCE(cx, proxy,
PIERCE(cx, proxy, GET,
call.destination->wrapId(cx, &id),
JSWrapper::getOwnPropertyDescriptor(cx, proxy, id, desc),
call.origin->wrap(cx, desc));
@ -506,7 +506,7 @@ bool
JSCrossCompartmentWrapper::defineProperty(JSContext *cx, JSObject *proxy, jsid id, JSPropertyDescriptor *desc)
{
AutoDescriptor desc2(cx, desc);
PIERCE(cx, proxy,
PIERCE(cx, proxy, SET,
call.destination->wrapId(cx, &id) && call.destination->wrap(cx, &desc2),
JSWrapper::getOwnPropertyDescriptor(cx, proxy, id, &desc2),
NOTHING);
@ -515,16 +515,16 @@ JSCrossCompartmentWrapper::defineProperty(JSContext *cx, JSObject *proxy, jsid i
bool
JSCrossCompartmentWrapper::getOwnPropertyNames(JSContext *cx, JSObject *proxy, AutoValueVector &props)
{
PIERCE(cx, proxy,
PIERCE(cx, proxy, GET,
NOTHING,
JSWrapper::getOwnPropertyNames(cx, proxy, props),
filter(cx, proxy, props) && call.origin->wrap(cx, props));
call.origin->wrap(cx, props));
}
bool
JSCrossCompartmentWrapper::delete_(JSContext *cx, JSObject *proxy, jsid id, bool *bp)
{
PIERCE(cx, proxy,
PIERCE(cx, proxy, SET,
call.destination->wrapId(cx, &id),
JSWrapper::delete_(cx, proxy, id, bp),
NOTHING);
@ -533,16 +533,16 @@ JSCrossCompartmentWrapper::delete_(JSContext *cx, JSObject *proxy, jsid id, bool
bool
JSCrossCompartmentWrapper::enumerate(JSContext *cx, JSObject *proxy, AutoValueVector &props)
{
PIERCE(cx, proxy,
PIERCE(cx, proxy, GET,
NOTHING,
JSWrapper::enumerate(cx, proxy, props),
filter(cx, proxy, props) && call.origin->wrap(cx, props));
call.origin->wrap(cx, props));
}
bool
JSCrossCompartmentWrapper::has(JSContext *cx, JSObject *proxy, jsid id, bool *bp)
{
PIERCE(cx, proxy,
PIERCE(cx, proxy, GET,
call.destination->wrapId(cx, &id),
JSWrapper::has(cx, proxy, id, bp),
NOTHING);
@ -551,7 +551,7 @@ JSCrossCompartmentWrapper::has(JSContext *cx, JSObject *proxy, jsid id, bool *bp
bool
JSCrossCompartmentWrapper::hasOwn(JSContext *cx, JSObject *proxy, jsid id, bool *bp)
{
PIERCE(cx, proxy,
PIERCE(cx, proxy, GET,
call.destination->wrapId(cx, &id),
JSWrapper::hasOwn(cx, proxy, id, bp),
NOTHING);
@ -560,7 +560,7 @@ JSCrossCompartmentWrapper::hasOwn(JSContext *cx, JSObject *proxy, jsid id, bool
bool
JSCrossCompartmentWrapper::get(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, jsval *vp)
{
PIERCE(cx, proxy,
PIERCE(cx, proxy, GET,
call.destination->wrap(cx, &receiver) && call.destination->wrapId(cx, &id),
JSWrapper::get(cx, proxy, receiver, id, vp),
call.origin->wrap(cx, vp));
@ -570,7 +570,7 @@ bool
JSCrossCompartmentWrapper::set(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, jsval *vp)
{
AutoValueRooter tvr(cx, *vp);
PIERCE(cx, proxy,
PIERCE(cx, proxy, SET,
call.destination->wrap(cx, &receiver) && call.destination->wrapId(cx, &id) && call.destination->wrap(cx, tvr.addr()),
JSWrapper::set(cx, proxy, receiver, id, tvr.addr()),
NOTHING);
@ -579,19 +579,49 @@ JSCrossCompartmentWrapper::set(JSContext *cx, JSObject *proxy, JSObject *receive
bool
JSCrossCompartmentWrapper::enumerateOwn(JSContext *cx, JSObject *proxy, AutoValueVector &props)
{
PIERCE(cx, proxy,
PIERCE(cx, proxy, GET,
NOTHING,
JSWrapper::enumerateOwn(cx, proxy, props),
filter(cx, proxy, props) && call.origin->wrap(cx, props));
call.origin->wrap(cx, props));
}
/*
* We can reify non-escaping iterator objects instead of having to wrap them. This
* allows fast iteration over objects across a compartment boundary.
*/
static bool
CanReify(jsval *vp)
{
return !JSVAL_IS_PRIMITIVE(*vp) &&
JSVAL_TO_OBJECT(*vp)->getClass() == &js_IteratorClass.base &&
!!(JSVAL_TO_OBJECT(*vp)->getNativeIterator()->flags & JSITER_ENUMERATE);
}
static bool
Reify(JSContext *cx, JSCompartment *origin, jsval *vp)
{
JSObject *iterObj = JSVAL_TO_OBJECT(*vp);
NativeIterator *ni = iterObj->getNativeIterator();
AutoValueVector props(cx);
size_t length = ni->length();
if (length > 0) {
props.resize(length);
for (size_t n = 0; n < length; ++n)
props[n] = origin->wrap(cx, &ni->begin()[n]);
}
JSObject *obj = ni->obj;
return origin->wrap(cx, &obj) &&
IdVectorToIterator(cx, obj, ni->flags, props, vp);
}
bool
JSCrossCompartmentWrapper::iterate(JSContext *cx, JSObject *proxy, uintN flags, jsval *vp)
{
PIERCE(cx, proxy,
PIERCE(cx, proxy, GET,
NOTHING,
JSWrapper::iterate(cx, proxy, flags, vp),
filter(cx, proxy, vp) && call.origin->wrap(cx, vp));
CanReify(vp) ? Reify(cx, call.origin, vp) : call.origin->wrap(cx, vp));
}
bool
@ -612,7 +642,7 @@ JSCrossCompartmentWrapper::call(JSContext *cx, JSObject *proxy, uintN argc, jsva
jsval *fakevp = call.getvp();
fakevp[0] = vp[0];
fakevp[1] = vp[1];
if (!enter(cx, proxy, JSVAL_VOID) || !JSWrapper::call(cx, proxy, argc, vp))
if (!enter(cx, proxy, JSVAL_VOID, GET) || !JSWrapper::call(cx, proxy, argc, vp))
return false;
leave(cx, proxy);
@ -635,7 +665,7 @@ JSCrossCompartmentWrapper::construct(JSContext *cx, JSObject *proxy, JSObject *r
jsval *vp = call.getvp();
vp[0] = OBJECT_TO_JSVAL(call.target);
if (!call.destination->wrap(cx, &receiver) ||
!enter(cx, proxy, JSVAL_VOID) ||
!enter(cx, proxy, JSVAL_VOID, GET) ||
!JSWrapper::construct(cx, proxy, receiver, argc, argv, rval)) {
return false;
}
@ -653,7 +683,7 @@ JSCrossCompartmentWrapper::obj_toString(JSContext *cx, JSObject *proxy)
if (!call.enter())
return NULL;
if (!enter(cx, proxy, JSVAL_VOID))
if (!enter(cx, proxy, JSVAL_VOID, GET))
return NULL;
JSString *str = JSWrapper::obj_toString(cx, proxy);
if (!str)
@ -674,7 +704,7 @@ JSCrossCompartmentWrapper::fun_toString(JSContext *cx, JSObject *proxy, uintN in
if (!call.enter())
return NULL;
if (!enter(cx, proxy, JSVAL_VOID))
if (!enter(cx, proxy, JSVAL_VOID, GET))
return NULL;
JSString *str = JSWrapper::fun_toString(cx, proxy, indent);
if (!str)
@ -689,7 +719,7 @@ JSCrossCompartmentWrapper::fun_toString(JSContext *cx, JSObject *proxy, uintN in
}
bool
JSCrossCompartmentWrapper::enter(JSContext *cx, JSObject *proxy, jsval id)
JSCrossCompartmentWrapper::enter(JSContext *cx, JSObject *proxy, jsval id, Mode mode)
{
return true;
}
@ -699,16 +729,4 @@ JSCrossCompartmentWrapper::leave(JSContext *cx, JSObject *proxy)
{
}
bool
JSCrossCompartmentWrapper::filter(JSContext *cx, JSObject *proxy, AutoValueVector &props)
{
return true;
}
bool
JSCrossCompartmentWrapper::filter(JSContext *cx, JSObject *proxy, jsval *vp)
{
return true;
}
JSCrossCompartmentWrapper JSCrossCompartmentWrapper::singleton;

View File

@ -101,6 +101,8 @@ class JSCrossCompartmentWrapper : public JSWrapper {
JS_FRIEND_API(JSCrossCompartmentWrapper());
public:
typedef enum { GET, SET } Mode;
virtual JS_FRIEND_API(~JSCrossCompartmentWrapper());
/* ES5 Harmony fundamental proxy traps. */
@ -130,10 +132,8 @@ class JSCrossCompartmentWrapper : public JSWrapper {
virtual JSString *fun_toString(JSContext *cx, JSObject *proxy, uintN indent);
/* Policy enforcement traps. */
virtual bool enter(JSContext *cx, JSObject *proxy, jsid id);
virtual bool enter(JSContext *cx, JSObject *proxy, jsid id, Mode mode);
virtual void leave(JSContext *cx, JSObject *proxy);
virtual bool filter(JSContext *cx, JSObject *proxy, js::AutoValueVector &props);
virtual bool filter(JSContext *cx, JSObject *proxy, jsval *vp);
static JSCrossCompartmentWrapper singleton;

View File

@ -0,0 +1,115 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=4 sw=4 et tw=99 ft=cpp:
*
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code, released
* June 24, 2010.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation
*
* Contributor(s):
* Andreas Gal <gal@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "jsapi.h"
#include "jswrapper.h"
#include "XPCWrapper.h"
#include "nsJSPrincipals.h"
#include "AccessCheck.h"
namespace xpc {
nsIPrincipal *
GetCompartmentPrincipal(JSCompartment *compartment)
{
return static_cast<nsJSPrincipals *>(compartment->principals)->nsIPrincipalPtr;
}
bool
AccessCheck::isPrivileged(JSCompartment *compartment)
{
nsIScriptSecurityManager *ssm = XPCWrapper::GetSecurityManager();
if(!ssm) {
return true;
}
PRBool privileged;
if(NS_SUCCEEDED(ssm->IsSystemPrincipal(GetCompartmentPrincipal(compartment), &privileged))
&& privileged) {
return true;
}
if(NS_SUCCEEDED(ssm->IsCapabilityEnabled("UniversalXPConnect", &privileged)) && privileged) {
return true;
}
return false;
}
void
AccessCheck::deny(JSContext *cx, jsid id)
{
if(id == JSVAL_VOID) {
JS_ReportError(cx, "Permission denied to access object");
} else {
JSString *str = JS_ValueToString(cx, id);
JS_ReportError(cx, "Permission denied to access property '%hs'", str);
}
}
bool
AccessCheck::enter(JSContext *cx, JSObject *wrapper, JSObject *wrappedObject, jsid id,
JSCrossCompartmentWrapper::Mode mode)
{
nsIScriptSecurityManager *ssm = XPCWrapper::GetSecurityManager();
if(!ssm) {
return true;
}
JSStackFrame *fp = NULL;
nsresult rv = ssm->PushContextPrincipal(cx, JS_FrameIterator(cx, &fp),
GetCompartmentPrincipal(wrappedObject->getCompartment(cx)));
if(NS_FAILED(rv)) {
NS_WARNING("Not allowing call because we're out of memory");
JS_ReportOutOfMemory(cx);
return false;
}
return true;
}
void
AccessCheck::leave(JSContext *cx, JSObject *wrapper, JSObject *wrappedObject)
{
nsIScriptSecurityManager *ssm = XPCWrapper::GetSecurityManager();
if(ssm) {
ssm->PopContextPrincipal(cx);
}
}
}

View File

@ -0,0 +1,57 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=4 sw=4 et tw=99 ft=cpp:
*
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code, released
* June 24, 2010.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation
*
* Contributor(s):
* Andreas Gal <gal@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "jsapi.h"
#include "jswrapper.h"
namespace xpc {
class AccessCheck {
public:
static bool subsumes(JSCompartment *subject, JSCompartment *object, bool *yesno);
static bool isPrivileged(JSCompartment *compartment);
static void deny(JSContext *cx, jsid id);
static bool enter(JSContext *cx, JSObject *wrapper, JSObject *wrappedObject, jsid id,
JSCrossCompartmentWrapper::Mode mode);
static void leave(JSContext *cx, JSObject *wrapper, JSObject *wrappedObject);
};
}

View File

@ -0,0 +1,244 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=4 sw=4 et tw=99 ft=cpp:
*
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code, released
* June 24, 2010.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation
*
* Contributor(s):
* Andreas Gal <gal@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "ChromeWrapper.h"
#include "AccessCheck.h"
#include "XPCWrapper.h"
using namespace js;
namespace xpc {
ChromeWrapper ChromeWrapper::singleton;
ChromeWrapper::ChromeWrapper() : JSCrossCompartmentWrapper()
{
}
ChromeWrapper::~ChromeWrapper()
{
}
typedef enum { READ = (1<<0), WRITE = (1<<1), DENIED=0 } Permission;
static bool
Allow(JSContext *cx, bool *yesno)
{
if(yesno) {
*yesno = true;
}
return true;
}
static bool
Deny(JSContext *cx, bool *yesno, const char *error)
{
if(yesno) {
*yesno = false;
return true;
}
JS_ReportError(cx, error);
return false;
}
static bool
CheckAccess(JSContext *cx, JSObject *hallpass, jsid id, JSCrossCompartmentWrapper::Mode mode,
bool *yesno = NULL)
{
if(!hallpass) {
return Allow(cx, yesno);
}
Permission perm = DENIED;
jsval v;
if(!JS_LookupPropertyById(cx, hallpass, id, &v)) {
return false;
}
if(!JSVAL_IS_STRING(v)) {
return Deny(cx, yesno, "property permission must be a string");
}
JSString *str = JSVAL_TO_STRING(v);
const jschar *chars = JS_GetStringChars(str);
size_t length = JS_GetStringLength(str);
for (size_t i = 0; i < length; ++i) {
switch (chars[i]) {
case 'r':
if(perm & READ) {
return Deny(cx, yesno, "duplicate 'readable' property flag");
}
perm = Permission(perm | READ);
break;
case 'w':
if(perm & WRITE) {
return Deny(cx, yesno, "duplicate 'writable' property flag");
}
perm = Permission(perm | WRITE);
break;
default:
return Deny(cx, yesno, "property permission can only be readable or read and writable");
}
}
if(perm == DENIED) {
return Deny(cx, yesno, "invalid property permission");
}
if((mode == JSCrossCompartmentWrapper::GET && !(perm & READ)) ||
(mode == JSCrossCompartmentWrapper::SET && !(perm & WRITE))) {
if(yesno) {
*yesno = false;
return true;
}
AccessCheck::deny(cx, id);
return false;
}
return Allow(cx, yesno);
}
static bool
GetHallPass(JSContext *cx, JSObject *wrappedObject, jsid id, JSObject **hallpassp)
{
jsid exposedPropsId = GetRTIdByIndex(cx, XPCJSRuntime::IDX_EXPOSEDPROPS);
JSBool found = JS_FALSE;
if(!JS_HasPropertyById(cx, wrappedObject, exposedPropsId, &found))
return false;
if(!found) {
*hallpassp = NULL;
return true;
}
jsval exposedProps;
if(!JS_LookupPropertyById(cx, wrappedObject, exposedPropsId, &exposedProps))
return false;
if(JSVAL_IS_VOID(exposedProps) || JSVAL_IS_NULL(exposedProps)) {
AccessCheck::deny(cx, id);
return false;
}
if(!JSVAL_IS_OBJECT(exposedProps)) {
JS_ReportError(cx,
"__exposedProps__ must be undefined, null, or an object");
return false;
}
*hallpassp = JSVAL_TO_OBJECT(exposedProps);
return true;
}
static bool
Filter(JSContext *cx, JSObject *wrappedObject, AutoValueVector &props)
{
JSObject *hallpass;
if(!GetHallPass(cx, wrappedObject, JSVAL_VOID, &hallpass))
return false;
if(!hallpass)
return true;
size_t w = 0;
for (size_t n = 0; n < props.length(); ++n) {
bool yes;
jsid id = props[n];
if(!CheckAccess(cx, hallpass, id, JSCrossCompartmentWrapper::GET, &yes))
return false;
if(yes) {
props[w++] = id;
}
}
props.resize(w);
return true;
}
bool
ChromeWrapper::getOwnPropertyNames(JSContext *cx, JSObject *wrapper, AutoValueVector &props)
{
return JSCrossCompartmentWrapper::getOwnPropertyNames(cx, wrapper, props) &&
Filter(cx, wrappedObject(wrapper), props);
}
bool
ChromeWrapper::enumerate(JSContext *cx, JSObject *wrapper, AutoValueVector &props)
{
return JSCrossCompartmentWrapper::enumerate(cx, wrapper, props) &&
Filter(cx, wrappedObject(wrapper), props);
}
bool
ChromeWrapper::enumerateOwn(JSContext *cx, JSObject *wrapper, AutoValueVector &props)
{
return JSCrossCompartmentWrapper::enumerateOwn(cx, wrapper, props) &&
Filter(cx, wrappedObject(wrapper), props);
}
bool
ChromeWrapper::iterate(JSContext *cx, JSObject *wrapper, uintN flags, jsval *vp)
{
// We refuse to trigger the iterator hook across chrome wrappers because
// we don't know how to censor custom iterator objects. Instead we trigger
// the default proxy iterate trap, which will ask ChromeWrapper::enumerate()
// for the list of (consored) ids.
return JSProxyHandler::iterate(cx, wrapper, flags, vp);
}
bool
ChromeWrapper::enter(JSContext *cx, JSObject *wrapper, jsid id, Mode mode)
{
JSObject *hallpass;
return GetHallPass(cx, wrappedObject(wrapper), id, &hallpass) &&
CheckAccess(cx, hallpass, id, mode);
}
JSString *
ChromeWrapper::fun_toString(JSContext *cx, JSObject *wrapper, uintN indent)
{
// Censor Function.prototype.toString.call(wrapper) and decompile Function instead.
JSObject *ctor;
if(!JS_GetClassObject(cx, wrapper->getGlobal(), JSProto_Function, &ctor))
return false;
return JS_DecompileFunction(cx, JS_ValueToConstructor(cx, OBJECT_TO_JSVAL(ctor)), indent);
}
}

View File

@ -0,0 +1,62 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=4 sw=4 et tw=99 ft=cpp:
*
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code, released
* June 24, 2010.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation
*
* Contributor(s):
* Andreas Gal <gal@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "jsapi.h"
#include "jswrapper.h"
namespace xpc {
class ChromeWrapper : public JSCrossCompartmentWrapper {
public:
ChromeWrapper();
virtual ~ChromeWrapper();
virtual bool getOwnPropertyNames(JSContext *cx, JSObject *wrapper, js::AutoValueVector &props);
virtual bool enumerate(JSContext *cx, JSObject *wrapper, js::AutoValueVector &props);
virtual bool enumerateOwn(JSContext *cx, JSObject *wrapper, js::AutoValueVector &props);
virtual bool iterate(JSContext *cx, JSObject *proxy, uintN flags, jsval *vp);
virtual bool enter(JSContext *cx, JSObject *wrapper, jsid id, Mode mode);
virtual JSString *fun_toString(JSContext *cx, JSObject *wrapper, uintN indent);
static ChromeWrapper singleton;
};
}

View File

@ -14,8 +14,8 @@
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla SpiderMonkey JavaScript 1.9.1 code, released
* June 30, 2009.
* The Original Code is mozilla.org code, released
* June 24, 2010.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation
@ -37,25 +37,12 @@
*
* ***** END LICENSE BLOCK ***** */
#include "jsapi.h"
#include "jswrapper.h"
#include "XPCWrapper.h"
#include "nsJSPrincipals.h"
#include "ContentWrapper.h"
#include "AccessCheck.h"
namespace xpc {
class ContentWrapper : public JSCrossCompartmentWrapper {
public:
ContentWrapper();
virtual ~ContentWrapper();
virtual bool enter(JSContext *cx, JSObject *proxy, jsid id);
virtual void leave(JSContext *cx, JSObject *proxy);
static ContentWrapper singleton;
};
ContentWrapper ContentWrapper::singleton;
ContentWrapper::ContentWrapper() : JSCrossCompartmentWrapper()
{
@ -66,41 +53,15 @@ ContentWrapper::~ContentWrapper()
}
bool
ContentWrapper::enter(JSContext *cx, JSObject *wrapper, jsid id)
ContentWrapper::enter(JSContext *cx, JSObject *wrapper, jsid id, Mode mode)
{
nsIScriptSecurityManager *ssm = XPCWrapper::GetSecurityManager();
if(!ssm) {
return true;
}
JSPrincipals *subjectPrincipals = wrapper->getCompartment(cx)->principals;
JSPrincipals *objectPrincipals = wrappedObject(wrapper)->getCompartment(cx)->principals;
if(!subjectPrincipals->subsume(subjectPrincipals, objectPrincipals)) {
if(id == JSVAL_VOID) {
JS_ReportError(cx, "Permission denied to access object");
} else {
JSString *str = JS_ValueToString(cx, id);
JS_ReportError(cx, "Permission denied to access property '%hs'", str);
}
return false;
}
JSStackFrame *fp = nsnull;
nsIPrincipal *principal = static_cast<nsJSPrincipals *>(objectPrincipals)->nsIPrincipalPtr;
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;
return AccessCheck::enter(cx, wrapper, wrappedObject(wrapper), id, mode);
}
void
ContentWrapper::leave(JSContext *cx, JSObject *proxy)
ContentWrapper::leave(JSContext *cx, JSObject *wrapper)
{
nsIScriptSecurityManager *ssm = XPCWrapper::GetSecurityManager();
if (ssm) {
ssm->PopContextPrincipal(cx);
}
return AccessCheck::leave(cx, wrapper, wrappedObject(wrapper));
}
}

View File

@ -0,0 +1,64 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=4 sw=4 et tw=99 ft=cpp:
*
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code, released
* June 24, 2010.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation
*
* Contributor(s):
* Andreas Gal <gal@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "jsapi.h"
#include "jswrapper.h"
// Content wrappers allow unmitigated access and are only used if the
// origin (subject) compartment's principals subsume the target (object)
// compartment's principals.
//
// The main responsibility of the content wrapper is to push and pop the
// target (object) compartment's principals when entering and leaving
// that compartment.
namespace xpc {
class ContentWrapper : public JSCrossCompartmentWrapper {
public:
ContentWrapper();
virtual ~ContentWrapper();
virtual bool enter(JSContext *cx, JSObject *wrapper, jsid id, Mode mode);
virtual void leave(JSContext *cx, JSObject *wrapper);
static ContentWrapper singleton;
};
}

View File

@ -47,7 +47,10 @@ LIBRARY_NAME = xpcwrappers_s
FORCE_STATIC_LIB = 1
LIBXUL_LIBRARY = 1
CPPSRCS = ContentWrapper.cpp
CPPSRCS = ContentWrapper.cpp \
ChromeWrapper.cpp \
AccessCheck.cpp \
WrapperFactory.cpp
LOCAL_INCLUDES = \
-I$(srcdir)/.. \

View File

@ -0,0 +1,56 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=4 sw=4 et tw=99 ft=cpp:
*
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code, released
* June 24, 2010.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation
*
* Contributor(s):
* Andreas Gal <gal@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "WrapperFactory.h"
#include "ContentWrapper.h"
#include "ChromeWrapper.h"
#include "AccessCheck.h"
namespace xpc {
JSCrossCompartmentWrapper *
WrapperFactory::select(JSContext *cx, JSCompartment *subject, JSCompartment *object)
{
if(AccessCheck::isPrivileged(object)) {
return &ChromeWrapper::singleton;
}
return &ContentWrapper::singleton;
}
}

View File

@ -0,0 +1,52 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=4 sw=4 et tw=99 ft=cpp:
*
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code, released
* June 24, 2010.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation
*
* Contributor(s):
* Andreas Gal <gal@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "jsapi.h"
#include "jswrapper.h"
namespace xpc {
class WrapperFactory {
// Return the wrapper handler to use, or NULL in case of error.
static JSCrossCompartmentWrapper *select(JSContext *cx,
JSCompartment *subject,
JSCompartment *object);
};
}