зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
77f02a9675
Коммит
4525afaf9f
|
@ -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
|
Загрузка…
Ссылка в новой задаче