tor-browser

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

ExpandedPrincipal.cpp (13938B)


      1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=2 sw=2 et 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 "ExpandedPrincipal.h"
      8 #include "nsIClassInfoImpl.h"
      9 #include "nsIObjectInputStream.h"
     10 #include "nsReadableUtils.h"
     11 #include "mozilla/Base64.h"
     12 #include "mozilla/extensions/WebExtensionPolicy.h"
     13 #include "mozilla/JSONWriter.h"
     14 
     15 #include "js/JSON.h"
     16 #include "ExpandedPrincipalJSONHandler.h"
     17 #include "SubsumedPrincipalJSONHandler.h"
     18 
     19 using namespace mozilla;
     20 
     21 NS_IMPL_CLASSINFO(ExpandedPrincipal, nullptr, 0, NS_EXPANDEDPRINCIPAL_CID)
     22 NS_IMPL_QUERY_INTERFACE_CI(ExpandedPrincipal, nsIPrincipal,
     23                           nsIExpandedPrincipal)
     24 NS_IMPL_CI_INTERFACE_GETTER(ExpandedPrincipal, nsIPrincipal,
     25                            nsIExpandedPrincipal)
     26 
     27 ExpandedPrincipal::ExpandedPrincipal(
     28    nsTArray<nsCOMPtr<nsIPrincipal>>&& aPrincipals,
     29    const nsACString& aOriginNoSuffix, const OriginAttributes& aAttrs)
     30    : BasePrincipal(eExpandedPrincipal, aOriginNoSuffix, aAttrs),
     31      mPrincipals(std::move(aPrincipals)) {}
     32 
     33 ExpandedPrincipal::~ExpandedPrincipal() = default;
     34 
     35 already_AddRefed<ExpandedPrincipal> ExpandedPrincipal::Create(
     36    const nsTArray<nsCOMPtr<nsIPrincipal>>& aAllowList,
     37    const OriginAttributes& aAttrs) {
     38  nsTArray<nsCOMPtr<nsIPrincipal>> principals;
     39  for (size_t i = 0; i < aAllowList.Length(); ++i) {
     40    principals.AppendElement(aAllowList[i]);
     41  }
     42 
     43  nsAutoCString origin;
     44  origin.AssignLiteral("[Expanded Principal [");
     45  StringJoinAppend(
     46      origin, ", "_ns, principals,
     47      [](nsACString& dest, const nsCOMPtr<nsIPrincipal>& principal) {
     48        nsAutoCString subOrigin;
     49        DebugOnly<nsresult> rv = principal->GetOrigin(subOrigin);
     50        MOZ_ASSERT(NS_SUCCEEDED(rv));
     51        dest.Append(subOrigin);
     52      });
     53  origin.AppendLiteral("]]");
     54 
     55  RefPtr<ExpandedPrincipal> ep =
     56      new ExpandedPrincipal(std::move(principals), origin, aAttrs);
     57  return ep.forget();
     58 }
     59 
     60 NS_IMETHODIMP
     61 ExpandedPrincipal::GetDomain(nsIURI** aDomain) {
     62  *aDomain = nullptr;
     63  return NS_OK;
     64 }
     65 
     66 NS_IMETHODIMP
     67 ExpandedPrincipal::SetDomain(nsIURI* aDomain) { return NS_OK; }
     68 
     69 bool ExpandedPrincipal::SubsumesInternal(
     70    nsIPrincipal* aOther,
     71    BasePrincipal::DocumentDomainConsideration aConsideration) {
     72  // If aOther is an ExpandedPrincipal too, we break it down into its component
     73  // nsIPrincipals, and check subsumes on each one.
     74  if (Cast(aOther)->Is<ExpandedPrincipal>()) {
     75    auto* expanded = Cast(aOther)->As<ExpandedPrincipal>();
     76 
     77    for (auto& other : expanded->AllowList()) {
     78      // Use SubsumesInternal rather than Subsumes here, since OriginAttribute
     79      // checks are only done between non-expanded sub-principals, and we don't
     80      // need to incur the extra virtual call overhead.
     81      if (!SubsumesInternal(other, aConsideration)) {
     82        return false;
     83      }
     84    }
     85    return true;
     86  }
     87 
     88  // We're dealing with a regular principal. One of our principals must subsume
     89  // it.
     90  for (uint32_t i = 0; i < mPrincipals.Length(); ++i) {
     91    if (Cast(mPrincipals[i])->Subsumes(aOther, aConsideration)) {
     92      return true;
     93    }
     94  }
     95 
     96  return false;
     97 }
     98 
     99 bool ExpandedPrincipal::MayLoadInternal(nsIURI* uri) {
    100  for (uint32_t i = 0; i < mPrincipals.Length(); ++i) {
    101    if (BasePrincipal::Cast(mPrincipals[i])->MayLoadInternal(uri)) {
    102      return true;
    103    }
    104  }
    105 
    106  return false;
    107 }
    108 
    109 NS_IMETHODIMP
    110 ExpandedPrincipal::GetURI(nsIURI** aURI) {
    111  *aURI = nullptr;
    112  return NS_OK;
    113 }
    114 
    115 const nsTArray<nsCOMPtr<nsIPrincipal>>& ExpandedPrincipal::AllowList() {
    116  return mPrincipals;
    117 }
    118 
    119 NS_IMETHODIMP
    120 ExpandedPrincipal::GetBaseDomain(nsACString& aBaseDomain) {
    121  return NS_ERROR_NOT_AVAILABLE;
    122 }
    123 
    124 NS_IMETHODIMP
    125 ExpandedPrincipal::GetAddonId(nsAString& aAddonId) {
    126  aAddonId.Truncate();
    127  return NS_OK;
    128 };
    129 
    130 bool ExpandedPrincipal::AddonHasPermission(const nsAtom* aPerm) {
    131  for (size_t i = 0; i < mPrincipals.Length(); ++i) {
    132    if (BasePrincipal::Cast(mPrincipals[i])->AddonHasPermission(aPerm)) {
    133      return true;
    134    }
    135  }
    136  return false;
    137 }
    138 
    139 bool ExpandedPrincipal::AddonAllowsLoad(nsIURI* aURI,
    140                                        bool aExplicit /* = false */) {
    141  for (const auto& principal : mPrincipals) {
    142    if (Cast(principal)->AddonAllowsLoad(aURI, aExplicit)) {
    143      return true;
    144    }
    145  }
    146  return false;
    147 }
    148 
    149 void ExpandedPrincipal::SetCsp(nsIContentSecurityPolicy* aCSP) {
    150  AssertIsOnMainThread();
    151  mCSP = new nsMainThreadPtrHolder<nsIContentSecurityPolicy>(
    152      "ExpandedPrincipal::mCSP", aCSP);
    153 }
    154 
    155 NS_IMETHODIMP
    156 ExpandedPrincipal::GetCsp(nsIContentSecurityPolicy** aCsp) {
    157  AssertIsOnMainThread();
    158  NS_IF_ADDREF(*aCsp = mCSP);
    159  return NS_OK;
    160 }
    161 
    162 nsIPrincipal* ExpandedPrincipal::PrincipalToInherit(nsIURI* aRequestedURI) {
    163  if (aRequestedURI) {
    164    // If a given sub-principal subsumes the given URI, use that principal for
    165    // inheritance. In general, this only happens with certain CORS modes, loads
    166    // with forced principal inheritance, and creation of XML documents from
    167    // XMLHttpRequests or fetch requests. For URIs that normally inherit a
    168    // principal (such as data: URIs), we fall back to the last principal in the
    169    // allowlist.
    170    for (const auto& principal : mPrincipals) {
    171      if (Cast(principal)->MayLoadInternal(aRequestedURI)) {
    172        return principal;
    173      }
    174    }
    175  }
    176  return mPrincipals.LastElement();
    177 }
    178 
    179 nsresult ExpandedPrincipal::GetScriptLocation(nsACString& aStr) {
    180  aStr.AssignLiteral("[Expanded Principal [");
    181  for (size_t i = 0; i < mPrincipals.Length(); ++i) {
    182    if (i != 0) {
    183      aStr.AppendLiteral(", ");
    184    }
    185 
    186    nsAutoCString spec;
    187    nsresult rv =
    188        nsJSPrincipals::get(mPrincipals.ElementAt(i))->GetScriptLocation(spec);
    189    NS_ENSURE_SUCCESS(rv, rv);
    190 
    191    aStr.Append(spec);
    192  }
    193  aStr.AppendLiteral("]]");
    194  return NS_OK;
    195 }
    196 
    197 //////////////////////////////////////////
    198 // Methods implementing nsISerializable //
    199 //////////////////////////////////////////
    200 
    201 // We've had way too many issues with unversioned serializations, so
    202 // explicitly version this one.
    203 static const uint32_t kSerializationVersion = 1;
    204 
    205 NS_IMETHODIMP
    206 ExpandedPrincipal::Deserializer::Read(nsIObjectInputStream* aStream) {
    207  uint32_t version;
    208  nsresult rv = aStream->Read32(&version);
    209  if (version != kSerializationVersion) {
    210    MOZ_ASSERT(false,
    211               "We really need to add handling of the old(?) version here");
    212    return NS_ERROR_UNEXPECTED;
    213  }
    214 
    215  uint32_t count;
    216  rv = aStream->Read32(&count);
    217  if (NS_FAILED(rv)) {
    218    return rv;
    219  }
    220 
    221  nsTArray<nsCOMPtr<nsIPrincipal>> principals;
    222  if (!principals.SetCapacity(count, fallible)) {
    223    return NS_ERROR_OUT_OF_MEMORY;
    224  }
    225 
    226  for (uint32_t i = 0; i < count; ++i) {
    227    nsCOMPtr<nsISupports> read;
    228    rv = aStream->ReadObject(true, getter_AddRefs(read));
    229    if (NS_FAILED(rv)) {
    230      return rv;
    231    }
    232 
    233    nsCOMPtr<nsIPrincipal> principal = do_QueryInterface(read);
    234    if (!principal) {
    235      return NS_ERROR_UNEXPECTED;
    236    }
    237 
    238    principals.AppendElement(std::move(principal));
    239  }
    240 
    241  mPrincipal = ExpandedPrincipal::Create(principals, OriginAttributes());
    242  return NS_OK;
    243 }
    244 
    245 nsresult ExpandedPrincipal::GetSiteIdentifier(SiteIdentifier& aSite) {
    246  // Call GetSiteIdentifier on each of our principals and return a new
    247  // ExpandedPrincipal.
    248 
    249  nsTArray<nsCOMPtr<nsIPrincipal>> allowlist;
    250  for (const auto& principal : mPrincipals) {
    251    SiteIdentifier site;
    252    nsresult rv = Cast(principal)->GetSiteIdentifier(site);
    253    NS_ENSURE_SUCCESS(rv, rv);
    254    allowlist.AppendElement(site.GetPrincipal());
    255  }
    256 
    257  RefPtr<ExpandedPrincipal> expandedPrincipal =
    258      ExpandedPrincipal::Create(allowlist, OriginAttributesRef());
    259  MOZ_ASSERT(expandedPrincipal, "ExpandedPrincipal::Create returned nullptr?");
    260 
    261  aSite.Init(expandedPrincipal);
    262  return NS_OK;
    263 }
    264 
    265 nsresult ExpandedPrincipal::WriteJSONInnerProperties(JSONWriter& aWriter) {
    266  aWriter.StartArrayProperty(JSONEnumKeyString<eSpecs>(),
    267                             JSONWriter::CollectionStyle::SingleLineStyle);
    268 
    269  for (const auto& principal : mPrincipals) {
    270    aWriter.StartObjectElement(JSONWriter::CollectionStyle::SingleLineStyle);
    271 
    272    nsresult rv = BasePrincipal::Cast(principal)->WriteJSONProperties(aWriter);
    273    NS_ENSURE_SUCCESS(rv, rv);
    274 
    275    aWriter.EndObject();
    276  }
    277 
    278  aWriter.EndArray();
    279 
    280  nsAutoCString suffix;
    281  OriginAttributesRef().CreateSuffix(suffix);
    282  if (suffix.Length() > 0) {
    283    WriteJSONProperty<eSuffix>(aWriter, suffix);
    284  }
    285 
    286  return NS_OK;
    287 }
    288 
    289 bool ExpandedPrincipalJSONHandler::ProcessSubsumedResult(bool aResult) {
    290  if (!aResult) {
    291    NS_WARNING("Failed to parse subsumed principal");
    292    mState = State::Error;
    293    return false;
    294  }
    295  return true;
    296 }
    297 
    298 bool ExpandedPrincipalJSONHandler::startObject() {
    299  if (mSubsumedHandler.isSome()) {
    300    return ProcessSubsumedResult(mSubsumedHandler->startObject());
    301  }
    302 
    303  switch (mState) {
    304    case State::Init:
    305      mState = State::StartObject;
    306      break;
    307    case State::StartArray:
    308      mState = State::SubsumedPrincipal;
    309      [[fallthrough]];
    310    case State::SubsumedPrincipal:
    311      mSubsumedHandler.emplace();
    312 
    313      return ProcessSubsumedResult(mSubsumedHandler->startObject());
    314    default:
    315      NS_WARNING("Unexpected object value");
    316      mState = State::Error;
    317      return false;
    318  }
    319 
    320  return true;
    321 }
    322 
    323 bool ExpandedPrincipalJSONHandler::propertyName(const JS::Latin1Char* name,
    324                                                size_t length) {
    325  if (mSubsumedHandler.isSome()) {
    326    return ProcessSubsumedResult(mSubsumedHandler->propertyName(name, length));
    327  }
    328 
    329  switch (mState) {
    330    case State::StartObject:
    331    case State::AfterPropertyValue: {
    332      if (length != 1) {
    333        NS_WARNING(
    334            nsPrintfCString("Unexpected property name length: %zu", length)
    335                .get());
    336        mState = State::Error;
    337        return false;
    338      }
    339 
    340      char key = char(name[0]);
    341      switch (key) {
    342        case ExpandedPrincipal::SpecsKey:
    343          mState = State::SpecsKey;
    344          break;
    345        case ExpandedPrincipal::SuffixKey:
    346          mState = State::SuffixKey;
    347          break;
    348        default:
    349          NS_WARNING(
    350              nsPrintfCString("Unexpected property name: '%c'", key).get());
    351          mState = State::Error;
    352          return false;
    353      }
    354      break;
    355    }
    356    default:
    357      NS_WARNING("Unexpected property name");
    358      mState = State::Error;
    359      return false;
    360  }
    361 
    362  return true;
    363 }
    364 
    365 bool ExpandedPrincipalJSONHandler::endObject() {
    366  if (mSubsumedHandler.isSome()) {
    367    if (!ProcessSubsumedResult(mSubsumedHandler->endObject())) {
    368      return false;
    369    }
    370    if (mSubsumedHandler->HasAccepted()) {
    371      nsCOMPtr<nsIPrincipal> principal = mSubsumedHandler->mPrincipal.forget();
    372      mSubsumedHandler.reset();
    373      mAllowList.AppendElement(principal);
    374    }
    375    return true;
    376  }
    377 
    378  switch (mState) {
    379    case State::AfterPropertyValue:
    380      mPrincipal = ExpandedPrincipal::Create(mAllowList, mAttrs);
    381      MOZ_ASSERT(mPrincipal);
    382 
    383      mState = State::EndObject;
    384      break;
    385    default:
    386      NS_WARNING("Unexpected end of object");
    387      mState = State::Error;
    388      return false;
    389  }
    390 
    391  return true;
    392 }
    393 
    394 bool ExpandedPrincipalJSONHandler::startArray() {
    395  switch (mState) {
    396    case State::SpecsKey:
    397      mState = State::StartArray;
    398      break;
    399    default:
    400      NS_WARNING("Unexpected array value");
    401      mState = State::Error;
    402      return false;
    403  }
    404 
    405  return true;
    406 }
    407 
    408 bool ExpandedPrincipalJSONHandler::endArray() {
    409  switch (mState) {
    410    case State::SubsumedPrincipal: {
    411      mState = State::AfterPropertyValue;
    412      break;
    413    }
    414    default:
    415      NS_WARNING("Unexpected end of array");
    416      mState = State::Error;
    417      return false;
    418  }
    419 
    420  return true;
    421 }
    422 
    423 bool ExpandedPrincipalJSONHandler::stringValue(const JS::Latin1Char* str,
    424                                               size_t length) {
    425  if (mSubsumedHandler.isSome()) {
    426    return ProcessSubsumedResult(mSubsumedHandler->stringValue(str, length));
    427  }
    428 
    429  switch (mState) {
    430    case State::SpecsKey: {
    431      nsDependentCSubstring specs(reinterpret_cast<const char*>(str), length);
    432 
    433      for (const nsACString& each : specs.Split(',')) {
    434        nsAutoCString result;
    435        nsresult rv = Base64Decode(each, result);
    436        MOZ_ASSERT(NS_SUCCEEDED(rv), "failed to decode");
    437        if (NS_FAILED(rv)) {
    438          mState = State::Error;
    439          return false;
    440        }
    441 
    442        nsCOMPtr<nsIPrincipal> principal = BasePrincipal::FromJSON(result);
    443        if (!principal) {
    444          mState = State::Error;
    445          return false;
    446        }
    447        mAllowList.AppendElement(principal);
    448      }
    449 
    450      mState = State::AfterPropertyValue;
    451      break;
    452    }
    453    case State::SuffixKey: {
    454      nsDependentCSubstring attrs(reinterpret_cast<const char*>(str), length);
    455      if (!mAttrs.PopulateFromSuffix(attrs)) {
    456        mState = State::Error;
    457        return false;
    458      }
    459 
    460      mState = State::AfterPropertyValue;
    461      break;
    462    }
    463    default:
    464      NS_WARNING("Unexpected string value");
    465      mState = State::Error;
    466      return false;
    467  }
    468 
    469  return true;
    470 }
    471 
    472 NS_IMETHODIMP
    473 ExpandedPrincipal::IsThirdPartyURI(nsIURI* aURI, bool* aRes) {
    474  // ExpandedPrincipal for extension content scripts consist of two principals,
    475  // the document's principal and the extension's principal.
    476  // To make sure that the third-party check behaves like the web page on which
    477  // the content script is running, ignore the extension's principal.
    478 
    479  for (const auto& principal : mPrincipals) {
    480    if (!Cast(principal)->AddonPolicyCore()) {
    481      return Cast(principal)->IsThirdPartyURI(aURI, aRes);
    482    }
    483  }
    484 
    485  if (mPrincipals.IsEmpty()) {
    486    *aRes = true;
    487    return NS_OK;
    488  }
    489 
    490  return Cast(mPrincipals[0])->IsThirdPartyURI(aURI, aRes);
    491 }