2010-06-25 15:58:09 -07:00
|
|
|
/* -*- 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 ***** */
|
|
|
|
|
2010-07-02 13:54:53 -07:00
|
|
|
#include "jsobj.h"
|
|
|
|
|
2010-06-25 15:58:09 -07:00
|
|
|
#include "WrapperFactory.h"
|
2010-07-02 13:54:53 -07:00
|
|
|
#include "CrossOriginWrapper.h"
|
|
|
|
#include "FilteringWrapper.h"
|
|
|
|
#include "XrayWrapper.h"
|
2010-06-25 15:58:09 -07:00
|
|
|
#include "AccessCheck.h"
|
|
|
|
|
2010-07-02 13:54:53 -07:00
|
|
|
#include "xpcprivate.h"
|
|
|
|
|
2010-06-25 15:58:09 -07:00
|
|
|
namespace xpc {
|
|
|
|
|
2010-07-02 13:54:53 -07:00
|
|
|
// When chrome pulls a naked property across the membrane using
|
|
|
|
// .wrappedJSObject, we want it to cross the membrane into the
|
|
|
|
// chrome compartment without automatically being wrapped into an
|
|
|
|
// X-ray wrapper. We achieve this by wrapping it into a special
|
|
|
|
// transparent wrapper in the origin (non-chrome) compartment. When
|
|
|
|
// an object with that special wrapper applied crosses into chrome,
|
|
|
|
// we know to not apply an X-ray wrapper.
|
|
|
|
JSWrapper WaiveXrayWrapperWrapper(WrapperFactory::WAIVE_XRAY_WRAPPER_FLAG);
|
|
|
|
|
|
|
|
// When objects for which we waived the X-ray wrapper cross into
|
|
|
|
// chrome, we wrap them into a special cross-compartment wrapper
|
|
|
|
// that transitively extends the waiver to all properties we get
|
|
|
|
// off it.
|
2010-09-20 14:47:15 -07:00
|
|
|
CrossOriginWrapper XrayWrapperWaivedWrapper(WrapperFactory::WAIVE_XRAY_WRAPPER_FLAG);
|
2010-07-02 13:54:53 -07:00
|
|
|
|
|
|
|
JSObject *
|
2010-09-17 14:54:40 -07:00
|
|
|
WrapperFactory::Rewrap(JSContext *cx, JSObject *obj, JSObject *wrappedProto, JSObject *parent,
|
|
|
|
uintN flags)
|
2010-06-25 15:58:09 -07:00
|
|
|
{
|
2010-08-23 15:34:11 -07:00
|
|
|
NS_ASSERTION(!obj->isWrapper() || obj->getClass()->ext.innerObject,
|
|
|
|
"wrapped object passed to rewrap");
|
2010-07-02 13:54:53 -07:00
|
|
|
|
2010-09-17 14:54:41 -07:00
|
|
|
if (IS_SLIM_WRAPPER(obj) && !MorphSlimWrapper(cx, obj))
|
|
|
|
return nsnull;
|
|
|
|
|
|
|
|
OBJ_TO_OUTER_OBJECT(cx, obj);
|
|
|
|
if (!obj)
|
|
|
|
return nsnull;
|
|
|
|
|
2010-09-17 14:54:41 -07:00
|
|
|
// Ugly hack to avoid wrapping holder objects instead of the actual
|
|
|
|
// underlying wrapped native JS object.
|
|
|
|
if (JS_GET_CLASS(cx, obj) == &HolderClass) {
|
|
|
|
obj = XrayWrapper<JSCrossCompartmentWrapper>::unwrapHolder(cx, obj);
|
|
|
|
OBJ_TO_OUTER_OBJECT(cx, obj);
|
|
|
|
if (!JS_WrapObject(cx, &obj))
|
|
|
|
return nsnull;
|
|
|
|
|
|
|
|
return obj;
|
|
|
|
}
|
|
|
|
|
2010-07-02 13:54:53 -07:00
|
|
|
JSCompartment *origin = obj->getCompartment(cx);
|
|
|
|
JSCompartment *target = cx->compartment;
|
|
|
|
|
|
|
|
JSWrapper *wrapper;
|
|
|
|
if (AccessCheck::isChrome(target)) {
|
2010-09-17 14:54:41 -07:00
|
|
|
if (AccessCheck::isChrome(origin)) {
|
|
|
|
wrapper = &JSCrossCompartmentWrapper::singleton;
|
|
|
|
} else if (flags & WAIVE_XRAY_WRAPPER_FLAG) {
|
|
|
|
// If we waived the X-ray wrapper for this object, wrap it into a
|
|
|
|
// special wrapper to transitively maintain the X-ray waiver.
|
2010-07-02 13:54:53 -07:00
|
|
|
wrapper = &XrayWrapperWaivedWrapper;
|
|
|
|
} else {
|
|
|
|
// Native objects must be wrapped into an X-ray wrapper.
|
2010-09-02 16:02:51 -07:00
|
|
|
if (!obj->getGlobal()->isSystem() &&
|
|
|
|
(IS_WN_WRAPPER(obj) || obj->getClass()->ext.innerObject)) {
|
|
|
|
typedef XrayWrapper<JSCrossCompartmentWrapper> Xray;
|
|
|
|
|
|
|
|
wrapper = &Xray::singleton;
|
|
|
|
obj = Xray::createHolder(cx, parent, obj);
|
|
|
|
} else {
|
|
|
|
wrapper = &JSCrossCompartmentWrapper::singleton;
|
|
|
|
}
|
2010-07-02 13:54:53 -07:00
|
|
|
}
|
|
|
|
} else if (AccessCheck::isChrome(origin)) {
|
|
|
|
// If an object that needs a system only wrapper crosses into content
|
|
|
|
// from chrome, we have to wrap it into a system only wrapper on the
|
|
|
|
// fly. In this case we don't need to restrict to exposed properties
|
|
|
|
// since only privileged content will be allowed to touch it anyway.
|
|
|
|
if (AccessCheck::needsSystemOnlyWrapper(obj)) {
|
|
|
|
wrapper = &FilteringWrapper<JSCrossCompartmentWrapper,
|
|
|
|
OnlyIfSubjectIsSystem>::singleton;
|
|
|
|
} else {
|
|
|
|
wrapper = &FilteringWrapper<JSCrossCompartmentWrapper,
|
|
|
|
ExposedPropertiesOnly>::singleton;
|
|
|
|
}
|
|
|
|
} else if (AccessCheck::isSameOrigin(origin, target)) {
|
|
|
|
// Same origin we use a transparent wrapper;
|
|
|
|
wrapper = &JSCrossCompartmentWrapper::singleton;
|
|
|
|
} else {
|
|
|
|
// Cross origin we want to disallow scripting and limit access to
|
|
|
|
// a predefined set of properties. XrayWrapper adds a property
|
|
|
|
// (.wrappedJSObject) which allows bypassing the XrayWrapper, but
|
|
|
|
// we filter out access to that property.
|
2010-09-02 16:02:51 -07:00
|
|
|
if (!IS_WN_WRAPPER(obj)) {
|
|
|
|
wrapper = &FilteringWrapper<JSCrossCompartmentWrapper,
|
|
|
|
CrossOriginAccessiblePropertiesOnly>::singleton;
|
|
|
|
} else {
|
|
|
|
typedef XrayWrapper<CrossOriginWrapper> Xray;
|
2010-09-20 14:47:15 -07:00
|
|
|
wrapper = &FilteringWrapper<Xray,
|
2010-09-02 16:02:51 -07:00
|
|
|
CrossOriginAccessiblePropertiesOnly>::singleton;
|
|
|
|
obj = Xray::createHolder(cx, parent, obj);
|
|
|
|
}
|
2010-06-25 15:58:09 -07:00
|
|
|
}
|
2010-07-02 13:54:53 -07:00
|
|
|
return JSWrapper::New(cx, obj, wrappedProto, NULL, wrapper);
|
2010-06-25 15:58:09 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|