mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
bug 515443 CSP no-eval support. r=mrbkap,brendan
This commit is contained in:
parent
1335f2114e
commit
47a3291b46
@ -431,6 +431,10 @@ private:
|
|||||||
jsval id, JSAccessMode mode,
|
jsval id, JSAccessMode mode,
|
||||||
jsval *vp);
|
jsval *vp);
|
||||||
|
|
||||||
|
// Decides, based on CSP, whether or not eval() and stuff can be executed.
|
||||||
|
static JSBool
|
||||||
|
ContentSecurityPolicyPermitsJSAction(JSContext *cx);
|
||||||
|
|
||||||
// Returns null if a principal cannot be found; generally callers
|
// Returns null if a principal cannot be found; generally callers
|
||||||
// should error out at that point.
|
// should error out at that point.
|
||||||
static nsIPrincipal*
|
static nsIPrincipal*
|
||||||
|
@ -93,6 +93,7 @@
|
|||||||
#include "nsCDefaultURIFixup.h"
|
#include "nsCDefaultURIFixup.h"
|
||||||
#include "nsIChromeRegistry.h"
|
#include "nsIChromeRegistry.h"
|
||||||
#include "nsPrintfCString.h"
|
#include "nsPrintfCString.h"
|
||||||
|
#include "nsIContentSecurityPolicy.h"
|
||||||
|
|
||||||
static NS_DEFINE_CID(kZipReaderCID, NS_ZIPREADER_CID);
|
static NS_DEFINE_CID(kZipReaderCID, NS_ZIPREADER_CID);
|
||||||
|
|
||||||
@ -513,6 +514,50 @@ NS_IMPL_ISUPPORTS5(nsScriptSecurityManager,
|
|||||||
///////////////////////////////////////////////////
|
///////////////////////////////////////////////////
|
||||||
|
|
||||||
///////////////// Security Checks /////////////////
|
///////////////// Security Checks /////////////////
|
||||||
|
JSBool
|
||||||
|
nsScriptSecurityManager::ContentSecurityPolicyPermitsJSAction(JSContext *cx)
|
||||||
|
{
|
||||||
|
// Get the security manager
|
||||||
|
nsScriptSecurityManager *ssm =
|
||||||
|
nsScriptSecurityManager::GetScriptSecurityManager();
|
||||||
|
|
||||||
|
NS_ASSERTION(ssm, "Failed to get security manager service");
|
||||||
|
if (!ssm)
|
||||||
|
return JS_FALSE;
|
||||||
|
|
||||||
|
nsresult rv;
|
||||||
|
nsIPrincipal* subjectPrincipal = ssm->GetSubjectPrincipal(cx, &rv);
|
||||||
|
|
||||||
|
NS_ASSERTION(NS_SUCCEEDED(rv), "CSP: Failed to get nsIPrincipal from js context");
|
||||||
|
if (NS_FAILED(rv))
|
||||||
|
return JS_FALSE; // Not just absence of principal, but failure.
|
||||||
|
|
||||||
|
if (!subjectPrincipal)
|
||||||
|
return JS_FALSE;
|
||||||
|
|
||||||
|
nsCOMPtr<nsIContentSecurityPolicy> csp;
|
||||||
|
rv = subjectPrincipal->GetCsp(getter_AddRefs(csp));
|
||||||
|
NS_ASSERTION(NS_SUCCEEDED(rv), "CSP: Failed to get CSP from principal.");
|
||||||
|
|
||||||
|
// don't do anything unless there's a CSP
|
||||||
|
if (!csp)
|
||||||
|
return JS_TRUE;
|
||||||
|
|
||||||
|
PRBool evalOK = PR_TRUE;
|
||||||
|
// this call will send violation reports as warranted (and return true if
|
||||||
|
// reportOnly is set).
|
||||||
|
rv = csp->GetAllowsEval(&evalOK);
|
||||||
|
|
||||||
|
if (NS_FAILED(rv))
|
||||||
|
{
|
||||||
|
NS_WARNING("CSP: failed to get allowsEval");
|
||||||
|
return JS_TRUE; // fail open to not break sites.
|
||||||
|
}
|
||||||
|
|
||||||
|
return evalOK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
JSBool
|
JSBool
|
||||||
nsScriptSecurityManager::CheckObjectAccess(JSContext *cx, JSObject *obj,
|
nsScriptSecurityManager::CheckObjectAccess(JSContext *cx, JSObject *obj,
|
||||||
jsval id, JSAccessMode mode,
|
jsval id, JSAccessMode mode,
|
||||||
@ -3361,9 +3406,10 @@ nsresult nsScriptSecurityManager::Init()
|
|||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
static JSSecurityCallbacks securityCallbacks = {
|
static JSSecurityCallbacks securityCallbacks = {
|
||||||
CheckObjectAccess,
|
CheckObjectAccess,
|
||||||
NULL,
|
NULL,
|
||||||
NULL
|
NULL,
|
||||||
|
ContentSecurityPolicyPermitsJSAction
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
|
@ -351,6 +351,10 @@ _TEST_FILES = test_bug5141.html \
|
|||||||
test_CSP_inlinescript.html \
|
test_CSP_inlinescript.html \
|
||||||
file_CSP_inlinescript_main.html \
|
file_CSP_inlinescript_main.html \
|
||||||
file_CSP_inlinescript_main.html^headers^ \
|
file_CSP_inlinescript_main.html^headers^ \
|
||||||
|
test_CSP_evalscript.html \
|
||||||
|
file_CSP_evalscript.sjs \
|
||||||
|
file_CSP_evalscript_main.html \
|
||||||
|
file_CSP_evalscript_main.js \
|
||||||
test_bug540854.html \
|
test_bug540854.html \
|
||||||
bug540854.sjs \
|
bug540854.sjs \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
@ -50,6 +50,7 @@
|
|||||||
#include "nsServiceManagerUtils.h"
|
#include "nsServiceManagerUtils.h"
|
||||||
#include "nsDOMError.h"
|
#include "nsDOMError.h"
|
||||||
#include "nsGlobalWindow.h"
|
#include "nsGlobalWindow.h"
|
||||||
|
#include "nsIContentSecurityPolicy.h"
|
||||||
|
|
||||||
static const char kSetIntervalStr[] = "setInterval";
|
static const char kSetIntervalStr[] = "setInterval";
|
||||||
static const char kSetTimeoutStr[] = "setTimeout";
|
static const char kSetTimeoutStr[] = "setTimeout";
|
||||||
@ -203,7 +204,7 @@ nsJSScriptTimeoutHandler::Init(nsGlobalWindow *aWindow, PRBool *aIsInterval,
|
|||||||
JSAutoRequest ar(cx);
|
JSAutoRequest ar(cx);
|
||||||
|
|
||||||
if (argc < 1) {
|
if (argc < 1) {
|
||||||
::JS_ReportError(cx, "Function %s requires at least 1 parameter",
|
::JS_ReportError(cx, "Function %s requires at least 2 parameter",
|
||||||
*aIsInterval ? kSetIntervalStr : kSetTimeoutStr);
|
*aIsInterval ? kSetIntervalStr : kSetTimeoutStr);
|
||||||
return NS_ERROR_DOM_TYPE_ERR;
|
return NS_ERROR_DOM_TYPE_ERR;
|
||||||
}
|
}
|
||||||
@ -243,6 +244,32 @@ nsJSScriptTimeoutHandler::Init(nsGlobalWindow *aWindow, PRBool *aIsInterval,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (expr) {
|
if (expr) {
|
||||||
|
// if CSP is enabled, and setTimeout/setInterval was called with a string
|
||||||
|
// or object, disable the registration and log an error
|
||||||
|
nsCOMPtr<nsIDocument> doc = do_QueryInterface(aWindow->GetExtantDocument());
|
||||||
|
|
||||||
|
if (doc) {
|
||||||
|
nsCOMPtr<nsIContentSecurityPolicy> csp;
|
||||||
|
nsresult rv = doc->NodePrincipal()->GetCsp(getter_AddRefs(csp));
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
if (csp) {
|
||||||
|
PRBool allowsEval;
|
||||||
|
// this call will send violation reports as warranted (and return true if
|
||||||
|
// reportOnly is set).
|
||||||
|
rv = csp->GetAllowsEval(&allowsEval);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
if (!allowsEval) {
|
||||||
|
::JS_ReportError(cx, "call to %s blocked by CSP",
|
||||||
|
*aIsInterval ? kSetIntervalStr : kSetTimeoutStr);
|
||||||
|
|
||||||
|
// Note: Our only caller knows to turn NS_ERROR_DOM_TYPE_ERR into NS_OK.
|
||||||
|
return NS_ERROR_DOM_TYPE_ERR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // if there's no document, we don't have to do anything.
|
||||||
|
|
||||||
rv = NS_HOLD_JS_OBJECTS(this, nsJSScriptTimeoutHandler);
|
rv = NS_HOLD_JS_OBJECTS(this, nsJSScriptTimeoutHandler);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
@ -326,3 +326,4 @@ MSG_DEF(JSMSG_CANT_DEFINE_ARRAY_INDEX,243, 0, JSEXN_TYPEERR, "can't define array
|
|||||||
MSG_DEF(JSMSG_TYPED_ARRAY_BAD_INDEX, 244, 0, JSEXN_ERR, "invalid or out-of-range index")
|
MSG_DEF(JSMSG_TYPED_ARRAY_BAD_INDEX, 244, 0, JSEXN_ERR, "invalid or out-of-range index")
|
||||||
MSG_DEF(JSMSG_TYPED_ARRAY_NEGATIVE_ARG, 245, 1, JSEXN_ERR, "argument {0} must be >= 0")
|
MSG_DEF(JSMSG_TYPED_ARRAY_NEGATIVE_ARG, 245, 1, JSEXN_ERR, "argument {0} must be >= 0")
|
||||||
MSG_DEF(JSMSG_TYPED_ARRAY_BAD_ARGS, 246, 0, JSEXN_ERR, "invalid arguments")
|
MSG_DEF(JSMSG_TYPED_ARRAY_BAD_ARGS, 246, 0, JSEXN_ERR, "invalid arguments")
|
||||||
|
MSG_DEF(JSMSG_CSP_BLOCKED_FUNCTION, 247, 0, JSEXN_ERR, "call to Function() blocked by CSP")
|
||||||
|
@ -2015,9 +2015,10 @@ JS_DropPrincipals(JSContext *cx, JSPrincipals *principals);
|
|||||||
|
|
||||||
|
|
||||||
struct JSSecurityCallbacks {
|
struct JSSecurityCallbacks {
|
||||||
JSCheckAccessOp checkObjectAccess;
|
JSCheckAccessOp checkObjectAccess;
|
||||||
JSPrincipalsTranscoder principalsTranscoder;
|
JSPrincipalsTranscoder principalsTranscoder;
|
||||||
JSObjectPrincipalsFinder findObjectPrincipals;
|
JSObjectPrincipalsFinder findObjectPrincipals;
|
||||||
|
JSCSPEvalChecker contentSecurityPolicyAllows;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern JS_PUBLIC_API(JSSecurityCallbacks *)
|
extern JS_PUBLIC_API(JSSecurityCallbacks *)
|
||||||
|
@ -2218,6 +2218,17 @@ Function(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
|||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* CSP check: whether new Function() is allowed at all.
|
||||||
|
* Report errors via CSP is done in the script security manager.
|
||||||
|
* js_CheckContentSecurityPolicy is defined in jsobj.cpp
|
||||||
|
*/
|
||||||
|
if (!js_CheckContentSecurityPolicy(cx)) {
|
||||||
|
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
||||||
|
JSMSG_CSP_BLOCKED_FUNCTION);
|
||||||
|
return JS_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
n = argc ? argc - 1 : 0;
|
n = argc ? argc - 1 : 0;
|
||||||
if (n > 0) {
|
if (n > 0) {
|
||||||
enum { OK, BAD, BAD_FORMAL } state;
|
enum { OK, BAD, BAD_FORMAL } state;
|
||||||
|
@ -1118,6 +1118,26 @@ Object_p_valueOf(JSContext* cx, JSObject* obj, JSString *hint)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check if CSP allows new Function() or eval() to run in the current
|
||||||
|
* principals.
|
||||||
|
*/
|
||||||
|
JSBool
|
||||||
|
js_CheckContentSecurityPolicy(JSContext *cx)
|
||||||
|
{
|
||||||
|
JSSecurityCallbacks *callbacks;
|
||||||
|
callbacks = JS_GetSecurityCallbacks(cx);
|
||||||
|
|
||||||
|
// if there are callbacks, make sure that the CSP callback is installed and
|
||||||
|
// that it permits eval().
|
||||||
|
if (callbacks) {
|
||||||
|
return callbacks->contentSecurityPolicyAllows &&
|
||||||
|
callbacks->contentSecurityPolicyAllows(cx);
|
||||||
|
}
|
||||||
|
|
||||||
|
return JS_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check whether principals subsumes scopeobj's principals, and return true
|
* Check whether principals subsumes scopeobj's principals, and return true
|
||||||
* if so (or if scopeobj has no principals, for backward compatibility with
|
* if so (or if scopeobj has no principals, for backward compatibility with
|
||||||
@ -1394,6 +1414,13 @@ obj_eval(JSContext *cx, uintN argc, jsval *vp)
|
|||||||
if (!result)
|
if (!result)
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
|
|
||||||
|
// CSP check: is eval() allowed at all?
|
||||||
|
// report errors via CSP is done in the script security mgr.
|
||||||
|
if (!js_CheckContentSecurityPolicy(cx)) {
|
||||||
|
JS_ReportError(cx, "call to eval() blocked by CSP");
|
||||||
|
return JS_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
JSObject *callee = JSVAL_TO_OBJECT(vp[0]);
|
JSObject *callee = JSVAL_TO_OBJECT(vp[0]);
|
||||||
JSPrincipals *principals = js_EvalFramePrincipals(cx, callee, caller);
|
JSPrincipals *principals = js_EvalFramePrincipals(cx, callee, caller);
|
||||||
uintN line;
|
uintN line;
|
||||||
|
@ -1100,6 +1100,10 @@ extern JSBool
|
|||||||
js_CheckPrincipalsAccess(JSContext *cx, JSObject *scopeobj,
|
js_CheckPrincipalsAccess(JSContext *cx, JSObject *scopeobj,
|
||||||
JSPrincipals *principals, JSAtom *caller);
|
JSPrincipals *principals, JSAtom *caller);
|
||||||
|
|
||||||
|
/* For CSP -- checks if eval() and friends are allowed to run. */
|
||||||
|
extern JSBool
|
||||||
|
js_CheckContentSecurityPolicy(JSContext *cx);
|
||||||
|
|
||||||
/* Infallible -- returns its argument if there is no wrapped object. */
|
/* Infallible -- returns its argument if there is no wrapped object. */
|
||||||
extern JSObject *
|
extern JSObject *
|
||||||
js_GetWrappedObject(JSContext *cx, JSObject *obj);
|
js_GetWrappedObject(JSContext *cx, JSObject *obj);
|
||||||
|
@ -584,6 +584,13 @@ typedef JSBool
|
|||||||
typedef JSPrincipals *
|
typedef JSPrincipals *
|
||||||
(* JSObjectPrincipalsFinder)(JSContext *cx, JSObject *obj);
|
(* JSObjectPrincipalsFinder)(JSContext *cx, JSObject *obj);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Used to check if a CSP instance wants to disable eval() and friends.
|
||||||
|
* See js_CheckCSPPermitsJSAction() in jsobj.
|
||||||
|
*/
|
||||||
|
typedef JSBool
|
||||||
|
(* JSCSPEvalChecker)(JSContext *cx);
|
||||||
|
|
||||||
JS_END_EXTERN_C
|
JS_END_EXTERN_C
|
||||||
|
|
||||||
#endif /* jspubtd_h___ */
|
#endif /* jspubtd_h___ */
|
||||||
|
Loading…
Reference in New Issue
Block a user