Bug 1740263 - Implement the CSP checking callback for WASM. r=dom-worker-reviewers,smaug,freddyb

Differential Revision: https://phabricator.services.mozilla.com/D141979
This commit is contained in:
Tom Schuster 2022-05-19 14:13:50 +00:00
Родитель 77f02a9675
Коммит 4525afaf9f
13 изменённых файлов: 124 добавлений и 114 удалений

Просмотреть файл

@ -448,7 +448,7 @@ NS_IMPL_ISUPPORTS(nsScriptSecurityManager, nsIScriptSecurityManager)
///////////////// Security Checks /////////////////
bool nsScriptSecurityManager::ContentSecurityPolicyPermitsJSAction(
JSContext* cx, JS::HandleString aCode) {
JSContext* cx, JS::RuntimeCode aKind, JS::Handle<JSString*> aCode) {
MOZ_ASSERT(cx == nsContentUtils::GetCurrentJSContext());
// Get the window, if any, corresponding to the current global
@ -484,30 +484,37 @@ bool nsScriptSecurityManager::ContentSecurityPolicyPermitsJSAction(
bool evalOK = true;
bool reportViolation = false;
nsresult rv = csp->GetAllowsEval(&reportViolation, &evalOK);
// A little convoluted. We want the scriptSample for a) reporting a violation
// or b) passing it to AssertEvalNotUsingSystemPrincipal or c) we're in the
// parent process. So do the work to get it if either of those cases is true.
nsAutoJSString scriptSample;
if (reportViolation || subjectPrincipal->IsSystemPrincipal() ||
XRE_IsE10sParentProcess()) {
if (NS_WARN_IF(!scriptSample.init(cx, aCode))) {
JS_ClearPendingException(cx);
return false;
if (aKind == JS::RuntimeCode::JS) {
nsresult rv = csp->GetAllowsEval(&reportViolation, &evalOK);
// A little convoluted. We want the scriptSample for a) reporting a
// violation or b) passing it to AssertEvalNotUsingSystemPrincipal or c)
// we're in the parent process. So do the work to get it if either of those
// cases is true.
if (reportViolation || subjectPrincipal->IsSystemPrincipal() ||
XRE_IsE10sParentProcess()) {
if (NS_WARN_IF(!scriptSample.init(cx, aCode))) {
JS_ClearPendingException(cx);
return false;
}
}
}
#if !defined(ANDROID)
if (!nsContentSecurityUtils::IsEvalAllowed(
cx, subjectPrincipal->IsSystemPrincipal(), scriptSample)) {
return false;
}
if (!nsContentSecurityUtils::IsEvalAllowed(
cx, subjectPrincipal->IsSystemPrincipal(), scriptSample)) {
return false;
}
#endif
if (NS_FAILED(rv)) {
NS_WARNING("CSP: failed to get allowsEval");
return true; // fail open to not break sites.
if (NS_FAILED(rv)) {
NS_WARNING("CSP: failed to get allowsEval");
return true; // fail open to not break sites.
}
} else {
if (NS_FAILED(csp->GetAllowsWasmEval(&reportViolation, &evalOK))) {
return false;
}
}
if (reportViolation) {
@ -522,7 +529,12 @@ bool nsScriptSecurityManager::ContentSecurityPolicyPermitsJSAction(
} else {
MOZ_ASSERT(!JS_IsExceptionPending(cx));
}
csp->LogViolationDetails(nsIContentSecurityPolicy::VIOLATION_TYPE_EVAL,
uint16_t violationType =
aKind == JS::RuntimeCode::JS
? nsIContentSecurityPolicy::VIOLATION_TYPE_EVAL
: nsIContentSecurityPolicy::VIOLATION_TYPE_WASM_EVAL;
csp->LogViolationDetails(violationType,
nullptr, // triggering element
cspEventListener, fileName, scriptSample, lineNum,
columnNum, u""_ns, u""_ns);

Просмотреть файл

@ -27,6 +27,10 @@ class OriginAttributes;
class SystemPrincipal;
} // namespace mozilla
namespace JS {
enum class RuntimeCode;
} // namespace JS
/////////////////////////////
// nsScriptSecurityManager //
/////////////////////////////
@ -90,7 +94,8 @@ class nsScriptSecurityManager final : public nsIScriptSecurityManager {
// Decides, based on CSP, whether or not eval() and stuff can be executed.
static bool ContentSecurityPolicyPermitsJSAction(JSContext* cx,
JS::HandleString aCode);
JS::RuntimeCode kind,
JS::Handle<JSString*> aCode);
static bool JSPrincipalsSubsume(JSPrincipals* first, JSPrincipals* second);

Просмотреть файл

@ -1759,7 +1759,9 @@ nsresult ServiceWorkerPrivate::SpawnWorkerIfNeeded(WakeUpReason aWhy,
// Default CSP permissions for now. These will be overrided if necessary
// based on the script CSP headers during load in ScriptLoader.
info.mEvalAllowed = true;
info.mReportCSPViolations = false;
info.mReportEvalCSPViolations = false;
info.mWasmEvalAllowed = true;
info.mReportWasmEvalCSPViolations = false;
WorkerPrivate::OverrideLoadInfoLoadGroup(info, info.mPrincipal);

Просмотреть файл

@ -448,17 +448,20 @@ bool InterruptCallback(JSContext* aCx) {
}
class LogViolationDetailsRunnable final : public WorkerMainThreadRunnable {
uint16_t mViolationType;
nsString mFileName;
uint32_t mLineNum;
uint32_t mColumnNum;
nsString mScriptSample;
public:
LogViolationDetailsRunnable(WorkerPrivate* aWorker, const nsString& aFileName,
uint32_t aLineNum, uint32_t aColumnNum,
LogViolationDetailsRunnable(WorkerPrivate* aWorker, uint16_t aViolationType,
const nsString& aFileName, uint32_t aLineNum,
uint32_t aColumnNum,
const nsAString& aScriptSample)
: WorkerMainThreadRunnable(aWorker,
"RuntimeService :: LogViolationDetails"_ns),
mViolationType(aViolationType),
mFileName(aFileName),
mLineNum(aLineNum),
mColumnNum(aColumnNum),
@ -472,22 +475,36 @@ class LogViolationDetailsRunnable final : public WorkerMainThreadRunnable {
~LogViolationDetailsRunnable() = default;
};
bool ContentSecurityPolicyAllows(JSContext* aCx, JS::Handle<JSString*> aCode) {
bool ContentSecurityPolicyAllows(JSContext* aCx, JS::RuntimeCode aKind,
JS::Handle<JSString*> aCode) {
WorkerPrivate* worker = GetWorkerPrivateFromContext(aCx);
worker->AssertIsOnWorkerThread();
bool evalOK;
bool reportViolation;
uint16_t violationType;
nsAutoJSString scriptSample;
if (NS_WARN_IF(!scriptSample.init(aCx, aCode))) {
JS_ClearPendingException(aCx);
return false;
if (aKind == JS::RuntimeCode::JS) {
if (NS_WARN_IF(!scriptSample.init(aCx, aCode))) {
JS_ClearPendingException(aCx);
return false;
}
if (!nsContentSecurityUtils::IsEvalAllowed(
aCx, worker->UsesSystemPrincipal(), scriptSample)) {
return false;
}
evalOK = worker->IsEvalAllowed();
reportViolation = worker->GetReportEvalCSPViolations();
violationType = nsIContentSecurityPolicy::VIOLATION_TYPE_EVAL;
} else {
evalOK = worker->IsWasmEvalAllowed();
reportViolation = worker->GetReportWasmEvalCSPViolations();
violationType = nsIContentSecurityPolicy::VIOLATION_TYPE_WASM_EVAL;
}
if (!nsContentSecurityUtils::IsEvalAllowed(aCx, worker->UsesSystemPrincipal(),
scriptSample)) {
return false;
}
if (worker->GetReportCSPViolations()) {
if (reportViolation) {
nsString fileName;
uint32_t lineNum = 0;
uint32_t columnNum = 0;
@ -501,8 +518,8 @@ bool ContentSecurityPolicyAllows(JSContext* aCx, JS::Handle<JSString*> aCode) {
}
RefPtr<LogViolationDetailsRunnable> runnable =
new LogViolationDetailsRunnable(worker, fileName, lineNum, columnNum,
scriptSample);
new LogViolationDetailsRunnable(worker, violationType, fileName,
lineNum, columnNum, scriptSample);
ErrorResult rv;
runnable->Dispatch(Killing, rv);
@ -511,7 +528,7 @@ bool ContentSecurityPolicyAllows(JSContext* aCx, JS::Handle<JSString*> aCode) {
}
}
return worker->IsEvalAllowed();
return evalOK;
}
void CTypesActivityCallback(JSContext* aCx, JS::CTypesActivityType aType) {
@ -1949,13 +1966,11 @@ bool LogViolationDetailsRunnable::MainThreadRun() {
nsIContentSecurityPolicy* csp = mWorkerPrivate->GetCSP();
if (csp) {
if (mWorkerPrivate->GetReportCSPViolations()) {
csp->LogViolationDetails(nsIContentSecurityPolicy::VIOLATION_TYPE_EVAL,
nullptr, // triggering element
mWorkerPrivate->CSPEventListener(), mFileName,
mScriptSample, mLineNum, mColumnNum, u""_ns,
u""_ns);
}
csp->LogViolationDetails(mViolationType,
nullptr, // triggering element
mWorkerPrivate->CSPEventListener(), mFileName,
mScriptSample, mLineNum, mColumnNum, u""_ns,
u""_ns);
}
return true;

Просмотреть файл

@ -90,7 +90,9 @@ WorkerLoadInfoData::WorkerLoadInfoData()
mPrincipalHashValue(0),
mFromWindow(false),
mEvalAllowed(false),
mReportCSPViolations(false),
mReportEvalCSPViolations(false),
mWasmEvalAllowed(false),
mReportWasmEvalCSPViolations(false),
mXHRParamsAllowed(false),
mPrincipalIsSystem(false),
mPrincipalIsAddonOrExpandedAddon(false),
@ -118,7 +120,8 @@ nsresult WorkerLoadInfo::SetPrincipalsAndCSPOnMainThread(
mCSP = aCsp;
if (mCSP) {
mCSP->GetAllowsEval(&mReportCSPViolations, &mEvalAllowed);
mCSP->GetAllowsEval(&mReportEvalCSPViolations, &mEvalAllowed);
mCSP->GetAllowsWasmEval(&mReportWasmEvalCSPViolations, &mWasmEvalAllowed);
mCSPInfo = MakeUnique<CSPInfo>();
nsresult rv = CSPToCSPInfo(aCsp, mCSPInfo.get());
if (NS_WARN_IF(NS_FAILED(rv))) {
@ -126,7 +129,9 @@ nsresult WorkerLoadInfo::SetPrincipalsAndCSPOnMainThread(
}
} else {
mEvalAllowed = true;
mReportCSPViolations = false;
mReportEvalCSPViolations = false;
mWasmEvalAllowed = true;
mReportWasmEvalCSPViolations = false;
}
mLoadGroup = aLoadGroup;

Просмотреть файл

@ -134,7 +134,9 @@ struct WorkerLoadInfoData {
OriginTrials mTrials;
bool mFromWindow;
bool mEvalAllowed;
bool mReportCSPViolations;
bool mReportEvalCSPViolations;
bool mWasmEvalAllowed;
bool mReportWasmEvalCSPViolations;
bool mXHRParamsAllowed;
bool mPrincipalIsSystem;
bool mPrincipalIsAddonOrExpandedAddon;

Просмотреть файл

@ -1419,15 +1419,25 @@ nsresult WorkerPrivate::SetCSPFromHeaderValues(
NS_ENSURE_SUCCESS(rv, rv);
}
mLoadInfo.mCSP = csp;
// Set evalAllowed, default value is set in GetAllowsEval
bool evalAllowed = false;
bool reportEvalViolations = false;
rv = csp->GetAllowsEval(&reportEvalViolations, &evalAllowed);
NS_ENSURE_SUCCESS(rv, rv);
mLoadInfo.mCSP = csp;
mLoadInfo.mEvalAllowed = evalAllowed;
mLoadInfo.mReportCSPViolations = reportEvalViolations;
mLoadInfo.mReportEvalCSPViolations = reportEvalViolations;
// Set wasmEvalAllowed
bool wasmEvalAllowed = false;
bool reportWasmEvalViolations = false;
rv = csp->GetAllowsWasmEval(&reportWasmEvalViolations, &wasmEvalAllowed);
NS_ENSURE_SUCCESS(rv, rv);
mLoadInfo.mWasmEvalAllowed = wasmEvalAllowed;
mLoadInfo.mReportWasmEvalCSPViolations = reportWasmEvalViolations;
mLoadInfo.mCSPInfo = MakeUnique<CSPInfo>();
rv = CSPToCSPInfo(csp, mLoadInfo.mCSPInfo.get());

Просмотреть файл

@ -822,14 +822,28 @@ class WorkerPrivate final
bool IsEvalAllowed() const { return mLoadInfo.mEvalAllowed; }
void SetEvalAllowed(bool aEvalAllowed) {
mLoadInfo.mEvalAllowed = aEvalAllowed;
void SetEvalAllowed(bool aAllowed) { mLoadInfo.mEvalAllowed = aAllowed; }
bool GetReportEvalCSPViolations() const {
return mLoadInfo.mReportEvalCSPViolations;
}
bool GetReportCSPViolations() const { return mLoadInfo.mReportCSPViolations; }
void SetReportEvalCSPViolations(bool aReport) {
mLoadInfo.mReportEvalCSPViolations = aReport;
}
void SetReportCSPViolations(bool aReport) {
mLoadInfo.mReportCSPViolations = aReport;
bool IsWasmEvalAllowed() const { return mLoadInfo.mWasmEvalAllowed; }
void SetWasmEvalAllowed(bool aAllowed) {
mLoadInfo.mWasmEvalAllowed = aAllowed;
}
bool GetReportWasmEvalCSPViolations() const {
return mLoadInfo.mReportWasmEvalCSPViolations;
}
void SetReportWasmEvalCSPViolations(bool aReport) {
mLoadInfo.mReportWasmEvalCSPViolations = aReport;
}
bool XHRParamsAllowed() const { return mLoadInfo.mXHRParamsAllowed; }

Просмотреть файл

@ -568,6 +568,7 @@ void CacheLoadHandler::DataReceived() {
// Set Eval and ContentSecurityPolicy
mWorkerPrivate->SetCSP(parent->GetCSP());
mWorkerPrivate->SetEvalAllowed(parent->IsEvalAllowed());
mWorkerPrivate->SetWasmEvalAllowed(parent->IsWasmEvalAllowed());
}
}
}

Просмотреть файл

@ -378,7 +378,9 @@ nsresult RemoteWorkerChild::ExecWorkerOnMainThread(RemoteWorkerData&& aData) {
// Default CSP permissions for now. These will be overrided if necessary
// based on the script CSP headers during load in ScriptLoader.
info.mEvalAllowed = true;
info.mReportCSPViolations = false;
info.mReportEvalCSPViolations = false;
info.mWasmEvalAllowed = true;
info.mReportWasmEvalCSPViolations = false;
info.mSecureContext = aData.isSecureContext()
? WorkerLoadInfo::eSecureContext
: WorkerLoadInfo::eInsecureContext;

Просмотреть файл

@ -1,18 +0,0 @@
[default-src-blocks-wasm.any.serviceworker.html]
[default-src-blocks-wasm]
expected: FAIL
[default-src-blocks-wasm.any.html]
[default-src-blocks-wasm]
expected: FAIL
[default-src-blocks-wasm.any.sharedworker.html]
[default-src-blocks-wasm]
expected: FAIL
[default-src-blocks-wasm.any.worker.html]
[default-src-blocks-wasm]
expected: FAIL

Просмотреть файл

@ -1,18 +0,0 @@
[script-src-blocks-wasm.any.sharedworker.html]
[script-src-blocks-wasm]
expected: FAIL
[script-src-blocks-wasm.any.html]
[script-src-blocks-wasm]
expected: FAIL
[script-src-blocks-wasm.any.worker.html]
[script-src-blocks-wasm]
expected: FAIL
[script-src-blocks-wasm.any.serviceworker.html]
[script-src-blocks-wasm]
expected: FAIL

Просмотреть файл

@ -1,22 +0,0 @@
[script-src-spv-asynch.any.sharedworker.html]
expected: TIMEOUT
[Securitypolicyviolation event looks like it should]
expected: TIMEOUT
[script-src-spv-asynch.any.html]
expected: TIMEOUT
[Securitypolicyviolation event looks like it should]
expected: TIMEOUT
[script-src-spv-asynch.any.serviceworker.html]
expected: TIMEOUT
[Securitypolicyviolation event looks like it should]
expected: TIMEOUT
[script-src-spv-asynch.any.worker.html]
expected: TIMEOUT
[Securitypolicyviolation event looks like it should]
expected: TIMEOUT