tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

FilteringWrapper.cpp (5696B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      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/. */
      6 
      7 #include "FilteringWrapper.h"
      8 #include "AccessCheck.h"
      9 #include "ChromeObjectWrapper.h"
     10 #include "XrayWrapper.h"
     11 #include "nsJSUtils.h"
     12 #include "mozilla/ErrorResult.h"
     13 #include "xpcpublic.h"
     14 #include "xpcprivate.h"
     15 
     16 #include "jsapi.h"
     17 #include "js/Symbol.h"
     18 
     19 using namespace JS;
     20 using namespace js;
     21 
     22 namespace xpc {
     23 
     24 static JS::SymbolCode sCrossOriginWhitelistedSymbolCodes[] = {
     25    JS::SymbolCode::toStringTag, JS::SymbolCode::hasInstance,
     26    JS::SymbolCode::isConcatSpreadable};
     27 
     28 static bool IsCrossOriginWhitelistedSymbol(JSContext* cx, JS::HandleId id) {
     29  if (!id.isSymbol()) {
     30    return false;
     31  }
     32 
     33  JS::Symbol* symbol = id.toSymbol();
     34  for (auto code : sCrossOriginWhitelistedSymbolCodes) {
     35    if (symbol == JS::GetWellKnownSymbol(cx, code)) {
     36      return true;
     37    }
     38  }
     39 
     40  return false;
     41 }
     42 
     43 bool IsCrossOriginWhitelistedProp(JSContext* cx, JS::HandleId id) {
     44  return id == GetJSIDByIndex(cx, XPCJSContext::IDX_THEN) ||
     45         IsCrossOriginWhitelistedSymbol(cx, id);
     46 }
     47 
     48 bool AppendCrossOriginWhitelistedPropNames(JSContext* cx,
     49                                           JS::MutableHandleIdVector props) {
     50  // Add "then" if it's not already in the list.
     51  RootedIdVector thenProp(cx);
     52  if (!thenProp.append(GetJSIDByIndex(cx, XPCJSContext::IDX_THEN))) {
     53    return false;
     54  }
     55 
     56  if (!AppendUnique(cx, props, thenProp)) {
     57    return false;
     58  }
     59 
     60  // Now add the three symbol-named props cross-origin objects have.
     61 #ifdef DEBUG
     62  for (size_t n = 0; n < props.length(); ++n) {
     63    MOZ_ASSERT(!props[n].isSymbol(), "Unexpected existing symbol-name prop");
     64  }
     65 #endif
     66  if (!props.reserve(props.length() +
     67                     std::size(sCrossOriginWhitelistedSymbolCodes))) {
     68    return false;
     69  }
     70 
     71  for (auto code : sCrossOriginWhitelistedSymbolCodes) {
     72    props.infallibleAppend(JS::GetWellKnownSymbolKey(cx, code));
     73  }
     74 
     75  return true;
     76 }
     77 
     78 // Note: Previously, FilteringWrapper supported complex access policies where
     79 // certain properties on an object were accessible and others weren't. Today,
     80 // the only supported policies are Opaque and OpaqueWithCall, none of which need
     81 // that. So we just stub out the unreachable paths.
     82 template <typename Base, typename Policy>
     83 bool FilteringWrapper<Base, Policy>::getOwnPropertyDescriptor(
     84    JSContext* cx, HandleObject wrapper, HandleId id,
     85    MutableHandle<mozilla::Maybe<PropertyDescriptor>> desc) const {
     86  MOZ_CRASH("FilteringWrappers are now always opaque");
     87 }
     88 
     89 template <typename Base, typename Policy>
     90 bool FilteringWrapper<Base, Policy>::ownPropertyKeys(
     91    JSContext* cx, HandleObject wrapper, MutableHandleIdVector props) const {
     92  MOZ_CRASH("FilteringWrappers are now always opaque");
     93 }
     94 
     95 template <typename Base, typename Policy>
     96 bool FilteringWrapper<Base, Policy>::getOwnEnumerablePropertyKeys(
     97    JSContext* cx, HandleObject wrapper, MutableHandleIdVector props) const {
     98  MOZ_CRASH("FilteringWrappers are now always opaque");
     99 }
    100 
    101 template <typename Base, typename Policy>
    102 bool FilteringWrapper<Base, Policy>::enumerate(
    103    JSContext* cx, HandleObject wrapper,
    104    JS::MutableHandleIdVector props) const {
    105  MOZ_CRASH("FilteringWrappers are now always opaque");
    106 }
    107 
    108 template <typename Base, typename Policy>
    109 bool FilteringWrapper<Base, Policy>::call(JSContext* cx,
    110                                          JS::Handle<JSObject*> wrapper,
    111                                          const JS::CallArgs& args) const {
    112  if (!Policy::checkCall(cx, wrapper, args)) {
    113    return false;
    114  }
    115  return Base::call(cx, wrapper, args);
    116 }
    117 
    118 template <typename Base, typename Policy>
    119 bool FilteringWrapper<Base, Policy>::construct(JSContext* cx,
    120                                               JS::Handle<JSObject*> wrapper,
    121                                               const JS::CallArgs& args) const {
    122  if (!Policy::checkCall(cx, wrapper, args)) {
    123    return false;
    124  }
    125  return Base::construct(cx, wrapper, args);
    126 }
    127 
    128 template <typename Base, typename Policy>
    129 bool FilteringWrapper<Base, Policy>::nativeCall(
    130    JSContext* cx, JS::IsAcceptableThis test, JS::NativeImpl impl,
    131    const JS::CallArgs& args) const {
    132  if (Policy::allowNativeCall(cx, test, impl)) {
    133    return Base::Permissive::nativeCall(cx, test, impl, args);
    134  }
    135  return Base::Restrictive::nativeCall(cx, test, impl, args);
    136 }
    137 
    138 template <typename Base, typename Policy>
    139 bool FilteringWrapper<Base, Policy>::getPrototype(
    140    JSContext* cx, JS::HandleObject wrapper,
    141    JS::MutableHandleObject protop) const {
    142  // Filtering wrappers do not allow access to the prototype.
    143  protop.set(nullptr);
    144  return true;
    145 }
    146 
    147 template <typename Base, typename Policy>
    148 bool FilteringWrapper<Base, Policy>::enter(JSContext* cx, HandleObject wrapper,
    149                                           HandleId id, Wrapper::Action act,
    150                                           bool mayThrow, bool* bp) const {
    151  if (!Policy::check(cx, wrapper, id, act)) {
    152    *bp =
    153        JS_IsExceptionPending(cx) ? false : Policy::deny(cx, act, id, mayThrow);
    154    return false;
    155  }
    156  *bp = true;
    157  return true;
    158 }
    159 
    160 #define NNXOW FilteringWrapper<CrossCompartmentSecurityWrapper, Opaque>
    161 #define NNXOWC FilteringWrapper<CrossCompartmentSecurityWrapper, OpaqueWithCall>
    162 
    163 template <>
    164 const NNXOW NNXOW::singleton(0);
    165 template <>
    166 const NNXOWC NNXOWC::singleton(0);
    167 
    168 template class NNXOW;
    169 template class NNXOWC;
    170 template class ChromeObjectWrapperBase;
    171 }  // namespace xpc