tor-browser

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

nsAboutProtocolHandler.cpp (12797B)


      1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* This Source Code Form is subject to the terms of the Mozilla Public
      3 * License, v. 2.0. If a copy of the MPL was not distributed with this
      4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      5 
      6 #include "base/basictypes.h"
      7 
      8 #include "nsAboutProtocolHandler.h"
      9 #include "nsIURI.h"
     10 #include "nsIAboutModule.h"
     11 #include "nsContentUtils.h"
     12 #include "nsString.h"
     13 #include "nsNetCID.h"
     14 #include "nsAboutProtocolUtils.h"
     15 #include "nsError.h"
     16 #include "nsNetUtil.h"
     17 #include "nsIObjectInputStream.h"
     18 #include "nsIObjectOutputStream.h"
     19 #include "nsIWritablePropertyBag2.h"
     20 #include "nsIChannel.h"
     21 #include "nsIScriptError.h"
     22 #include "nsIClassInfoImpl.h"
     23 
     24 #include "mozilla/ipc/URIUtils.h"
     25 
     26 namespace mozilla {
     27 namespace net {
     28 
     29 static NS_DEFINE_CID(kNestedAboutURICID, NS_NESTEDABOUTURI_CID);
     30 
     31 static bool IsSafeToLinkForUntrustedContent(nsIURI* aURI) {
     32  nsAutoCString path;
     33  aURI->GetPathQueryRef(path);
     34 
     35  int32_t f = path.FindChar('#');
     36  if (f >= 0) {
     37    path.SetLength(f);
     38  }
     39 
     40  f = path.FindChar('?');
     41  if (f >= 0) {
     42    path.SetLength(f);
     43  }
     44 
     45  ToLowerCase(path);
     46 
     47  // The about modules for these URL types have the
     48  // URI_SAFE_FOR_UNTRUSTED_CONTENT and MAKE_LINKABLE flags set.
     49  return path.EqualsLiteral("blank") || path.EqualsLiteral("logo") ||
     50         path.EqualsLiteral("srcdoc");
     51 }
     52 
     53 ////////////////////////////////////////////////////////////////////////////////
     54 
     55 NS_IMPL_ISUPPORTS(nsAboutProtocolHandler, nsIProtocolHandler,
     56                  nsIProtocolHandlerWithDynamicFlags, nsISupportsWeakReference)
     57 
     58 ////////////////////////////////////////////////////////////////////////////////
     59 // nsIProtocolHandler methods:
     60 
     61 NS_IMETHODIMP
     62 nsAboutProtocolHandler::GetScheme(nsACString& result) {
     63  result.AssignLiteral("about");
     64  return NS_OK;
     65 }
     66 
     67 NS_IMETHODIMP
     68 nsAboutProtocolHandler::GetFlagsForURI(nsIURI* aURI, uint32_t* aFlags) {
     69  // First use the default (which is "unsafe for content"):
     70  *aFlags = URI_NORELATIVE | URI_NOAUTH | URI_DANGEROUS_TO_LOAD |
     71            URI_SCHEME_NOT_SELF_LINKABLE;
     72 
     73  // Now try to see if this URI overrides the default:
     74  nsCOMPtr<nsIAboutModule> aboutMod;
     75  nsresult rv = NS_GetAboutModule(aURI, getter_AddRefs(aboutMod));
     76  if (NS_FAILED(rv)) {
     77    // Swallow this and just tell the consumer the default:
     78    return NS_OK;
     79  }
     80  uint32_t aboutModuleFlags = 0;
     81  rv = aboutMod->GetURIFlags(aURI, &aboutModuleFlags);
     82  // This should never happen, so pass back the error:
     83  NS_ENSURE_SUCCESS(rv, rv);
     84 
     85  // Secure (https) pages can load safe about pages without becoming
     86  // mixed content.
     87  if (aboutModuleFlags & nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT) {
     88    *aFlags |= URI_IS_POTENTIALLY_TRUSTWORTHY;
     89    // about: pages can only be loaded by unprivileged principals
     90    // if they are marked as LINKABLE
     91    if (aboutModuleFlags & nsIAboutModule::MAKE_LINKABLE) {
     92      // Replace URI_DANGEROUS_TO_LOAD with URI_LOADABLE_BY_ANYONE.
     93      *aFlags &= ~URI_DANGEROUS_TO_LOAD;
     94      *aFlags |= URI_LOADABLE_BY_ANYONE;
     95    }
     96  }
     97  return NS_OK;
     98 }
     99 
    100 // static
    101 nsresult nsAboutProtocolHandler::CreateNewURI(const nsACString& aSpec,
    102                                              const char* aCharset,
    103                                              nsIURI* aBaseURI,
    104                                              nsIURI** aResult) {
    105  *aResult = nullptr;
    106  nsresult rv;
    107 
    108  // Use a simple URI to parse out some stuff first
    109  nsCOMPtr<nsIURI> url;
    110  rv = NS_MutateURI(new nsSimpleURI::Mutator()).SetSpec(aSpec).Finalize(url);
    111 
    112  if (NS_FAILED(rv)) {
    113    return rv;
    114  }
    115 
    116  if (IsSafeToLinkForUntrustedContent(url)) {
    117    // We need to indicate that this baby is safe.  Use an inner URI that
    118    // no one but the security manager will see.  Make sure to preserve our
    119    // path, in case someone decides to hardcode checks for particular
    120    // about: URIs somewhere.
    121    nsAutoCString spec;
    122    rv = url->GetPathQueryRef(spec);
    123    NS_ENSURE_SUCCESS(rv, rv);
    124 
    125    spec.InsertLiteral("moz-safe-about:", 0);
    126 
    127    nsCOMPtr<nsIURI> inner;
    128    rv = NS_NewURI(getter_AddRefs(inner), spec);
    129    NS_ENSURE_SUCCESS(rv, rv);
    130 
    131    rv = NS_MutateURI(new nsNestedAboutURI::Mutator())
    132             .Apply(&nsINestedAboutURIMutator::InitWithBase, inner, aBaseURI)
    133             .SetSpec(aSpec)
    134             .Finalize(url);
    135    NS_ENSURE_SUCCESS(rv, rv);
    136  }
    137 
    138  url.swap(*aResult);
    139  return NS_OK;
    140 }
    141 
    142 NS_IMETHODIMP
    143 nsAboutProtocolHandler::NewChannel(nsIURI* uri, nsILoadInfo* aLoadInfo,
    144                                   nsIChannel** result) {
    145  NS_ENSURE_ARG_POINTER(uri);
    146 
    147  // about:what you ask?
    148  nsCOMPtr<nsIAboutModule> aboutMod;
    149  nsresult rv = NS_GetAboutModule(uri, getter_AddRefs(aboutMod));
    150 
    151  nsAutoCString path;
    152  if (NS_SUCCEEDED(NS_GetAboutModuleName(uri, path)) &&
    153      path.EqualsLiteral("srcdoc")) {
    154    // about:srcdoc is meant to be unresolvable, yet is included in the
    155    // about lookup tables so that it can pass security checks when used in
    156    // a srcdoc iframe.  To ensure that it stays unresolvable, we pretend
    157    // that it doesn't exist.
    158    return NS_ERROR_MALFORMED_URI;
    159  }
    160 
    161  if (NS_FAILED(rv)) {
    162    if (rv == NS_ERROR_FACTORY_NOT_REGISTERED) {
    163      // This looks like an about: we don't know about.  Convert
    164      // this to an invalid URI error.
    165      return NS_ERROR_MALFORMED_URI;
    166    }
    167 
    168    return rv;
    169  }
    170 
    171  uint32_t flags = 0;
    172  if (NS_FAILED(aboutMod->GetURIFlags(uri, &flags))) {
    173    return NS_ERROR_FAILURE;
    174  }
    175 
    176  bool safeForUntrustedContent =
    177      (flags & nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT) != 0;
    178 
    179  MOZ_DIAGNOSTIC_ASSERT(
    180      safeForUntrustedContent ||
    181          (flags & (nsIAboutModule::URI_CAN_LOAD_IN_CHILD |
    182                    nsIAboutModule::URI_MUST_LOAD_IN_CHILD)) == 0,
    183      "Only unprivileged content should be loaded in child processes. (Did "
    184      "you forget to add URI_SAFE_FOR_UNTRUSTED_CONTENT to your about: "
    185      "page?)");
    186 
    187  // The standard return case:
    188  rv = aboutMod->NewChannel(uri, aLoadInfo, result);
    189  if (NS_FAILED(rv)) {
    190    if (rv == NS_ERROR_FACTORY_NOT_REGISTERED) {
    191      // This looks like an about: we don't know about.  Convert
    192      // this to an invalid URI error.
    193      return NS_ERROR_MALFORMED_URI;
    194    }
    195 
    196    return rv;
    197  }
    198 
    199  // Not all implementations of nsIAboutModule::NewChannel()
    200  // set the LoadInfo on the newly created channel yet, as
    201  // an interim solution we set the LoadInfo here if not
    202  // available on the channel. Bug 1087720
    203  nsCOMPtr<nsILoadInfo> loadInfo = (*result)->LoadInfo();
    204  if (aLoadInfo != loadInfo) {
    205    NS_ASSERTION(false,
    206                 "nsIAboutModule->newChannel(aURI, aLoadInfo) needs to "
    207                 "set LoadInfo");
    208    AutoTArray<nsString, 2> params = {
    209        u"nsIAboutModule->newChannel(aURI)"_ns,
    210        u"nsIAboutModule->newChannel(aURI, aLoadInfo)"_ns};
    211    nsContentUtils::ReportToConsole(
    212        nsIScriptError::warningFlag, "Security by Default"_ns,
    213        nullptr,  // aDocument
    214        nsContentUtils::eNECKO_PROPERTIES, "APIDeprecationWarning", params);
    215    (*result)->SetLoadInfo(aLoadInfo);
    216  }
    217 
    218  // If this URI is safe for untrusted content, enforce that its
    219  // principal be based on the channel's originalURI by setting the
    220  // owner to null.
    221  // Note: this relies on aboutMod's newChannel implementation
    222  // having set the proper originalURI, which probably isn't ideal.
    223  if (safeForUntrustedContent) {
    224    (*result)->SetOwner(nullptr);
    225  }
    226 
    227  RefPtr<nsNestedAboutURI> aboutURI;
    228  if (NS_SUCCEEDED(
    229          uri->QueryInterface(kNestedAboutURICID, getter_AddRefs(aboutURI))) &&
    230      aboutURI->GetBaseURI()) {
    231    nsCOMPtr<nsIWritablePropertyBag2> writableBag = do_QueryInterface(*result);
    232    if (writableBag) {
    233      writableBag->SetPropertyAsInterface(u"baseURI"_ns,
    234                                          aboutURI->GetBaseURI());
    235    }
    236  }
    237 
    238  return NS_OK;
    239 }
    240 
    241 NS_IMETHODIMP
    242 nsAboutProtocolHandler::AllowPort(int32_t port, const char* scheme,
    243                                  bool* _retval) {
    244  // don't override anything.
    245  *_retval = false;
    246  return NS_OK;
    247 }
    248 
    249 ////////////////////////////////////////////////////////////////////////////////
    250 // Safe about protocol handler impl
    251 
    252 NS_IMPL_ISUPPORTS(nsSafeAboutProtocolHandler, nsIProtocolHandler,
    253                  nsISupportsWeakReference)
    254 
    255 // nsIProtocolHandler methods:
    256 
    257 NS_IMETHODIMP
    258 nsSafeAboutProtocolHandler::GetScheme(nsACString& result) {
    259  result.AssignLiteral("moz-safe-about");
    260  return NS_OK;
    261 }
    262 
    263 NS_IMETHODIMP
    264 nsSafeAboutProtocolHandler::NewChannel(nsIURI* uri, nsILoadInfo* aLoadInfo,
    265                                       nsIChannel** result) {
    266  *result = nullptr;
    267  return NS_ERROR_NOT_AVAILABLE;
    268 }
    269 
    270 NS_IMETHODIMP
    271 nsSafeAboutProtocolHandler::AllowPort(int32_t port, const char* scheme,
    272                                      bool* _retval) {
    273  // don't override anything.
    274  *_retval = false;
    275  return NS_OK;
    276 }
    277 
    278 ////////////////////////////////////////////////////////////
    279 // nsNestedAboutURI implementation
    280 
    281 NS_IMPL_CLASSINFO(nsNestedAboutURI, nullptr, nsIClassInfo::THREADSAFE,
    282                  NS_NESTEDABOUTURI_CID);
    283 // Empty CI getter. We only need nsIClassInfo for Serialization
    284 NS_IMPL_CI_INTERFACE_GETTER0(nsNestedAboutURI)
    285 
    286 NS_INTERFACE_MAP_BEGIN(nsNestedAboutURI)
    287  if (aIID.Equals(kNestedAboutURICID)) {
    288    foundInterface = static_cast<nsIURI*>(this);
    289  } else
    290    NS_IMPL_QUERY_CLASSINFO(nsNestedAboutURI)
    291 NS_INTERFACE_MAP_END_INHERITING(nsSimpleNestedURI)
    292 
    293 // nsISerializable
    294 
    295 NS_IMETHODIMP
    296 nsNestedAboutURI::Read(nsIObjectInputStream* aStream) {
    297  MOZ_ASSERT_UNREACHABLE("Use nsIURIMutator.read() instead");
    298  return NS_ERROR_NOT_IMPLEMENTED;
    299 }
    300 
    301 nsresult nsNestedAboutURI::ReadPrivate(nsIObjectInputStream* aStream) {
    302  nsresult rv = nsSimpleNestedURI::ReadPrivate(aStream);
    303  if (NS_FAILED(rv)) return rv;
    304 
    305  bool haveBase;
    306  rv = aStream->ReadBoolean(&haveBase);
    307  if (NS_FAILED(rv)) return rv;
    308 
    309  if (haveBase) {
    310    nsCOMPtr<nsISupports> supports;
    311    rv = aStream->ReadObject(true, getter_AddRefs(supports));
    312    if (NS_FAILED(rv)) return rv;
    313 
    314    mBaseURI = do_QueryInterface(supports, &rv);
    315    if (NS_FAILED(rv)) return rv;
    316  }
    317 
    318  return NS_OK;
    319 }
    320 
    321 NS_IMETHODIMP
    322 nsNestedAboutURI::Write(nsIObjectOutputStream* aStream) {
    323  nsresult rv = nsSimpleNestedURI::Write(aStream);
    324  if (NS_FAILED(rv)) return rv;
    325 
    326  rv = aStream->WriteBoolean(mBaseURI != nullptr);
    327  if (NS_FAILED(rv)) return rv;
    328 
    329  if (mBaseURI) {
    330    // A previous iteration of this code wrote out mBaseURI as nsISupports
    331    // and then read it in as nsIURI, which is non-kosher when mBaseURI
    332    // implements more than just a single line of interfaces and the
    333    // canonical nsISupports* isn't the one a static_cast<> of mBaseURI
    334    // would produce.  For backwards compatibility with existing
    335    // serializations we continue to write mBaseURI as nsISupports but
    336    // switch to reading it as nsISupports, with a post-read QI to get to
    337    // nsIURI.
    338    rv = aStream->WriteCompoundObject(mBaseURI, NS_GET_IID(nsISupports), true);
    339    if (NS_FAILED(rv)) return rv;
    340  }
    341 
    342  return NS_OK;
    343 }
    344 
    345 NS_IMETHODIMP_(void)
    346 nsNestedAboutURI::Serialize(mozilla::ipc::URIParams& aParams) {
    347  using namespace mozilla::ipc;
    348 
    349  NestedAboutURIParams params;
    350  URIParams nestedParams;
    351 
    352  nsSimpleNestedURI::Serialize(nestedParams);
    353  params.nestedParams() = nestedParams;
    354 
    355  if (mBaseURI) {
    356    SerializeURI(mBaseURI, params.baseURI());
    357  }
    358 
    359  aParams = params;
    360 }
    361 
    362 bool nsNestedAboutURI::Deserialize(const mozilla::ipc::URIParams& aParams) {
    363  using namespace mozilla::ipc;
    364 
    365  if (aParams.type() != URIParams::TNestedAboutURIParams) {
    366    NS_ERROR("Received unknown parameters from the other process!");
    367    return false;
    368  }
    369 
    370  const NestedAboutURIParams& params = aParams.get_NestedAboutURIParams();
    371  if (!nsSimpleNestedURI::Deserialize(params.nestedParams())) {
    372    return false;
    373  }
    374 
    375  mBaseURI = nullptr;
    376  if (params.baseURI()) {
    377    mBaseURI = DeserializeURI(*params.baseURI());
    378  }
    379  return true;
    380 }
    381 
    382 // nsSimpleURI
    383 /* virtual */ already_AddRefed<nsSimpleURI> nsNestedAboutURI::StartClone() {
    384  NS_ENSURE_TRUE(mInnerURI, nullptr);
    385 
    386  RefPtr<nsNestedAboutURI> url = new nsNestedAboutURI(mInnerURI, mBaseURI);
    387 
    388  return url.forget();
    389 }
    390 
    391 // Queries this list of interfaces. If none match, it queries mURI.
    392 NS_IMPL_NSIURIMUTATOR_ISUPPORTS(nsNestedAboutURI::Mutator, nsIURISetters,
    393                                nsIURIMutator, nsISerializable,
    394                                nsINestedAboutURIMutator)
    395 
    396 NS_IMETHODIMP
    397 nsNestedAboutURI::Mutate(nsIURIMutator** aMutator) {
    398  RefPtr<nsNestedAboutURI::Mutator> mutator = new nsNestedAboutURI::Mutator();
    399  nsresult rv = mutator->InitFromURI(this);
    400  if (NS_FAILED(rv)) {
    401    return rv;
    402  }
    403  mutator.forget(aMutator);
    404  return NS_OK;
    405 }
    406 
    407 }  // namespace net
    408 }  // namespace mozilla