Bug 1892041 - Part 1: Update test262 features. r=spidermonkey-reviewers,dminor
[gecko.git] / dom / security / CSPEvalChecker.cpp
blob71fa4397ed9b22954018836cd5e56af4bafec5a0
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/BasePrincipal.h"
12 #include "mozilla/ErrorResult.h"
13 #include "nsIParentChannel.h"
14 #include "nsGlobalWindowInner.h"
15 #include "nsContentSecurityUtils.h"
16 #include "nsContentUtils.h"
17 #include "nsCOMPtr.h"
18 #include "nsJSUtils.h"
20 using namespace mozilla;
21 using namespace mozilla::dom;
23 namespace {
25 // We use the subjectPrincipal to assert that eval() is never
26 // executed in system privileged context.
27 nsresult CheckInternal(nsIContentSecurityPolicy* aCSP,
28 nsICSPEventListener* aCSPEventListener,
29 nsIPrincipal* aSubjectPrincipal,
30 const nsAString& aExpression,
31 const nsAString& aFileNameString, uint32_t aLineNum,
32 uint32_t aColumnNum, bool* aAllowed) {
33 MOZ_ASSERT(NS_IsMainThread());
34 MOZ_ASSERT(aAllowed);
36 // The value is set at any "return", but better to have a default value here.
37 *aAllowed = false;
39 // This is the non-CSP check for gating eval() use in the SystemPrincipal
40 #if !defined(ANDROID)
41 JSContext* cx = nsContentUtils::GetCurrentJSContext();
42 if (!nsContentSecurityUtils::IsEvalAllowed(
43 cx, aSubjectPrincipal->IsSystemPrincipal(), aExpression)) {
44 *aAllowed = false;
45 return NS_OK;
47 #endif
49 if (!aCSP) {
50 *aAllowed = true;
51 return NS_OK;
54 bool reportViolation = false;
55 nsresult rv = aCSP->GetAllowsEval(&reportViolation, aAllowed);
56 if (NS_WARN_IF(NS_FAILED(rv))) {
57 *aAllowed = false;
58 return rv;
61 if (reportViolation) {
62 aCSP->LogViolationDetails(nsIContentSecurityPolicy::VIOLATION_TYPE_EVAL,
63 nullptr, // triggering element
64 aCSPEventListener, aFileNameString, aExpression,
65 aLineNum, aColumnNum, u""_ns, u""_ns);
68 return NS_OK;
71 class WorkerCSPCheckRunnable final : public WorkerMainThreadRunnable {
72 public:
73 WorkerCSPCheckRunnable(WorkerPrivate* aWorkerPrivate,
74 const nsAString& aExpression,
75 const nsAString& aFileNameString, uint32_t aLineNum,
76 uint32_t aColumnNum)
77 : WorkerMainThreadRunnable(aWorkerPrivate, "CSP Eval Check"_ns),
78 mExpression(aExpression),
79 mFileNameString(aFileNameString),
80 mLineNum(aLineNum),
81 mColumnNum(aColumnNum),
82 mEvalAllowed(false) {}
84 bool MainThreadRun() override {
85 mResult = CheckInternal(
86 mWorkerPrivate->GetCsp(), mWorkerPrivate->CSPEventListener(),
87 mWorkerPrivate->GetLoadingPrincipal(), mExpression, mFileNameString,
88 mLineNum, mColumnNum, &mEvalAllowed);
89 return true;
92 nsresult GetResult(bool* aAllowed) {
93 MOZ_ASSERT(aAllowed);
94 *aAllowed = mEvalAllowed;
95 return mResult;
98 private:
99 const nsString mExpression;
100 const nsString mFileNameString;
101 const uint32_t mLineNum;
102 const uint32_t mColumnNum;
103 bool mEvalAllowed;
104 nsresult mResult;
107 } // namespace
109 /* static */
110 nsresult CSPEvalChecker::CheckForWindow(JSContext* aCx,
111 nsGlobalWindowInner* aWindow,
112 const nsAString& aExpression,
113 bool* aAllowEval) {
114 MOZ_ASSERT(NS_IsMainThread());
115 MOZ_ASSERT(aWindow);
116 MOZ_ASSERT(aAllowEval);
118 // The value is set at any "return", but better to have a default value here.
119 *aAllowEval = false;
121 // if CSP is enabled, and setTimeout/setInterval was called with a string,
122 // disable the registration and log an error
123 nsCOMPtr<Document> doc = aWindow->GetExtantDoc();
124 if (!doc) {
125 // if there's no document, we don't have to do anything.
126 *aAllowEval = true;
127 return NS_OK;
130 nsresult rv = NS_OK;
132 // Get the calling location.
133 uint32_t lineNum = 0;
134 uint32_t columnNum = 1;
135 nsAutoString fileNameString;
136 if (!nsJSUtils::GetCallingLocation(aCx, fileNameString, &lineNum,
137 &columnNum)) {
138 fileNameString.AssignLiteral("unknown");
141 nsCOMPtr<nsIContentSecurityPolicy> csp = doc->GetCsp();
142 rv = CheckInternal(csp, nullptr /* no CSPEventListener for window */,
143 doc->NodePrincipal(), aExpression, fileNameString, lineNum,
144 columnNum, aAllowEval);
145 if (NS_WARN_IF(NS_FAILED(rv))) {
146 *aAllowEval = false;
147 return rv;
150 return NS_OK;
153 /* static */
154 nsresult CSPEvalChecker::CheckForWorker(JSContext* aCx,
155 WorkerPrivate* aWorkerPrivate,
156 const nsAString& aExpression,
157 bool* aAllowEval) {
158 MOZ_ASSERT(aWorkerPrivate);
159 aWorkerPrivate->AssertIsOnWorkerThread();
160 MOZ_ASSERT(aAllowEval);
162 // The value is set at any "return", but better to have a default value here.
163 *aAllowEval = false;
165 // Get the calling location.
166 uint32_t lineNum = 0;
167 uint32_t columnNum = 1;
168 nsAutoString fileNameString;
169 if (!nsJSUtils::GetCallingLocation(aCx, fileNameString, &lineNum,
170 &columnNum)) {
171 fileNameString.AssignLiteral("unknown");
174 RefPtr<WorkerCSPCheckRunnable> r = new WorkerCSPCheckRunnable(
175 aWorkerPrivate, aExpression, fileNameString, lineNum, columnNum);
176 ErrorResult error;
177 r->Dispatch(Canceling, error);
178 if (NS_WARN_IF(error.Failed())) {
179 *aAllowEval = false;
180 return error.StealNSResult();
183 nsresult rv = r->GetResult(aAllowEval);
184 if (NS_WARN_IF(NS_FAILED(rv))) {
185 *aAllowEval = false;
186 return rv;
189 return NS_OK;