tor-browser

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

CSPEvalChecker.cpp (5376B)


      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 "mozilla/dom/CSPEvalChecker.h"
      8 
      9 #include "mozilla/ErrorResult.h"
     10 #include "mozilla/dom/Document.h"
     11 #include "mozilla/dom/PolicyContainer.h"
     12 #include "mozilla/dom/WorkerPrivate.h"
     13 #include "mozilla/dom/WorkerRunnable.h"
     14 #include "nsCOMPtr.h"
     15 #include "nsContentSecurityUtils.h"
     16 #include "nsContentUtils.h"
     17 #include "nsGlobalWindowInner.h"
     18 
     19 using namespace mozilla;
     20 using namespace mozilla::dom;
     21 
     22 namespace {
     23 
     24 // We use the subjectPrincipal to assert that eval() is never
     25 // executed in system privileged context.
     26 nsresult CheckInternal(nsIContentSecurityPolicy* aCSP,
     27                       nsICSPEventListener* aCSPEventListener,
     28                       nsIPrincipal* aSubjectPrincipal,
     29                       const nsAString& aExpression,
     30                       const JSCallingLocation& aCaller, bool* aAllowed) {
     31  MOZ_ASSERT(NS_IsMainThread());
     32  MOZ_ASSERT(aAllowed);
     33 
     34  // The value is set at any "return", but better to have a default value here.
     35  *aAllowed = false;
     36 
     37  // This is the non-CSP check for gating eval() use in the SystemPrincipal
     38  JSContext* cx = nsContentUtils::GetCurrentJSContext();
     39  if (!nsContentSecurityUtils::IsEvalAllowed(
     40          cx, aSubjectPrincipal->IsSystemPrincipal(), aExpression)) {
     41    *aAllowed = false;
     42    return NS_OK;
     43  }
     44 
     45  if (!aCSP) {
     46    *aAllowed = true;
     47    return NS_OK;
     48  }
     49 
     50  bool reportViolation = false;
     51  nsresult rv = aCSP->GetAllowsEval(&reportViolation, aAllowed);
     52  if (NS_WARN_IF(NS_FAILED(rv))) {
     53    *aAllowed = false;
     54    return rv;
     55  }
     56 
     57  if (reportViolation) {
     58    aCSP->LogViolationDetails(nsIContentSecurityPolicy::VIOLATION_TYPE_EVAL,
     59                              nullptr,  // triggering element
     60                              aCSPEventListener, aCaller.FileName(),
     61                              aExpression, aCaller.mLine, aCaller.mColumn,
     62                              u""_ns, u""_ns);
     63  }
     64 
     65  return NS_OK;
     66 }
     67 
     68 class WorkerCSPCheckRunnable final : public WorkerMainThreadRunnable {
     69 public:
     70  WorkerCSPCheckRunnable(WorkerPrivate* aWorkerPrivate,
     71                         const nsAString& aExpression,
     72                         JSCallingLocation&& aCaller)
     73      : WorkerMainThreadRunnable(aWorkerPrivate, "CSP Eval Check"_ns),
     74        mExpression(aExpression),
     75        mCaller(std::move(aCaller)),
     76        mEvalAllowed(false) {}
     77 
     78  bool MainThreadRun() override {
     79    MOZ_ASSERT(mWorkerRef);
     80    WorkerPrivate* workerPrivate = mWorkerRef->Private();
     81    mResult = CheckInternal(workerPrivate->GetCsp(),
     82                            workerPrivate->CSPEventListener(),
     83                            workerPrivate->GetLoadingPrincipal(), mExpression,
     84                            mCaller, &mEvalAllowed);
     85    return true;
     86  }
     87 
     88  nsresult GetResult(bool* aAllowed) {
     89    MOZ_ASSERT(aAllowed);
     90    *aAllowed = mEvalAllowed;
     91    return mResult;
     92  }
     93 
     94 private:
     95  const nsString mExpression;
     96  const JSCallingLocation mCaller;
     97  bool mEvalAllowed;
     98  nsresult mResult;
     99 };
    100 
    101 }  // namespace
    102 
    103 /* static */
    104 nsresult CSPEvalChecker::CheckForWindow(JSContext* aCx,
    105                                        nsGlobalWindowInner* aWindow,
    106                                        const nsAString& aExpression,
    107                                        bool* aAllowEval) {
    108  MOZ_ASSERT(NS_IsMainThread());
    109  MOZ_ASSERT(aWindow);
    110  MOZ_ASSERT(aAllowEval);
    111 
    112  // The value is set at any "return", but better to have a default value here.
    113  *aAllowEval = false;
    114 
    115  // if CSP is enabled, and setTimeout/setInterval was called with a string,
    116  // disable the registration and log an error
    117  nsCOMPtr<Document> doc = aWindow->GetExtantDoc();
    118  if (!doc) {
    119    // if there's no document, we don't have to do anything.
    120    *aAllowEval = true;
    121    return NS_OK;
    122  }
    123 
    124  nsresult rv = NS_OK;
    125 
    126  auto location = JSCallingLocation::Get(aCx);
    127  nsCOMPtr<nsIContentSecurityPolicy> csp =
    128      PolicyContainer::GetCSP(doc->GetPolicyContainer());
    129  rv = CheckInternal(csp, nullptr /* no CSPEventListener for window */,
    130                     doc->NodePrincipal(), aExpression, location, aAllowEval);
    131  if (NS_WARN_IF(NS_FAILED(rv))) {
    132    *aAllowEval = false;
    133    return rv;
    134  }
    135 
    136  return NS_OK;
    137 }
    138 
    139 /* static */
    140 nsresult CSPEvalChecker::CheckForWorker(JSContext* aCx,
    141                                        WorkerPrivate* aWorkerPrivate,
    142                                        const nsAString& aExpression,
    143                                        bool* aAllowEval) {
    144  MOZ_ASSERT(aWorkerPrivate);
    145  aWorkerPrivate->AssertIsOnWorkerThread();
    146  MOZ_ASSERT(aAllowEval);
    147 
    148  // The value is set at any "return", but better to have a default value here.
    149  *aAllowEval = false;
    150 
    151  RefPtr<WorkerCSPCheckRunnable> r = new WorkerCSPCheckRunnable(
    152      aWorkerPrivate, aExpression, JSCallingLocation::Get(aCx));
    153  ErrorResult error;
    154  r->Dispatch(aWorkerPrivate, Canceling, error);
    155  if (NS_WARN_IF(error.Failed())) {
    156    *aAllowEval = false;
    157    return error.StealNSResult();
    158  }
    159 
    160  nsresult rv = r->GetResult(aAllowEval);
    161  if (NS_WARN_IF(NS_FAILED(rv))) {
    162    *aAllowEval = false;
    163    return rv;
    164  }
    165 
    166  return NS_OK;
    167 }