Issue #2402 - Workers.setTimeout/setInterval must handle CSP rejections. https://bugzilla.mozilla.org/show_bug.cgi?id=1490165 Has some namespace issues adding the files, so differs slightly.

This commit is contained in:
Brian Smith 2024-01-08 03:22:44 -06:00 committed by roytam1
commit e74612e23e
10 changed files with 270 additions and 65 deletions

View file

@ -9,6 +9,7 @@
#include "mozilla/Function.h"
#include "mozilla/Likely.h"
#include "mozilla/Maybe.h"
#include "mozilla/dom/CSPEvalChecker.h"
#include "mozilla/dom/FunctionBinding.h"
#include "mozilla/dom/ModuleScript.h"
#include "nsAXPCNativeCallContext.h"
@ -52,7 +53,8 @@ public:
Function& aFunction,
nsTArray<JS::Heap<JS::Value>>&& aArguments);
nsJSScriptTimeoutHandler(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
const nsAString& aExpression);
const nsAString& aExpression, bool* aAllowEval,
ErrorResult& aRv);
virtual const nsAString& GetHandlerText() override;
@ -182,54 +184,6 @@ NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsJSScriptTimeoutHandler)
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsJSScriptTimeoutHandler)
static bool
CheckCSPForEval(JSContext* aCx, nsGlobalWindow* aWindow, ErrorResult& aError)
{
// if CSP is enabled, and setTimeout/setInterval was called with a string,
// disable the registration and log an error
nsCOMPtr<nsIDocument> doc = aWindow->GetExtantDoc();
if (!doc) {
// if there's no document, we don't have to do anything.
return true;
}
nsCOMPtr<nsIContentSecurityPolicy> csp;
aError = doc->NodePrincipal()->GetCsp(getter_AddRefs(csp));
if (aError.Failed()) {
return false;
}
if (!csp) {
return true;
}
bool allowsEval = true;
bool reportViolation = false;
aError = csp->GetAllowsEval(&reportViolation, &allowsEval);
if (aError.Failed()) {
return false;
}
if (reportViolation) {
// TODO : need actual script sample in violation report.
NS_NAMED_LITERAL_STRING(scriptSample,
"call to eval() or related function blocked by CSP");
// Get the calling location.
uint32_t lineNum = 0;
nsAutoString fileNameString;
if (!nsJSUtils::GetCallingLocation(aCx, fileNameString, &lineNum)) {
fileNameString.AssignLiteral("unknown");
}
csp->LogViolationDetails(nsIContentSecurityPolicy::VIOLATION_TYPE_EVAL,
fileNameString, scriptSample, lineNum,
EmptyString(), EmptyString());
}
return allowsEval;
}
nsJSScriptTimeoutHandler::nsJSScriptTimeoutHandler()
: mLineNo(0)
, mColumn(0)
@ -273,8 +227,9 @@ nsJSScriptTimeoutHandler::nsJSScriptTimeoutHandler(JSContext* aCx,
return;
}
*aAllowEval = CheckCSPForEval(aCx, aWindow, aError);
if (aError.Failed() || !*aAllowEval) {
aError = CSPEvalChecker::CheckForWindow(aCx, aWindow, aExpression,
aAllowEval);
if (NS_WARN_IF(aError.Failed()) || !*aAllowEval) {
return;
}
@ -297,7 +252,9 @@ nsJSScriptTimeoutHandler::nsJSScriptTimeoutHandler(JSContext* aCx,
nsJSScriptTimeoutHandler::nsJSScriptTimeoutHandler(JSContext* aCx,
WorkerPrivate* aWorkerPrivate,
const nsAString& aExpression)
const nsAString& aExpression,
bool* aAllowEval,
ErrorResult& aError)
: mLineNo(0)
, mColumn(0)
, mExpr(aExpression)
@ -305,6 +262,12 @@ nsJSScriptTimeoutHandler::nsJSScriptTimeoutHandler(JSContext* aCx,
MOZ_ASSERT(aWorkerPrivate);
aWorkerPrivate->AssertIsOnWorkerThread();
aError = CSPEvalChecker::CheckForWorker(aCx, aWorkerPrivate, aExpression,
aAllowEval);
if (NS_WARN_IF(aError.Failed()) || !*aAllowEval) {
return;
}
Init(aCx);
}
@ -399,9 +362,15 @@ NS_CreateJSTimeoutHandler(JSContext *aCx, WorkerPrivate* aWorkerPrivate,
already_AddRefed<nsIScriptTimeoutHandler>
NS_CreateJSTimeoutHandler(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
const nsAString& aExpression)
const nsAString& aExpression, ErrorResult& aRv)
{
bool allowEval = false;
RefPtr<nsJSScriptTimeoutHandler> handler =
new nsJSScriptTimeoutHandler(aCx, aWorkerPrivate, aExpression);
new nsJSScriptTimeoutHandler(aCx, aWorkerPrivate, aExpression, &allowEval,
aRv);
if (aRv.Failed() || !allowEval) {
return nullptr;
}
return handler.forget();
}