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/. */
7 #include "mozilla/dom/CSPEvalChecker.h"
8 #include "mozilla/dom/Document.h"
9 #include "mozilla/dom/WorkerPrivate.h"
10 #include "mozilla/dom/WorkerRunnable.h"
11 #include "mozilla/ErrorResult.h"
12 #include "nsGlobalWindowInner.h"
13 #include "nsContentSecurityUtils.h"
14 #include "nsContentUtils.h"
17 using namespace mozilla
;
18 using namespace mozilla::dom
;
22 // We use the subjectPrincipal to assert that eval() is never
23 // executed in system privileged context.
24 nsresult
CheckInternal(nsIContentSecurityPolicy
* aCSP
,
25 nsICSPEventListener
* aCSPEventListener
,
26 nsIPrincipal
* aSubjectPrincipal
,
27 const nsAString
& aExpression
,
28 const JSCallingLocation
& aCaller
, bool* aAllowed
) {
29 MOZ_ASSERT(NS_IsMainThread());
32 // The value is set at any "return", but better to have a default value here.
35 // This is the non-CSP check for gating eval() use in the SystemPrincipal
37 JSContext
* cx
= nsContentUtils::GetCurrentJSContext();
38 if (!nsContentSecurityUtils::IsEvalAllowed(
39 cx
, aSubjectPrincipal
->IsSystemPrincipal(), aExpression
)) {
50 bool reportViolation
= false;
51 nsresult rv
= aCSP
->GetAllowsEval(&reportViolation
, aAllowed
);
52 if (NS_WARN_IF(NS_FAILED(rv
))) {
57 if (reportViolation
) {
58 aCSP
->LogViolationDetails(nsIContentSecurityPolicy::VIOLATION_TYPE_EVAL
,
59 nullptr, // triggering element
60 aCSPEventListener
, aCaller
.FileName(),
61 aExpression
, aCaller
.mLine
, aCaller
.mColumn
,
68 class WorkerCSPCheckRunnable final
: public WorkerMainThreadRunnable
{
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) {}
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
);
88 nsresult
GetResult(bool* aAllowed
) {
90 *aAllowed
= mEvalAllowed
;
95 const nsString mExpression
;
96 const JSCallingLocation mCaller
;
104 nsresult
CSPEvalChecker::CheckForWindow(JSContext
* aCx
,
105 nsGlobalWindowInner
* aWindow
,
106 const nsAString
& aExpression
,
108 MOZ_ASSERT(NS_IsMainThread());
110 MOZ_ASSERT(aAllowEval
);
112 // The value is set at any "return", but better to have a default value here.
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();
119 // if there's no document, we don't have to do anything.
126 auto location
= JSCallingLocation::Get(aCx
);
127 nsCOMPtr
<nsIContentSecurityPolicy
> csp
= doc
->GetCsp();
128 rv
= CheckInternal(csp
, nullptr /* no CSPEventListener for window */,
129 doc
->NodePrincipal(), aExpression
, location
, aAllowEval
);
130 if (NS_WARN_IF(NS_FAILED(rv
))) {
139 nsresult
CSPEvalChecker::CheckForWorker(JSContext
* aCx
,
140 WorkerPrivate
* aWorkerPrivate
,
141 const nsAString
& aExpression
,
143 MOZ_ASSERT(aWorkerPrivate
);
144 aWorkerPrivate
->AssertIsOnWorkerThread();
145 MOZ_ASSERT(aAllowEval
);
147 // The value is set at any "return", but better to have a default value here.
150 RefPtr
<WorkerCSPCheckRunnable
> r
= new WorkerCSPCheckRunnable(
151 aWorkerPrivate
, aExpression
, JSCallingLocation::Get(aCx
));
153 r
->Dispatch(aWorkerPrivate
, Canceling
, error
);
154 if (NS_WARN_IF(error
.Failed())) {
156 return error
.StealNSResult();
159 nsresult rv
= r
->GetResult(aAllowEval
);
160 if (NS_WARN_IF(NS_FAILED(rv
))) {