js/xpconnect/wrappers/FilteringWrapper.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

     1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
     2 /* vim: set ts=8 sts=4 et sw=4 tw=99: */
     3 /* This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 #include "FilteringWrapper.h"
     8 #include "AccessCheck.h"
     9 #include "ChromeObjectWrapper.h"
    10 #include "XrayWrapper.h"
    12 #include "jsapi.h"
    14 using namespace JS;
    15 using namespace js;
    17 namespace xpc {
    19 template <typename Base, typename Policy>
    20 FilteringWrapper<Base, Policy>::FilteringWrapper(unsigned flags) : Base(flags)
    21 {
    22 }
    24 template <typename Base, typename Policy>
    25 FilteringWrapper<Base, Policy>::~FilteringWrapper()
    26 {
    27 }
    29 template <typename Policy>
    30 static bool
    31 Filter(JSContext *cx, HandleObject wrapper, AutoIdVector &props)
    32 {
    33     size_t w = 0;
    34     RootedId id(cx);
    35     for (size_t n = 0; n < props.length(); ++n) {
    36         id = props[n];
    37         if (Policy::check(cx, wrapper, id, Wrapper::GET))
    38             props[w++] = id;
    39         else if (JS_IsExceptionPending(cx))
    40             return false;
    41     }
    42     props.resize(w);
    43     return true;
    44 }
    46 template <typename Policy>
    47 static bool
    48 FilterSetter(JSContext *cx, JSObject *wrapper, jsid id, JS::MutableHandle<JSPropertyDescriptor> desc)
    49 {
    50     bool setAllowed = Policy::check(cx, wrapper, id, Wrapper::SET);
    51     if (!setAllowed) {
    52         if (JS_IsExceptionPending(cx))
    53             return false;
    54         desc.setSetter(nullptr);
    55     }
    56     return true;
    57 }
    59 template <typename Base, typename Policy>
    60 bool
    61 FilteringWrapper<Base, Policy>::getPropertyDescriptor(JSContext *cx, HandleObject wrapper,
    62                                                       HandleId id,
    63                                                       JS::MutableHandle<JSPropertyDescriptor> desc)
    64 {
    65     assertEnteredPolicy(cx, wrapper, id, BaseProxyHandler::GET | BaseProxyHandler::SET);
    66     if (!Base::getPropertyDescriptor(cx, wrapper, id, desc))
    67         return false;
    68     return FilterSetter<Policy>(cx, wrapper, id, desc);
    69 }
    71 template <typename Base, typename Policy>
    72 bool
    73 FilteringWrapper<Base, Policy>::getOwnPropertyDescriptor(JSContext *cx, HandleObject wrapper,
    74                                                          HandleId id,
    75                                                          JS::MutableHandle<JSPropertyDescriptor> desc)
    76 {
    77     assertEnteredPolicy(cx, wrapper, id, BaseProxyHandler::GET | BaseProxyHandler::SET);
    78     if (!Base::getOwnPropertyDescriptor(cx, wrapper, id, desc))
    79         return false;
    80     return FilterSetter<Policy>(cx, wrapper, id, desc);
    81 }
    83 template <typename Base, typename Policy>
    84 bool
    85 FilteringWrapper<Base, Policy>::getOwnPropertyNames(JSContext *cx, HandleObject wrapper,
    86                                                     AutoIdVector &props)
    87 {
    88     assertEnteredPolicy(cx, wrapper, JSID_VOID, BaseProxyHandler::ENUMERATE);
    89     return Base::getOwnPropertyNames(cx, wrapper, props) &&
    90            Filter<Policy>(cx, wrapper, props);
    91 }
    93 template <typename Base, typename Policy>
    94 bool
    95 FilteringWrapper<Base, Policy>::enumerate(JSContext *cx, HandleObject wrapper,
    96                                           AutoIdVector &props)
    97 {
    98     assertEnteredPolicy(cx, wrapper, JSID_VOID, BaseProxyHandler::ENUMERATE);
    99     return Base::enumerate(cx, wrapper, props) &&
   100            Filter<Policy>(cx, wrapper, props);
   101 }
   103 template <typename Base, typename Policy>
   104 bool
   105 FilteringWrapper<Base, Policy>::keys(JSContext *cx, HandleObject wrapper,
   106                                      AutoIdVector &props)
   107 {
   108     assertEnteredPolicy(cx, wrapper, JSID_VOID, BaseProxyHandler::ENUMERATE);
   109     return Base::keys(cx, wrapper, props) &&
   110            Filter<Policy>(cx, wrapper, props);
   111 }
   113 template <typename Base, typename Policy>
   114 bool
   115 FilteringWrapper<Base, Policy>::iterate(JSContext *cx, HandleObject wrapper,
   116                                         unsigned flags, MutableHandleValue vp)
   117 {
   118     assertEnteredPolicy(cx, wrapper, JSID_VOID, BaseProxyHandler::ENUMERATE);
   119     // We refuse to trigger the iterator hook across chrome wrappers because
   120     // we don't know how to censor custom iterator objects. Instead we trigger
   121     // the default proxy iterate trap, which will ask enumerate() for the list
   122     // of (censored) ids.
   123     return js::BaseProxyHandler::iterate(cx, wrapper, flags, vp);
   124 }
   126 template <typename Base, typename Policy>
   127 bool
   128 FilteringWrapper<Base, Policy>::nativeCall(JSContext *cx, JS::IsAcceptableThis test,
   129                                            JS::NativeImpl impl, JS::CallArgs args)
   130 {
   131     if (Policy::allowNativeCall(cx, test, impl))
   132         return Base::Permissive::nativeCall(cx, test, impl, args);
   133     return Base::Restrictive::nativeCall(cx, test, impl, args);
   134 }
   136 template <typename Base, typename Policy>
   137 bool
   138 FilteringWrapper<Base, Policy>::defaultValue(JSContext *cx, HandleObject obj,
   139                                              JSType hint, MutableHandleValue vp)
   140 {
   141     return Base::defaultValue(cx, obj, hint, vp);
   142 }
   144 // With our entirely-opaque wrapper, the DefaultValue algorithm throws,
   145 // causing spurious exceptions. Manually implement something benign.
   146 template<>
   147 bool
   148 FilteringWrapper<CrossCompartmentSecurityWrapper, GentlyOpaque>
   149                 ::defaultValue(JSContext *cx, HandleObject obj,
   150                                JSType hint, MutableHandleValue vp)
   151 {
   152     JSString *str = JS_NewStringCopyZ(cx, "[Opaque]");
   153     if (!str)
   154         return false;
   155     vp.set(JS::StringValue(str));
   156     return true;
   157 }
   160 template <typename Base, typename Policy>
   161 bool
   162 FilteringWrapper<Base, Policy>::enter(JSContext *cx, HandleObject wrapper,
   163                                       HandleId id, Wrapper::Action act, bool *bp)
   164 {
   165     // This is a super ugly hacky to get around Xray Resolve wonkiness.
   166     //
   167     // Basically, XPCWN Xrays sometimes call into the Resolve hook of the
   168     // scriptable helper, and pass the wrapper itself as the object upon which
   169     // the resolve is happening. Then, special handling happens in
   170     // XrayWrapper::defineProperty to detect the resolve and redefine the
   171     // property on the holder. Really, we should just pass the holder itself to
   172     // NewResolve, but there's too much code in nsDOMClassInfo that assumes this
   173     // isn't the case (in particular, code expects to be able to look up
   174     // properties on the object, which doesn't work for the holder). Given that
   175     // these hooks are going away eventually with the new DOM bindings, let's
   176     // just hack around this for now.
   177     if (XrayUtils::IsXrayResolving(cx, wrapper, id)) {
   178         *bp = true;
   179         return true;
   180     }
   181     if (!Policy::check(cx, wrapper, id, act)) {
   182         *bp = JS_IsExceptionPending(cx) ? false : Policy::deny(act, id);
   183         return false;
   184     }
   185     *bp = true;
   186     return true;
   187 }
   189 #define XOW FilteringWrapper<SecurityXrayXPCWN, CrossOriginAccessiblePropertiesOnly>
   190 #define DXOW   FilteringWrapper<SecurityXrayDOM, CrossOriginAccessiblePropertiesOnly>
   191 #define NNXOW FilteringWrapper<CrossCompartmentSecurityWrapper, Opaque>
   192 #define NNXOWC FilteringWrapper<CrossCompartmentSecurityWrapper, OpaqueWithCall>
   193 #define GO FilteringWrapper<CrossCompartmentSecurityWrapper, GentlyOpaque>
   194 template<> XOW XOW::singleton(0);
   195 template<> DXOW DXOW::singleton(0);
   196 template<> NNXOW NNXOW::singleton(0);
   197 template<> NNXOWC NNXOWC::singleton(0);
   199 template<> GO GO::singleton(0);
   201 template class XOW;
   202 template class DXOW;
   203 template class NNXOW;
   204 template class NNXOWC;
   205 template class ChromeObjectWrapperBase;
   206 template class GO;
   207 }

mercurial