Bug 1406794 - Provide the CSP keywords in both UTF8 and UTF16 forms. r=ckerschb

This avoids the need for numerous 8-to-16-bit and 16-to-8-bit string
conversions.

The patch also introduces a higher-order macro, FOR_EACH_CSP_KEYWORD, which
defines all the stuff about the keywords in a single place and makes the code
nicer.

--HG--
extra : rebase_source : b0f655546aa397749bb18dc7d6d27fbc12fe8fca
This commit is contained in:
Nicholas Nethercote 2017-10-06 16:16:52 +11:00
Родитель 0b432c20bc
Коммит 159f6b5627
4 изменённых файлов: 82 добавлений и 61 удалений

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

@ -552,7 +552,7 @@ nsCSPParser::keywordSource()
return nullptr;
}
mStrictDynamic = true;
return new nsCSPKeywordSrc(CSP_KeywordToEnum(mCurToken));
return new nsCSPKeywordSrc(CSP_UTF16KeywordToEnum(mCurToken));
}
if (CSP_IsKeyword(mCurToken, CSP_UNSAFE_INLINE)) {
@ -571,7 +571,8 @@ nsCSPParser::keywordSource()
}
// cache if we encounter 'unsafe-inline' so we can invalidate (ignore) it in
// case that script-src directive also contains hash- or nonce-.
mUnsafeInlineKeywordSrc = new nsCSPKeywordSrc(CSP_KeywordToEnum(mCurToken));
mUnsafeInlineKeywordSrc =
new nsCSPKeywordSrc(CSP_UTF16KeywordToEnum(mCurToken));
return mUnsafeInlineKeywordSrc;
}
@ -581,7 +582,7 @@ nsCSPParser::keywordSource()
if (doc) {
doc->SetHasUnsafeEvalCSP(true);
}
return new nsCSPKeywordSrc(CSP_KeywordToEnum(mCurToken));
return new nsCSPKeywordSrc(CSP_UTF16KeywordToEnum(mCurToken));
}
return nullptr;
}
@ -665,7 +666,8 @@ nsCSPParser::nonceSource()
NS_ConvertUTF16toUTF8(mCurValue).get()));
// Check if mCurToken begins with "'nonce-" and ends with "'"
if (!StringBeginsWith(mCurToken, NS_ConvertUTF8toUTF16(CSP_EnumToKeyword(CSP_NONCE)),
if (!StringBeginsWith(mCurToken,
nsDependentString(CSP_EnumToUTF16Keyword(CSP_NONCE)),
nsASCIICaseInsensitiveStringComparator()) ||
mCurToken.Last() != SINGLEQUOTE) {
return nullptr;
@ -861,8 +863,7 @@ nsCSPParser::sourceList(nsTArray<nsCSPBaseSrc*>& outSrcs)
}
// Otherwise, we ignore 'none' and report a warning
else {
NS_ConvertUTF8toUTF16 unicodeNone(CSP_EnumToKeyword(CSP_NONE));
const char16_t* params[] = { unicodeNone.get() };
const char16_t* params[] = { CSP_EnumToUTF16Keyword(CSP_NONE) };
logWarningErrorToConsole(nsIScriptError::warningFlag, "ignoringUnknownOption",
params, ArrayLength(params));
}
@ -1252,10 +1253,10 @@ nsCSPParser::directive()
// Even though we invalidate all of the srcs internally, we don't want to log
// messages for the srcs: (1) strict-dynamic, (2) unsafe-inline,
// (3) nonces, and (4) hashes
if (!srcStr.EqualsASCII(CSP_EnumToKeyword(CSP_STRICT_DYNAMIC)) &&
!srcStr.EqualsASCII(CSP_EnumToKeyword(CSP_UNSAFE_EVAL)) &&
!StringBeginsWith(NS_ConvertUTF16toUTF8(srcStr), NS_LITERAL_CSTRING("'nonce-")) &&
!StringBeginsWith(NS_ConvertUTF16toUTF8(srcStr), NS_LITERAL_CSTRING("'sha")))
if (!srcStr.EqualsASCII(CSP_EnumToUTF8Keyword(CSP_STRICT_DYNAMIC)) &&
!srcStr.EqualsASCII(CSP_EnumToUTF8Keyword(CSP_UNSAFE_EVAL)) &&
!StringBeginsWith(srcStr, nsDependentString(CSP_EnumToUTF16Keyword(CSP_NONCE))) &&
!StringBeginsWith(srcStr, NS_LITERAL_STRING("'sha")))
{
const char16_t* params[] = { srcStr.get() };
logWarningErrorToConsole(nsIScriptError::warningFlag, "ignoringSrcForStrictDynamic",

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

@ -322,7 +322,7 @@ CSP_IsDirective(const nsAString& aValue, CSPDirective aDir)
bool
CSP_IsKeyword(const nsAString& aValue, enum CSPKeyword aKey)
{
return aValue.LowerCaseEqualsASCII(CSP_EnumToKeyword(aKey));
return aValue.LowerCaseEqualsASCII(CSP_EnumToUTF8Keyword(aKey));
}
bool
@ -331,14 +331,10 @@ CSP_IsQuotelessKeyword(const nsAString& aKey)
nsString lowerKey = PromiseFlatString(aKey);
ToLowerCase(lowerKey);
static_assert(CSP_LAST_KEYWORD_VALUE ==
(sizeof(CSPStrKeywords) / sizeof(CSPStrKeywords[0])),
"CSP_LAST_KEYWORD_VALUE does not match length of CSPStrKeywords");
nsAutoString keyword;
for (uint32_t i = 0; i < CSP_LAST_KEYWORD_VALUE; i++) {
// skipping the leading ' and trimming the trailing '
keyword.AssignASCII(CSPStrKeywords[i] + 1);
keyword.AssignASCII(gCSPUTF8Keywords[i] + 1);
keyword.Trim("'", false, true);
if (lowerKey.Equals(keyword)) {
return true;
@ -482,7 +478,7 @@ nsCSPBaseSrc::allows(enum CSPKeyword aKeyword, const nsAString& aHashOrNonce,
bool aParserCreated) const
{
CSPUTILSLOG(("nsCSPBaseSrc::allows, aKeyWord: %s, a HashOrNonce: %s",
aKeyword == CSP_HASH ? "hash" : CSP_EnumToKeyword(aKeyword),
aKeyword == CSP_HASH ? "hash" : CSP_EnumToUTF8Keyword(aKeyword),
NS_ConvertUTF16toUTF8(aHashOrNonce).get()));
return false;
}
@ -827,7 +823,7 @@ nsCSPKeywordSrc::allows(enum CSPKeyword aKeyword, const nsAString& aHashOrNonce,
bool aParserCreated) const
{
CSPUTILSLOG(("nsCSPKeywordSrc::allows, aKeyWord: %s, aHashOrNonce: %s, mInvalidated: %s",
CSP_EnumToKeyword(aKeyword),
CSP_EnumToUTF8Keyword(aKeyword),
NS_ConvertUTF16toUTF8(aHashOrNonce).get(),
mInvalidated ? "yes" : "false"));
@ -853,7 +849,7 @@ nsCSPKeywordSrc::visit(nsCSPSrcVisitor* aVisitor) const
void
nsCSPKeywordSrc::toString(nsAString& outStr) const
{
outStr.AppendASCII(CSP_EnumToKeyword(mKeyword));
outStr.Append(CSP_EnumToUTF16Keyword(mKeyword));
}
/* ===== nsCSPNonceSrc ==================== */
@ -886,7 +882,8 @@ nsCSPNonceSrc::allows(enum CSPKeyword aKeyword, const nsAString& aHashOrNonce,
bool aParserCreated) const
{
CSPUTILSLOG(("nsCSPNonceSrc::allows, aKeyWord: %s, a HashOrNonce: %s",
CSP_EnumToKeyword(aKeyword), NS_ConvertUTF16toUTF8(aHashOrNonce).get()));
CSP_EnumToUTF8Keyword(aKeyword),
NS_ConvertUTF16toUTF8(aHashOrNonce).get()));
if (aKeyword != CSP_NONCE) {
return false;
@ -904,7 +901,7 @@ nsCSPNonceSrc::visit(nsCSPSrcVisitor* aVisitor) const
void
nsCSPNonceSrc::toString(nsAString& outStr) const
{
outStr.AppendASCII(CSP_EnumToKeyword(CSP_NONCE));
outStr.Append(CSP_EnumToUTF16Keyword(CSP_NONCE));
outStr.Append(mNonce);
outStr.AppendASCII("'");
}
@ -928,7 +925,8 @@ nsCSPHashSrc::allows(enum CSPKeyword aKeyword, const nsAString& aHashOrNonce,
bool aParserCreated) const
{
CSPUTILSLOG(("nsCSPHashSrc::allows, aKeyWord: %s, a HashOrNonce: %s",
CSP_EnumToKeyword(aKeyword), NS_ConvertUTF16toUTF8(aHashOrNonce).get()));
CSP_EnumToUTF8Keyword(aKeyword),
NS_ConvertUTF16toUTF8(aHashOrNonce).get()));
if (aKeyword != CSP_HASH) {
return false;
@ -1061,7 +1059,8 @@ nsCSPDirective::allows(enum CSPKeyword aKeyword, const nsAString& aHashOrNonce,
bool aParserCreated) const
{
CSPUTILSLOG(("nsCSPDirective::allows, aKeyWord: %s, a HashOrNonce: %s",
CSP_EnumToKeyword(aKeyword), NS_ConvertUTF16toUTF8(aHashOrNonce).get()));
CSP_EnumToUTF8Keyword(aKeyword),
NS_ConvertUTF16toUTF8(aHashOrNonce).get()));
for (uint32_t i = 0; i < mSrcs.Length(); i++) {
if (mSrcs[i]->allows(aKeyword, aHashOrNonce, aParserCreated)) {
@ -1450,7 +1449,8 @@ nsCSPPolicy::allows(nsContentPolicyType aContentType,
bool aParserCreated) const
{
CSPUTILSLOG(("nsCSPPolicy::allows, aKeyWord: %s, a HashOrNonce: %s",
CSP_EnumToKeyword(aKeyword), NS_ConvertUTF16toUTF8(aHashOrNonce).get()));
CSP_EnumToUTF8Keyword(aKeyword),
NS_ConvertUTF16toUTF8(aHashOrNonce).get()));
nsCSPDirective* defaultDir = nullptr;

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

@ -11,6 +11,7 @@
#include "nsIContentPolicy.h"
#include "nsIContentSecurityPolicy.h"
#include "nsIURI.h"
#include "nsLiteralString.h"
#include "nsString.h"
#include "nsTArray.h"
#include "nsUnicharUtils.h"
@ -116,61 +117,81 @@ inline CSPDirective CSP_StringToCSPDirective(const nsAString& aDir)
return nsIContentSecurityPolicy::NO_DIRECTIVE;
}
// Please add any new enum items not only to CSPKeyword, but also add
// a string version for every enum >> using the same index << to
// CSPStrKeywords underneath.
#define FOR_EACH_CSP_KEYWORD(macro) \
macro(CSP_SELF, "'self'") \
macro(CSP_UNSAFE_INLINE, "'unsafe-inline'") \
macro(CSP_UNSAFE_EVAL, "'unsafe-eval'") \
macro(CSP_NONE, "'none'") \
macro(CSP_NONCE, "'nonce-") \
macro(CSP_REQUIRE_SRI_FOR, "require-sri-for") \
macro(CSP_STRICT_DYNAMIC, "'strict-dynamic'")
enum CSPKeyword {
CSP_SELF = 0,
CSP_UNSAFE_INLINE,
CSP_UNSAFE_EVAL,
CSP_NONE,
CSP_NONCE,
CSP_REQUIRE_SRI_FOR,
CSP_STRICT_DYNAMIC,
#define KEYWORD_ENUM(id_, string_) id_,
FOR_EACH_CSP_KEYWORD(KEYWORD_ENUM)
#undef KEYWORD_ENUM
// CSP_LAST_KEYWORD_VALUE always needs to be the last element in the enum
// because we use it to calculate the size for the char* array.
CSP_LAST_KEYWORD_VALUE,
// Putting CSP_HASH after the delimitor, because CSP_HASH is not a valid
// keyword (hash uses e.g. sha256, sha512) but we use CSP_HASH internally
// to identify allowed hashes in ::allows.
CSP_HASH
};
static const char* CSPStrKeywords[] = {
"'self'", // CSP_SELF = 0
"'unsafe-inline'", // CSP_UNSAFE_INLINE
"'unsafe-eval'", // CSP_UNSAFE_EVAL
"'none'", // CSP_NONE
"'nonce-", // CSP_NONCE
"require-sri-for", // CSP_REQUIRE_SRI_FOR
"'strict-dynamic'" // CSP_STRICT_DYNAMIC
// Remember: CSP_HASH is not supposed to be used
// The keywords, in UTF-8 form.
static const char* gCSPUTF8Keywords[] = {
#define KEYWORD_UTF8_LITERAL(id_, string_) string_,
FOR_EACH_CSP_KEYWORD(KEYWORD_UTF8_LITERAL)
#undef KEYWORD_UTF8_LITERAL
};
inline const char* CSP_EnumToKeyword(enum CSPKeyword aKey)
{
// Make sure all elements in enum CSPKeyword got added to CSPStrKeywords.
static_assert((sizeof(CSPStrKeywords) / sizeof(CSPStrKeywords[0]) ==
static_cast<uint32_t>(CSP_LAST_KEYWORD_VALUE)),
"CSP_LAST_KEYWORD_VALUE does not match length of CSPStrKeywords");
// The keywords, in UTF-16 form.
static const char16_t* gCSPUTF16Keywords[] = {
#define KEYWORD_UTF16_LITERAL(id_, string_) u"" string_,
FOR_EACH_CSP_KEYWORD(KEYWORD_UTF16_LITERAL)
#undef KEYWORD_UTF16_LITERAL
};
if (static_cast<uint32_t>(aKey) < static_cast<uint32_t>(CSP_LAST_KEYWORD_VALUE)) {
return CSPStrKeywords[static_cast<uint32_t>(aKey)];
#undef FOR_EACH_CSP_KEYWORD
inline const char* CSP_EnumToUTF8Keyword(enum CSPKeyword aKey)
{
// Make sure all elements in enum CSPKeyword got added to gCSPUTF8Keywords.
static_assert((sizeof(gCSPUTF8Keywords) / sizeof(gCSPUTF8Keywords[0]) ==
CSP_LAST_KEYWORD_VALUE),
"CSP_LAST_KEYWORD_VALUE != length(gCSPUTF8Keywords)");
if (static_cast<uint32_t>(aKey) <
static_cast<uint32_t>(CSP_LAST_KEYWORD_VALUE)) {
return gCSPUTF8Keywords[static_cast<uint32_t>(aKey)];
}
return "error: invalid keyword in CSP_EnumToKeyword";
return "error: invalid keyword in CSP_EnumToUTF8Keyword";
}
inline CSPKeyword CSP_KeywordToEnum(const nsAString& aKey)
inline const char16_t* CSP_EnumToUTF16Keyword(enum CSPKeyword aKey)
{
// Make sure all elements in enum CSPKeyword got added to gCSPUTF16Keywords.
static_assert((sizeof(gCSPUTF16Keywords) / sizeof(gCSPUTF16Keywords[0]) ==
CSP_LAST_KEYWORD_VALUE),
"CSP_LAST_KEYWORD_VALUE != length(gCSPUTF16Keywords)");
if (static_cast<uint32_t>(aKey) <
static_cast<uint32_t>(CSP_LAST_KEYWORD_VALUE)) {
return gCSPUTF16Keywords[static_cast<uint32_t>(aKey)];
}
return u"error: invalid keyword in CSP_EnumToUTF16Keyword";
}
inline CSPKeyword CSP_UTF16KeywordToEnum(const nsAString& aKey)
{
nsString lowerKey = PromiseFlatString(aKey);
ToLowerCase(lowerKey);
static_assert(CSP_LAST_KEYWORD_VALUE ==
(sizeof(CSPStrKeywords) / sizeof(CSPStrKeywords[0])),
"CSP_LAST_KEYWORD_VALUE does not match length of CSPStrKeywords");
for (uint32_t i = 0; i < CSP_LAST_KEYWORD_VALUE; i++) {
if (lowerKey.EqualsASCII(CSPStrKeywords[i])) {
if (lowerKey.Equals(gCSPUTF16Keywords[i])) {
return static_cast<CSPKeyword>(i);
}
}

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

@ -263,9 +263,8 @@ class CSPValidator final : public nsCSPSrcVisitor {
return true;
default:
NS_ConvertASCIItoUTF16 keyword(CSP_EnumToKeyword(src.getKeyword()));
FormatError("csp.error.illegal-keyword", keyword);
FormatError("csp.error.illegal-keyword",
nsDependentString(CSP_EnumToUTF16Keyword(src.getKeyword())));
return false;
}
};