LCOV - code coverage report
Current view: top level - js/xpconnect/wrappers - AccessCheck.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 27 240 11.2 %
Date: 2017-07-14 16:53:18 Functions: 8 20 40.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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/. */
       6             : 
       7             : #include "AccessCheck.h"
       8             : 
       9             : #include "nsJSPrincipals.h"
      10             : #include "BasePrincipal.h"
      11             : #include "nsGlobalWindow.h"
      12             : 
      13             : #include "XPCWrapper.h"
      14             : #include "XrayWrapper.h"
      15             : #include "FilteringWrapper.h"
      16             : 
      17             : #include "jsfriendapi.h"
      18             : #include "mozilla/ErrorResult.h"
      19             : #include "mozilla/dom/BindingUtils.h"
      20             : #include "mozilla/dom/LocationBinding.h"
      21             : #include "mozilla/dom/WindowBinding.h"
      22             : #include "mozilla/jsipc/CrossProcessObjectWrappers.h"
      23             : #include "nsIDOMWindowCollection.h"
      24             : #include "nsJSUtils.h"
      25             : #include "xpcprivate.h"
      26             : 
      27             : using namespace mozilla;
      28             : using namespace JS;
      29             : using namespace js;
      30             : 
      31             : namespace xpc {
      32             : 
      33             : nsIPrincipal*
      34       69517 : GetCompartmentPrincipal(JSCompartment* compartment)
      35             : {
      36       69517 :     return nsJSPrincipals::get(JS_GetCompartmentPrincipals(compartment));
      37             : }
      38             : 
      39             : nsIPrincipal*
      40          33 : GetObjectPrincipal(JSObject* obj)
      41             : {
      42          33 :     return GetCompartmentPrincipal(js::GetObjectCompartment(obj));
      43             : }
      44             : 
      45             : // Does the principal of compartment a subsume the principal of compartment b?
      46             : bool
      47           5 : AccessCheck::subsumes(JSCompartment* a, JSCompartment* b)
      48             : {
      49           5 :     nsIPrincipal* aprin = GetCompartmentPrincipal(a);
      50           5 :     nsIPrincipal* bprin = GetCompartmentPrincipal(b);
      51           5 :     return BasePrincipal::Cast(aprin)->FastSubsumes(bprin);
      52             : }
      53             : 
      54             : bool
      55           4 : AccessCheck::subsumes(JSObject* a, JSObject* b)
      56             : {
      57           4 :     return subsumes(js::GetObjectCompartment(a), js::GetObjectCompartment(b));
      58             : }
      59             : 
      60             : // Same as above, but considering document.domain.
      61             : bool
      62       18621 : AccessCheck::subsumesConsideringDomain(JSCompartment* a, JSCompartment* b)
      63             : {
      64       18621 :     MOZ_ASSERT(OriginAttributes::IsRestrictOpenerAccessForFPI());
      65       18621 :     nsIPrincipal* aprin = GetCompartmentPrincipal(a);
      66       18621 :     nsIPrincipal* bprin = GetCompartmentPrincipal(b);
      67       18621 :     return BasePrincipal::Cast(aprin)->FastSubsumesConsideringDomain(bprin);
      68             : }
      69             : 
      70             : bool
      71           0 : AccessCheck::subsumesConsideringDomainIgnoringFPD(JSCompartment* a,
      72             :                                                   JSCompartment* b)
      73             : {
      74           0 :     MOZ_ASSERT(!OriginAttributes::IsRestrictOpenerAccessForFPI());
      75           0 :     nsIPrincipal* aprin = GetCompartmentPrincipal(a);
      76           0 :     nsIPrincipal* bprin = GetCompartmentPrincipal(b);
      77           0 :     return BasePrincipal::Cast(aprin)->FastSubsumesConsideringDomainIgnoringFPD(bprin);
      78             : }
      79             : 
      80             : // Does the compartment of the wrapper subsumes the compartment of the wrappee?
      81             : bool
      82           0 : AccessCheck::wrapperSubsumes(JSObject* wrapper)
      83             : {
      84           0 :     MOZ_ASSERT(js::IsWrapper(wrapper));
      85           0 :     JSObject* wrapped = js::UncheckedUnwrap(wrapper);
      86           0 :     return AccessCheck::subsumes(js::GetObjectCompartment(wrapper),
      87           0 :                                  js::GetObjectCompartment(wrapped));
      88             : }
      89             : 
      90             : bool
      91       32232 : AccessCheck::isChrome(JSCompartment* compartment)
      92             : {
      93       32232 :     nsIPrincipal* principal = GetCompartmentPrincipal(compartment);
      94       32232 :     return nsXPConnect::SystemPrincipal() == principal;
      95             : }
      96             : 
      97             : bool
      98        3353 : AccessCheck::isChrome(JSObject* obj)
      99             : {
     100        3353 :     return isChrome(js::GetObjectCompartment(obj));
     101             : }
     102             : 
     103             : nsIPrincipal*
     104           0 : AccessCheck::getPrincipal(JSCompartment* compartment)
     105             : {
     106           0 :     return GetCompartmentPrincipal(compartment);
     107             : }
     108             : 
     109             : // Hardcoded policy for cross origin property access. See the HTML5 Spec.
     110             : static bool
     111           0 : IsPermitted(CrossOriginObjectType type, JSFlatString* prop, bool set)
     112             : {
     113           0 :     size_t propLength = JS_GetStringLength(JS_FORGET_STRING_FLATNESS(prop));
     114           0 :     if (!propLength)
     115           0 :         return false;
     116             : 
     117           0 :     char16_t propChar0 = JS_GetFlatStringCharAt(prop, 0);
     118           0 :     if (type == CrossOriginLocation)
     119           0 :         return dom::LocationBinding::IsPermitted(prop, propChar0, set);
     120           0 :     if (type == CrossOriginWindow)
     121           0 :         return dom::WindowBinding::IsPermitted(prop, propChar0, set);
     122             : 
     123           0 :     return false;
     124             : }
     125             : 
     126             : static bool
     127           0 : IsFrameId(JSContext* cx, JSObject* obj, jsid idArg)
     128             : {
     129           0 :     MOZ_ASSERT(!js::IsWrapper(obj));
     130           0 :     RootedId id(cx, idArg);
     131             : 
     132           0 :     nsGlobalWindow* win = WindowOrNull(obj);
     133           0 :     if (!win) {
     134           0 :         return false;
     135             :     }
     136             : 
     137           0 :     nsCOMPtr<nsIDOMWindowCollection> col = win->GetFrames();
     138           0 :     if (!col) {
     139           0 :         return false;
     140             :     }
     141             : 
     142           0 :     nsCOMPtr<mozIDOMWindowProxy> domwin;
     143           0 :     if (JSID_IS_INT(id)) {
     144           0 :         col->Item(JSID_TO_INT(id), getter_AddRefs(domwin));
     145           0 :     } else if (JSID_IS_STRING(id)) {
     146           0 :         nsAutoJSString idAsString;
     147           0 :         if (!idAsString.init(cx, JSID_TO_STRING(id))) {
     148           0 :             return false;
     149             :         }
     150           0 :         col->NamedItem(idAsString, getter_AddRefs(domwin));
     151             :     }
     152             : 
     153           0 :     return domwin != nullptr;
     154             : }
     155             : 
     156             : CrossOriginObjectType
     157           1 : IdentifyCrossOriginObject(JSObject* obj)
     158             : {
     159           1 :     obj = js::UncheckedUnwrap(obj, /* stopAtWindowProxy = */ false);
     160           1 :     const js::Class* clasp = js::GetObjectClass(obj);
     161           1 :     MOZ_ASSERT(!XrayUtils::IsXPCWNHolderClass(Jsvalify(clasp)), "shouldn't have a holder here");
     162             : 
     163           1 :     if (clasp->name[0] == 'L' && !strcmp(clasp->name, "Location"))
     164           0 :         return CrossOriginLocation;
     165           1 :     if (clasp->name[0] == 'W' && !strcmp(clasp->name, "Window"))
     166           1 :         return CrossOriginWindow;
     167             : 
     168           0 :     return CrossOriginOpaque;
     169             : }
     170             : 
     171             : bool
     172           0 : AccessCheck::isCrossOriginAccessPermitted(JSContext* cx, HandleObject wrapper, HandleId id,
     173             :                                           Wrapper::Action act)
     174             : {
     175           0 :     if (act == Wrapper::CALL)
     176           0 :         return false;
     177             : 
     178           0 :     if (act == Wrapper::ENUMERATE)
     179           0 :         return true;
     180             : 
     181             :     // For the case of getting a property descriptor, we allow if either GET or SET
     182             :     // is allowed, and rely on FilteringWrapper to filter out any disallowed accessors.
     183           0 :     if (act == Wrapper::GET_PROPERTY_DESCRIPTOR) {
     184           0 :         return isCrossOriginAccessPermitted(cx, wrapper, id, Wrapper::GET) ||
     185           0 :                isCrossOriginAccessPermitted(cx, wrapper, id, Wrapper::SET);
     186             :     }
     187             : 
     188           0 :     RootedObject obj(cx, js::UncheckedUnwrap(wrapper, /* stopAtWindowProxy = */ false));
     189           0 :     CrossOriginObjectType type = IdentifyCrossOriginObject(obj);
     190           0 :     if (JSID_IS_STRING(id)) {
     191           0 :         if (IsPermitted(type, JSID_TO_FLAT_STRING(id), act == Wrapper::SET))
     192           0 :             return true;
     193           0 :     } else if (type != CrossOriginOpaque &&
     194           0 :                IsCrossOriginWhitelistedSymbol(cx, id)) {
     195             :         // We always allow access to @@toStringTag, @@hasInstance, and
     196             :         // @@isConcatSpreadable.  But then we nerf them to be a value descriptor
     197             :         // with value undefined in CrossOriginXrayWrapper.
     198           0 :         return true;
     199             :     }
     200             : 
     201           0 :     if (act != Wrapper::GET)
     202           0 :         return false;
     203             : 
     204             :     // Check for frame IDs. If we're resolving named frames, make sure to only
     205             :     // resolve ones that don't shadow native properties. See bug 860494.
     206           0 :     if (type == CrossOriginWindow) {
     207           0 :         if (JSID_IS_STRING(id)) {
     208           0 :             bool wouldShadow = false;
     209           0 :             if (!XrayUtils::HasNativeProperty(cx, wrapper, id, &wouldShadow) ||
     210             :                 wouldShadow)
     211             :             {
     212             :                 // If the named subframe matches the name of a DOM constructor,
     213             :                 // the global resolve triggered by the HasNativeProperty call
     214             :                 // above will try to perform a CheckedUnwrap on |wrapper|, and
     215             :                 // throw a security error if it fails. That exception isn't
     216             :                 // really useful for our callers, so we silence it and just
     217             :                 // deny access to the property (since it matched a builtin).
     218             :                 //
     219             :                 // Note that this would be a problem if the resolve code ever
     220             :                 // tried to CheckedUnwrap the wrapper _before_ concluding that
     221             :                 // the name corresponds to a builtin global property, since it
     222             :                 // would mean that we'd never permit cross-origin named subframe
     223             :                 // access (something we regrettably need to support).
     224           0 :                 JS_ClearPendingException(cx);
     225           0 :                 return false;
     226             :             }
     227             :         }
     228           0 :         return IsFrameId(cx, obj, id);
     229             :     }
     230           0 :     return false;
     231             : }
     232             : 
     233             : bool
     234           0 : AccessCheck::checkPassToPrivilegedCode(JSContext* cx, HandleObject wrapper, HandleValue v)
     235             : {
     236             :     // Primitives are fine.
     237           0 :     if (!v.isObject())
     238           0 :         return true;
     239           0 :     RootedObject obj(cx, &v.toObject());
     240             : 
     241             :     // Non-wrappers are fine.
     242           0 :     if (!js::IsWrapper(obj))
     243           0 :         return true;
     244             : 
     245             :     // CPOWs use COWs (in the unprivileged junk scope) for all child->parent
     246             :     // references. Without this test, the child process wouldn't be able to
     247             :     // pass any objects at all to CPOWs.
     248           0 :     if (mozilla::jsipc::IsWrappedCPOW(obj) &&
     249           0 :         js::GetObjectCompartment(wrapper) == js::GetObjectCompartment(xpc::UnprivilegedJunkScope()) &&
     250           0 :         XRE_IsParentProcess())
     251             :     {
     252           0 :         return true;
     253             :     }
     254             : 
     255             :     // COWs are fine to pass to chrome if and only if they have __exposedProps__,
     256             :     // since presumably content should never have a reason to pass an opaque
     257             :     // object back to chrome.
     258           0 :     if (AccessCheck::isChrome(js::UncheckedUnwrap(wrapper)) && WrapperFactory::IsCOW(obj)) {
     259           0 :         RootedObject target(cx, js::UncheckedUnwrap(obj));
     260           0 :         JSAutoCompartment ac(cx, target);
     261           0 :         RootedId id(cx, GetJSIDByIndex(cx, XPCJSContext::IDX_EXPOSEDPROPS));
     262           0 :         bool found = false;
     263           0 :         if (!JS_HasPropertyById(cx, target, id, &found))
     264           0 :             return false;
     265           0 :         if (found)
     266           0 :             return true;
     267             :     }
     268             : 
     269             :     // Same-origin wrappers are fine.
     270           0 :     if (AccessCheck::wrapperSubsumes(obj))
     271           0 :         return true;
     272             : 
     273             :     // Badness.
     274           0 :     JS_ReportErrorASCII(cx, "Permission denied to pass object to privileged code");
     275           0 :     return false;
     276             : }
     277             : 
     278             : bool
     279           0 : AccessCheck::checkPassToPrivilegedCode(JSContext* cx, HandleObject wrapper, const CallArgs& args)
     280             : {
     281           0 :     if (!checkPassToPrivilegedCode(cx, wrapper, args.thisv()))
     282           0 :         return false;
     283           0 :     for (size_t i = 0; i < args.length(); ++i) {
     284           0 :         if (!checkPassToPrivilegedCode(cx, wrapper, args[i]))
     285           0 :             return false;
     286             :     }
     287           0 :     return true;
     288             : }
     289             : 
     290             : void
     291           0 : AccessCheck::reportCrossOriginDenial(JSContext* cx, JS::HandleId id,
     292             :                                      const nsACString& accessType)
     293             : {
     294             :     // This function exists because we want to report DOM SecurityErrors, not JS
     295             :     // Errors, when denying access on cross-origin DOM objects.  It's
     296             :     // conceptually pretty similar to
     297             :     // AutoEnterPolicy::reportErrorIfExceptionIsNotPending.
     298           0 :     if (JS_IsExceptionPending(cx)) {
     299           0 :         return;
     300             :     }
     301             : 
     302           0 :     nsAutoCString message;
     303           0 :     if (JSID_IS_VOID(id)) {
     304           0 :         message = NS_LITERAL_CSTRING("Permission denied to access object");
     305             :     } else {
     306             :         // We want to use JS_ValueToSource here, because that most closely
     307             :         // matches what AutoEnterPolicy::reportErrorIfExceptionIsNotPending
     308             :         // does.
     309           0 :         JS::RootedValue idVal(cx, js::IdToValue(id));
     310           0 :         nsAutoJSString propName;
     311           0 :         JS::RootedString idStr(cx, JS_ValueToSource(cx, idVal));
     312           0 :         if (!idStr || !propName.init(cx, idStr)) {
     313           0 :             return;
     314             :         }
     315           0 :         message = NS_LITERAL_CSTRING("Permission denied to ") +
     316           0 :                   accessType +
     317           0 :                   NS_LITERAL_CSTRING(" property ") +
     318           0 :                   NS_ConvertUTF16toUTF8(propName) +
     319           0 :                   NS_LITERAL_CSTRING(" on cross-origin object");
     320             :     }
     321           0 :     ErrorResult rv;
     322           0 :     rv.ThrowDOMException(NS_ERROR_DOM_SECURITY_ERR, message);
     323           0 :     MOZ_ALWAYS_TRUE(rv.MaybeSetPendingException(cx));
     324             : }
     325             : 
     326             : enum Access { READ = (1<<0), WRITE = (1<<1), NO_ACCESS = 0 };
     327             : 
     328             : static void
     329           0 : EnterAndThrowASCII(JSContext* cx, JSObject* wrapper, const char* msg)
     330             : {
     331           0 :     JSAutoCompartment ac(cx, wrapper);
     332           0 :     JS_ReportErrorASCII(cx, "%s", msg);
     333           0 : }
     334             : 
     335             : bool
     336           0 : ExposedPropertiesOnly::check(JSContext* cx, HandleObject wrapper, HandleId id, Wrapper::Action act)
     337             : {
     338           0 :     RootedObject wrappedObject(cx, Wrapper::wrappedObject(wrapper));
     339             : 
     340           0 :     if (act == Wrapper::CALL)
     341           0 :         return false;
     342             : 
     343             :     // For the case of getting a property descriptor, we allow if either GET or SET
     344             :     // is allowed, and rely on FilteringWrapper to filter out any disallowed accessors.
     345           0 :     if (act == Wrapper::GET_PROPERTY_DESCRIPTOR) {
     346           0 :         return check(cx, wrapper, id, Wrapper::GET) ||
     347           0 :                check(cx, wrapper, id, Wrapper::SET);
     348             :     }
     349             : 
     350           0 :     RootedId exposedPropsId(cx, GetJSIDByIndex(cx, XPCJSContext::IDX_EXPOSEDPROPS));
     351             : 
     352             :     // We need to enter the wrappee's compartment to look at __exposedProps__,
     353             :     // but we want to be in the wrapper's compartment if we call Deny().
     354             :     //
     355             :     // Unfortunately, |cx| can be in either compartment when we call ::check. :-(
     356           0 :     JSAutoCompartment ac(cx, wrappedObject);
     357             : 
     358           0 :     bool found = false;
     359           0 :     if (!JS_HasPropertyById(cx, wrappedObject, exposedPropsId, &found))
     360           0 :         return false;
     361             : 
     362             :     // If no __exposedProps__ existed, deny access.
     363           0 :     if (!found) {
     364             :         // Previously we automatically granted access to indexed properties and
     365             :         // .length for Array COWs. We're not doing that anymore, so make sure to
     366             :         // let people know what's going on.
     367             :         bool isArray;
     368           0 :         if (!JS_IsArrayObject(cx, wrappedObject, &isArray))
     369           0 :             return false;
     370           0 :         if (!isArray)
     371           0 :             isArray = JS_IsTypedArrayObject(wrappedObject);
     372           0 :         bool isIndexedAccessOnArray = isArray && JSID_IS_INT(id) && JSID_TO_INT(id) >= 0;
     373           0 :         bool isLengthAccessOnArray = isArray && JSID_IS_STRING(id) &&
     374           0 :                                      JS_FlatStringEqualsAscii(JSID_TO_FLAT_STRING(id), "length");
     375           0 :         if (isIndexedAccessOnArray || isLengthAccessOnArray) {
     376           0 :             JSAutoCompartment ac2(cx, wrapper);
     377             :             ReportWrapperDenial(cx, id, WrapperDenialForCOW,
     378           0 :                                 "Access to elements and length of privileged Array not permitted");
     379             :         }
     380             : 
     381           0 :         return false;
     382             :     }
     383             : 
     384           0 :     if (id == JSID_VOID)
     385           0 :         return true;
     386             : 
     387           0 :     Rooted<PropertyDescriptor> desc(cx);
     388           0 :     if (!JS_GetPropertyDescriptorById(cx, wrappedObject, exposedPropsId, &desc))
     389           0 :         return false;
     390             : 
     391           0 :     if (!desc.object())
     392           0 :         return false;
     393             : 
     394           0 :     if (desc.hasGetterOrSetter()) {
     395           0 :         EnterAndThrowASCII(cx, wrapper, "__exposedProps__ must be a value property");
     396           0 :         return false;
     397             :     }
     398             : 
     399           0 :     RootedValue exposedProps(cx, desc.value());
     400           0 :     if (exposedProps.isNullOrUndefined())
     401           0 :         return false;
     402             : 
     403           0 :     if (!exposedProps.isObject()) {
     404           0 :         EnterAndThrowASCII(cx, wrapper, "__exposedProps__ must be undefined, null, or an Object");
     405           0 :         return false;
     406             :     }
     407             : 
     408           0 :     RootedObject hallpass(cx, &exposedProps.toObject());
     409             : 
     410           0 :     if (!AccessCheck::subsumes(js::UncheckedUnwrap(hallpass), wrappedObject)) {
     411           0 :         EnterAndThrowASCII(cx, wrapper, "Invalid __exposedProps__");
     412           0 :         return false;
     413             :     }
     414             : 
     415           0 :     Access access = NO_ACCESS;
     416             : 
     417           0 :     if (!JS_GetPropertyDescriptorById(cx, hallpass, id, &desc)) {
     418           0 :         return false; // Error
     419             :     }
     420           0 :     if (!desc.object() || !desc.enumerable())
     421           0 :         return false;
     422             : 
     423           0 :     if (!desc.value().isString()) {
     424           0 :         EnterAndThrowASCII(cx, wrapper, "property must be a string");
     425           0 :         return false;
     426             :     }
     427             : 
     428           0 :     JSFlatString* flat = JS_FlattenString(cx, desc.value().toString());
     429           0 :     if (!flat)
     430           0 :         return false;
     431             : 
     432           0 :     size_t length = JS_GetStringLength(JS_FORGET_STRING_FLATNESS(flat));
     433             : 
     434           0 :     for (size_t i = 0; i < length; ++i) {
     435           0 :         char16_t ch = JS_GetFlatStringCharAt(flat, i);
     436           0 :         switch (ch) {
     437             :         case 'r':
     438           0 :             if (access & READ) {
     439           0 :                 EnterAndThrowASCII(cx, wrapper, "duplicate 'readable' property flag");
     440           0 :                 return false;
     441             :             }
     442           0 :             access = Access(access | READ);
     443           0 :             break;
     444             : 
     445             :         case 'w':
     446           0 :             if (access & WRITE) {
     447           0 :                 EnterAndThrowASCII(cx, wrapper, "duplicate 'writable' property flag");
     448           0 :                 return false;
     449             :             }
     450           0 :             access = Access(access | WRITE);
     451           0 :             break;
     452             : 
     453             :         default:
     454           0 :             EnterAndThrowASCII(cx, wrapper, "properties can only be readable or read and writable");
     455           0 :             return false;
     456             :         }
     457             :     }
     458             : 
     459           0 :     if (access == NO_ACCESS) {
     460           0 :         EnterAndThrowASCII(cx, wrapper, "specified properties must have a permission bit set");
     461           0 :         return false;
     462             :     }
     463             : 
     464           0 :     if ((act == Wrapper::SET && !(access & WRITE)) ||
     465           0 :         (act != Wrapper::SET && !(access & READ))) {
     466           0 :         return false;
     467             :     }
     468             : 
     469             :     // Inspect the property on the underlying object to check for red flags.
     470           0 :     if (!JS_GetPropertyDescriptorById(cx, wrappedObject, id, &desc))
     471           0 :         return false;
     472             : 
     473             :     // Reject accessor properties.
     474           0 :     if (desc.hasGetterOrSetter()) {
     475           0 :         EnterAndThrowASCII(cx, wrapper, "Exposing privileged accessor properties is prohibited");
     476           0 :         return false;
     477             :     }
     478             : 
     479             :     // Reject privileged or cross-origin callables.
     480           0 :     if (desc.value().isObject()) {
     481           0 :         RootedObject maybeCallable(cx, js::UncheckedUnwrap(&desc.value().toObject()));
     482           0 :         if (JS::IsCallable(maybeCallable) && !AccessCheck::subsumes(wrapper, maybeCallable)) {
     483           0 :             EnterAndThrowASCII(cx, wrapper, "Exposing privileged or cross-origin callable is prohibited");
     484           0 :             return false;
     485             :         }
     486             :     }
     487             : 
     488           0 :     return true;
     489             : }
     490             : 
     491             : bool
     492           0 : ExposedPropertiesOnly::deny(JSContext* cx, js::Wrapper::Action act, HandleId id,
     493             :                             bool mayThrow)
     494             : {
     495             :     // Fail silently for GET, ENUMERATE, and GET_PROPERTY_DESCRIPTOR.
     496           0 :     if (act == js::Wrapper::GET || act == js::Wrapper::ENUMERATE ||
     497             :         act == js::Wrapper::GET_PROPERTY_DESCRIPTOR)
     498             :     {
     499             :         // Note that ReportWrapperDenial doesn't do any _exception_ reporting,
     500             :         // so we want to do this regardless of the value of mayThrow.
     501             :         return ReportWrapperDenial(cx, id, WrapperDenialForCOW,
     502           0 :                                    "Access to privileged JS object not permitted");
     503             :     }
     504             : 
     505           0 :     return false;
     506             : }
     507             : 
     508             : } // namespace xpc

Generated by: LCOV version 1.13