Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/security/CSPEvalChecker.cpp
Line
Count
Source (jump to first uncovered line)
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
#include "mozilla/dom/WorkerPrivate.h"
9
#include "mozilla/dom/WorkerRunnable.h"
10
#include "mozilla/ErrorResult.h"
11
#include "nsGlobalWindowInner.h"
12
#include "nsIDocument.h"
13
#include "nsCOMPtr.h"
14
#include "nsJSUtils.h"
15
16
using namespace mozilla;
17
using namespace mozilla::dom;
18
19
namespace {
20
21
nsresult
22
CheckInternal(nsIContentSecurityPolicy* aCSP,
23
              const nsAString& aExpression,
24
              const nsAString& aFileNameString,
25
              uint32_t aLineNum,
26
              uint32_t aColumnNum,
27
              bool* aAllowed)
28
0
{
29
0
  MOZ_ASSERT(NS_IsMainThread());
30
0
  MOZ_ASSERT(aAllowed);
31
0
32
0
  // The value is set at any "return", but better to have a default value here.
33
0
  *aAllowed = false;
34
0
35
0
  if (!aCSP) {
36
0
    *aAllowed = true;
37
0
    return NS_OK;
38
0
  }
39
0
40
0
  bool reportViolation = false;
41
0
  nsresult rv = aCSP->GetAllowsEval(&reportViolation, aAllowed);
42
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
43
0
    *aAllowed = false;
44
0
    return rv;
45
0
  }
46
0
47
0
  if (reportViolation) {
48
0
    aCSP->LogViolationDetails(nsIContentSecurityPolicy::VIOLATION_TYPE_EVAL,
49
0
                              nullptr, // triggering element
50
0
                              aFileNameString, aExpression, aLineNum,
51
0
                              aColumnNum, EmptyString(), EmptyString());
52
0
  }
53
0
54
0
  return NS_OK;
55
0
}
56
57
class WorkerCSPCheckRunnable final : public WorkerMainThreadRunnable
58
{
59
public:
60
  WorkerCSPCheckRunnable(WorkerPrivate* aWorkerPrivate,
61
                         const nsAString& aExpression,
62
                         const nsAString& aFileNameString,
63
                         uint32_t aLineNum,
64
                         uint32_t aColumnNum)
65
    : WorkerMainThreadRunnable(aWorkerPrivate,
66
                               NS_LITERAL_CSTRING("CSP Eval Check"))
67
    , mExpression(aExpression)
68
    , mFileNameString(aFileNameString)
69
    , mLineNum(aLineNum)
70
    , mColumnNum(aColumnNum)
71
    , mEvalAllowed(false)
72
0
  {}
73
74
  bool
75
  MainThreadRun() override
76
0
  {
77
0
    mResult = CheckInternal(mWorkerPrivate->GetCSP(), mExpression,
78
0
                            mFileNameString, mLineNum, mColumnNum,
79
0
                            &mEvalAllowed);
80
0
    return true;
81
0
  }
82
83
  nsresult
84
  GetResult(bool* aAllowed)
85
0
  {
86
0
    MOZ_ASSERT(aAllowed);
87
0
    *aAllowed = mEvalAllowed;
88
0
    return mResult;
89
0
  }
90
91
private:
92
  const nsString mExpression;
93
  const nsString mFileNameString;
94
  const uint32_t mLineNum;
95
  const uint32_t mColumnNum;
96
  bool mEvalAllowed;
97
  nsresult mResult;
98
};
99
100
} // anonymous
101
102
/* static */ nsresult
103
CSPEvalChecker::CheckForWindow(JSContext* aCx, nsGlobalWindowInner* aWindow,
104
                               const nsAString& aExpression, bool* aAllowEval)
105
0
{
106
0
  MOZ_ASSERT(NS_IsMainThread());
107
0
  MOZ_ASSERT(aWindow);
108
0
  MOZ_ASSERT(aAllowEval);
109
0
110
0
  // The value is set at any "return", but better to have a default value here.
111
0
  *aAllowEval = false;
112
0
113
0
  // if CSP is enabled, and setTimeout/setInterval was called with a string,
114
0
  // disable the registration and log an error
115
0
  nsCOMPtr<nsIDocument> doc = aWindow->GetExtantDoc();
116
0
  if (!doc) {
117
0
    // if there's no document, we don't have to do anything.
118
0
    *aAllowEval = true;
119
0
    return NS_OK;
120
0
  }
121
0
122
0
  nsCOMPtr<nsIContentSecurityPolicy> csp;
123
0
  nsresult rv = doc->NodePrincipal()->GetCsp(getter_AddRefs(csp));
124
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
125
0
    *aAllowEval = false;
126
0
    return rv;
127
0
  }
128
0
129
0
  // Get the calling location.
130
0
  uint32_t lineNum = 0;
131
0
  uint32_t columnNum = 0;
132
0
  nsAutoString fileNameString;
133
0
  if (!nsJSUtils::GetCallingLocation(aCx, fileNameString, &lineNum,
134
0
                                     &columnNum)) {
135
0
    fileNameString.AssignLiteral("unknown");
136
0
  }
137
0
138
0
  rv = CheckInternal(csp, aExpression, fileNameString, lineNum, columnNum,
139
0
                     aAllowEval);
140
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
141
0
    *aAllowEval = false;
142
0
    return rv;
143
0
  }
144
0
145
0
  return NS_OK;
146
0
}
147
148
/* static */ nsresult
149
CSPEvalChecker::CheckForWorker(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
150
                               const nsAString& aExpression, bool* aAllowEval)
151
0
{
152
0
  MOZ_ASSERT(aWorkerPrivate);
153
0
  aWorkerPrivate->AssertIsOnWorkerThread();
154
0
  MOZ_ASSERT(aAllowEval);
155
0
156
0
  // The value is set at any "return", but better to have a default value here.
157
0
  *aAllowEval = false;
158
0
159
0
  // Get the calling location.
160
0
  uint32_t lineNum = 0;
161
0
  uint32_t columnNum = 0;
162
0
  nsAutoString fileNameString;
163
0
  if (!nsJSUtils::GetCallingLocation(aCx, fileNameString, &lineNum,
164
0
                                     &columnNum)) {
165
0
    fileNameString.AssignLiteral("unknown");
166
0
  }
167
0
168
0
  RefPtr<WorkerCSPCheckRunnable> r =
169
0
    new WorkerCSPCheckRunnable(aWorkerPrivate, aExpression, fileNameString,
170
0
                               lineNum, columnNum);
171
0
  ErrorResult error;
172
0
  r->Dispatch(Canceling, error);
173
0
  if (NS_WARN_IF(error.Failed())) {
174
0
    *aAllowEval = false;
175
0
    return error.StealNSResult();
176
0
  }
177
0
178
0
  nsresult rv = r->GetResult(aAllowEval);
179
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
180
0
    *aAllowEval = false;
181
0
    return rv;
182
0
  }
183
0
184
0
  return NS_OK;
185
0
}