mirror of
https://bitbucket.org/chromiumembedded/cef
synced 2025-06-05 21:39:12 +02:00
Allow CefV8Context::Eval to bypass CSP (issue #2024)
This commit is contained in:
@@ -291,7 +291,7 @@ PERF_TEST_FUNC(V8ContextEval) {
|
||||
CefRefPtr<CefV8Exception> exception;
|
||||
|
||||
PERF_ITERATIONS_START()
|
||||
context->Eval(jsCode, retval, exception);
|
||||
context->Eval(jsCode, CefString(), 0, retval, exception);
|
||||
PERF_ITERATIONS_END()
|
||||
}
|
||||
|
||||
|
@@ -260,6 +260,20 @@ void TestHandler::OnBeforeClose(CefRefPtr<CefBrowser> browser) {
|
||||
browser_count_--;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
CefResponse::HeaderMap ToCefHeaderMap(
|
||||
const ResourceContent::HeaderMap& headerMap) {
|
||||
CefResponse::HeaderMap result;
|
||||
ResourceContent::HeaderMap::const_iterator it = headerMap.begin();
|
||||
for (; it != headerMap.end(); ++it) {
|
||||
result.insert(std::pair<CefString, CefString>(it->first, it->second));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
CefRefPtr<CefResourceHandler> TestHandler::GetResourceHandler(
|
||||
CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
@@ -280,9 +294,10 @@ CefRefPtr<CefResourceHandler> TestHandler::GetResourceHandler(
|
||||
// Return the previously mapped resource
|
||||
CefRefPtr<CefStreamReader> stream =
|
||||
CefStreamReader::CreateForData(
|
||||
static_cast<void*>(const_cast<char*>(it->second.first.c_str())),
|
||||
it->second.first.length());
|
||||
return new CefStreamResourceHandler(it->second.second, stream);
|
||||
static_cast<void*>(const_cast<char*>(it->second.content().c_str())),
|
||||
it->second.content().length());
|
||||
return new CefStreamResourceHandler(200, "OK", it->second.mimeType(),
|
||||
ToCefHeaderMap(it->second.headerMap()), stream);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -401,10 +416,25 @@ void TestHandler::CloseBrowser(CefRefPtr<CefBrowser> browser,
|
||||
|
||||
void TestHandler::AddResource(const std::string& url,
|
||||
const std::string& content,
|
||||
const std::string& mimeType) {
|
||||
const std::string& mime_type) {
|
||||
ResourceContent::HeaderMap headerMap = ResourceContent::HeaderMap();
|
||||
ResourceContent rc = ResourceContent(content, mime_type, headerMap);
|
||||
AddResourceEx(url, rc);
|
||||
}
|
||||
|
||||
void TestHandler::AddResource(const std::string& url,
|
||||
const std::string& content,
|
||||
const std::string& mime_type,
|
||||
const ResourceContent::HeaderMap& header_map) {
|
||||
ResourceContent rc = ResourceContent(content, mime_type, header_map);
|
||||
AddResourceEx(url, rc);
|
||||
}
|
||||
|
||||
void TestHandler::AddResourceEx(const std::string& url,
|
||||
const ResourceContent& content) {
|
||||
if (!CefCurrentlyOn(TID_IO)) {
|
||||
CefPostTask(TID_IO,
|
||||
base::Bind(&TestHandler::AddResource, this, url, content, mimeType));
|
||||
base::Bind(&TestHandler::AddResourceEx, this, url, content));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -414,8 +444,7 @@ void TestHandler::AddResource(const std::string& url,
|
||||
if (idx > 0)
|
||||
urlStr = urlStr.substr(0, idx);
|
||||
|
||||
resource_map_.insert(
|
||||
std::make_pair(urlStr, std::make_pair(content, mimeType)));
|
||||
resource_map_.insert(std::make_pair(urlStr, content));
|
||||
}
|
||||
|
||||
void TestHandler::ClearResources() {
|
||||
|
@@ -32,6 +32,28 @@ class TrackCallback {
|
||||
bool gotit_;
|
||||
};
|
||||
|
||||
class ResourceContent {
|
||||
public:
|
||||
typedef std::multimap<std::string, std::string> HeaderMap;
|
||||
|
||||
ResourceContent(const std::string& content,
|
||||
const std::string& mime_type,
|
||||
const HeaderMap& header_map)
|
||||
: content_(content),
|
||||
mime_type_(mime_type),
|
||||
header_map_(header_map)
|
||||
{}
|
||||
|
||||
const std::string& content() const { return content_; }
|
||||
const std::string& mimeType() const { return mime_type_; }
|
||||
const HeaderMap& headerMap() const { return header_map_; }
|
||||
|
||||
private:
|
||||
std::string content_;
|
||||
std::string mime_type_;
|
||||
HeaderMap header_map_;
|
||||
};
|
||||
|
||||
|
||||
// Base implementation of CefClient for unit tests. Add new interfaces as needed
|
||||
// by test cases.
|
||||
@@ -235,7 +257,15 @@ class TestHandler : public CefClient,
|
||||
|
||||
void AddResource(const std::string& url,
|
||||
const std::string& content,
|
||||
const std::string& mimeType);
|
||||
const std::string& mime_type);
|
||||
|
||||
void AddResource(const std::string& url,
|
||||
const std::string& content,
|
||||
const std::string& mime_type,
|
||||
const ResourceContent::HeaderMap& header_map);
|
||||
|
||||
void AddResourceEx(const std::string& url, const ResourceContent& content);
|
||||
|
||||
void ClearResources();
|
||||
|
||||
void SetSignalCompletionWhenAllBrowsersClose(bool val) {
|
||||
@@ -274,8 +304,7 @@ class TestHandler : public CefClient,
|
||||
|
||||
// Map of resources that can be automatically loaded. Only accessed on the
|
||||
// IO thread.
|
||||
typedef std::map<std::string, std::pair<std::string, std::string> >
|
||||
ResourceMap;
|
||||
typedef std::map<std::string, ResourceContent > ResourceMap;
|
||||
ResourceMap resource_map_;
|
||||
|
||||
// If true test completion will be signaled when all browsers have closed.
|
||||
|
@@ -31,6 +31,10 @@ const char kV8BindingTestUrl[] = "http://tests/V8Test.BindingTest";
|
||||
const char kV8ContextParentTestUrl[] = "http://tests/V8Test.ContextParentTest";
|
||||
const char kV8ContextChildTestUrl[] = "http://tests/V8Test.ContextChildTest";
|
||||
const char kV8NavTestUrl[] = "http://tests/V8Test.NavTest";
|
||||
const char kV8ContextEvalCspBypassUnsafeEval[] =
|
||||
"http://tests/V8Test.ContextEvalCspBypassUnsafeEval";
|
||||
const char kV8ContextEvalCspBypassSandbox[] =
|
||||
"http://tests/V8Test.ContextEvalCspBypassSandbox";
|
||||
const char kV8OnUncaughtExceptionTestUrl[] =
|
||||
"http://tests/V8Test.OnUncaughtException";
|
||||
const char kV8TestMsg[] = "V8Test.Test";
|
||||
@@ -71,6 +75,8 @@ enum V8TestMode {
|
||||
V8TEST_FUNCTION_HANDLER_EMPTY_STRING,
|
||||
V8TEST_CONTEXT_EVAL,
|
||||
V8TEST_CONTEXT_EVAL_EXCEPTION,
|
||||
V8TEST_CONTEXT_EVAL_CSP_BYPASS_UNSAFE_EVAL,
|
||||
V8TEST_CONTEXT_EVAL_CSP_BYPASS_SANDBOX,
|
||||
V8TEST_CONTEXT_ENTERED,
|
||||
V8TEST_CONTEXT_INVALID,
|
||||
V8TEST_BINDING,
|
||||
@@ -213,6 +219,12 @@ class V8RendererTest : public ClientAppRenderer::Delegate,
|
||||
case V8TEST_CONTEXT_EVAL_EXCEPTION:
|
||||
RunContextEvalExceptionTest();
|
||||
break;
|
||||
case V8TEST_CONTEXT_EVAL_CSP_BYPASS_UNSAFE_EVAL:
|
||||
RunContextEvalCspBypassUnsafeEval();
|
||||
break;
|
||||
case V8TEST_CONTEXT_EVAL_CSP_BYPASS_SANDBOX:
|
||||
RunContextEvalCspBypassSandbox();
|
||||
break;
|
||||
case V8TEST_CONTEXT_ENTERED:
|
||||
RunContextEnteredTest();
|
||||
break;
|
||||
@@ -890,7 +902,7 @@ class V8RendererTest : public ClientAppRenderer::Delegate,
|
||||
CefRefPtr<CefV8Value> retval;
|
||||
CefRefPtr<CefV8Exception> exception;
|
||||
|
||||
EXPECT_TRUE(context->Eval(test.str(), retval, exception));
|
||||
EXPECT_TRUE(context->Eval(test.str(), CefString(), 0, retval, exception));
|
||||
if (exception.get())
|
||||
ADD_FAILURE() << exception->GetMessage().c_str();
|
||||
|
||||
@@ -929,7 +941,7 @@ class V8RendererTest : public ClientAppRenderer::Delegate,
|
||||
CefRefPtr<CefV8Value> retval;
|
||||
CefRefPtr<CefV8Exception> exception;
|
||||
|
||||
EXPECT_TRUE(context->Eval(test.str(), retval, exception));
|
||||
EXPECT_TRUE(context->Eval(test.str(), CefString(), 0, retval, exception));
|
||||
if (exception.get())
|
||||
ADD_FAILURE() << exception->GetMessage().c_str();
|
||||
|
||||
@@ -971,7 +983,7 @@ class V8RendererTest : public ClientAppRenderer::Delegate,
|
||||
CefRefPtr<CefV8Value> retval;
|
||||
CefRefPtr<CefV8Exception> exception;
|
||||
|
||||
EXPECT_TRUE(context->Eval(test.str(), retval, exception));
|
||||
EXPECT_TRUE(context->Eval(test.str(), CefString(), 0, retval, exception));
|
||||
if (exception.get())
|
||||
ADD_FAILURE() << exception->GetMessage().c_str();
|
||||
|
||||
@@ -1013,7 +1025,7 @@ class V8RendererTest : public ClientAppRenderer::Delegate,
|
||||
CefRefPtr<CefV8Value> retval;
|
||||
CefRefPtr<CefV8Exception> exception;
|
||||
|
||||
EXPECT_TRUE(context->Eval(test.str(), retval, exception));
|
||||
EXPECT_TRUE(context->Eval(test.str(), CefString(), 0, retval, exception));
|
||||
if (exception.get())
|
||||
ADD_FAILURE() << exception->GetMessage().c_str();
|
||||
|
||||
@@ -1053,7 +1065,7 @@ class V8RendererTest : public ClientAppRenderer::Delegate,
|
||||
CefRefPtr<CefV8Value> retval;
|
||||
CefRefPtr<CefV8Exception> exception;
|
||||
|
||||
EXPECT_TRUE(context->Eval(test.str(), retval, exception));
|
||||
EXPECT_TRUE(context->Eval(test.str(), CefString(), 0, retval, exception));
|
||||
if (exception.get())
|
||||
ADD_FAILURE() << exception->GetMessage().c_str();
|
||||
|
||||
@@ -1093,7 +1105,7 @@ class V8RendererTest : public ClientAppRenderer::Delegate,
|
||||
CefRefPtr<CefV8Value> retval;
|
||||
CefRefPtr<CefV8Exception> exception;
|
||||
|
||||
EXPECT_TRUE(context->Eval(test.str(), retval, exception));
|
||||
EXPECT_TRUE(context->Eval(test.str(), CefString(), 0, retval, exception));
|
||||
if (exception.get())
|
||||
ADD_FAILURE() << exception->GetMessage().c_str();
|
||||
|
||||
@@ -1514,7 +1526,7 @@ class V8RendererTest : public ClientAppRenderer::Delegate,
|
||||
CefRefPtr<CefV8Value> retval;
|
||||
CefRefPtr<CefV8Exception> exception;
|
||||
|
||||
EXPECT_TRUE(context->Eval("1+2", retval, exception));
|
||||
EXPECT_TRUE(context->Eval("1+2", CefString(), 0, retval, exception));
|
||||
EXPECT_TRUE(retval.get());
|
||||
EXPECT_TRUE(retval->IsInt());
|
||||
EXPECT_EQ(3, retval->GetIntValue());
|
||||
@@ -1529,9 +1541,58 @@ class V8RendererTest : public ClientAppRenderer::Delegate,
|
||||
CefRefPtr<CefV8Value> retval;
|
||||
CefRefPtr<CefV8Exception> exception;
|
||||
|
||||
EXPECT_FALSE(context->Eval("1+foo", retval, exception));
|
||||
EXPECT_FALSE(context->Eval("\n\n\n1+foo", CefString(), 0, retval, exception));
|
||||
EXPECT_FALSE(retval.get());
|
||||
EXPECT_TRUE(exception.get());
|
||||
EXPECT_EQ(4, exception->GetLineNumber());
|
||||
|
||||
DestroyTest();
|
||||
}
|
||||
|
||||
void RunContextEvalCspBypassUnsafeEval() {
|
||||
CefRefPtr<CefV8Context> context = GetContext();
|
||||
|
||||
CefRefPtr<CefV8Value> retval;
|
||||
CefRefPtr<CefV8Exception> exception;
|
||||
|
||||
bool success = context->Eval(
|
||||
"(document.getElementById('result').innerHTML)",
|
||||
CefString(), 0, retval, exception);
|
||||
if (exception.get()) {
|
||||
ADD_FAILURE() << exception->GetMessage().c_str();
|
||||
EXPECT_FALSE(success);
|
||||
}
|
||||
|
||||
EXPECT_TRUE(success);
|
||||
EXPECT_TRUE(retval.get());
|
||||
if (retval.get()) {
|
||||
EXPECT_TRUE(retval->IsString());
|
||||
EXPECT_EQ(CefString("CSP_BYPASSED"), retval->GetStringValue());
|
||||
}
|
||||
|
||||
DestroyTest();
|
||||
}
|
||||
|
||||
void RunContextEvalCspBypassSandbox() {
|
||||
CefRefPtr<CefV8Context> context = GetContext();
|
||||
|
||||
CefRefPtr<CefV8Value> retval;
|
||||
CefRefPtr<CefV8Exception> exception;
|
||||
|
||||
bool success = context->Eval(
|
||||
"(document.getElementById('result').innerHTML)",
|
||||
CefString(), 0, retval, exception);
|
||||
if (exception.get()) {
|
||||
ADD_FAILURE() << exception->GetMessage().c_str();
|
||||
EXPECT_FALSE(success);
|
||||
}
|
||||
|
||||
EXPECT_TRUE(success);
|
||||
EXPECT_TRUE(retval.get());
|
||||
if (retval.get()) {
|
||||
EXPECT_TRUE(retval->IsString());
|
||||
EXPECT_EQ(CefString("CSP_BYPASSED"), retval->GetStringValue());
|
||||
}
|
||||
|
||||
DestroyTest();
|
||||
}
|
||||
@@ -1545,7 +1606,7 @@ class V8RendererTest : public ClientAppRenderer::Delegate,
|
||||
// Test value defined in OnContextCreated
|
||||
EXPECT_TRUE(context->Eval(
|
||||
"document.getElementById('f').contentWindow.v8_context_entered_test()",
|
||||
retval, exception));
|
||||
CefString(), 0, retval, exception));
|
||||
if (exception.get())
|
||||
ADD_FAILURE() << exception->GetMessage().c_str();
|
||||
|
||||
@@ -1624,7 +1685,7 @@ class V8RendererTest : public ClientAppRenderer::Delegate,
|
||||
EXPECT_TRUE(context->Eval(
|
||||
"function jsfunc() { return window.myfunc(); }\n"
|
||||
"jsfunc();",
|
||||
retval, exception));
|
||||
CefString(), 0, retval, exception));
|
||||
EXPECT_TRUE(retval.get());
|
||||
EXPECT_TRUE(retval->IsInt());
|
||||
EXPECT_EQ(3, retval->GetIntValue());
|
||||
@@ -1642,7 +1703,7 @@ class V8RendererTest : public ClientAppRenderer::Delegate,
|
||||
EXPECT_EQ(1, frame->GetLineNumber());
|
||||
EXPECT_EQ(35, frame->GetColumn());
|
||||
EXPECT_TRUE(frame.get());
|
||||
EXPECT_TRUE(frame->IsEval());
|
||||
EXPECT_FALSE(frame->IsEval());
|
||||
EXPECT_FALSE(frame->IsConstructor());
|
||||
|
||||
frame = handler->stack_trace_->GetFrame(1);
|
||||
@@ -1652,7 +1713,7 @@ class V8RendererTest : public ClientAppRenderer::Delegate,
|
||||
EXPECT_EQ(2, frame->GetLineNumber());
|
||||
EXPECT_EQ(1, frame->GetColumn());
|
||||
EXPECT_TRUE(frame.get());
|
||||
EXPECT_TRUE(frame->IsEval());
|
||||
EXPECT_FALSE(frame->IsEval());
|
||||
EXPECT_FALSE(frame->IsConstructor());
|
||||
|
||||
// Exit the V8 context.
|
||||
@@ -1711,6 +1772,10 @@ class V8RendererTest : public ClientAppRenderer::Delegate,
|
||||
}
|
||||
if (test_mode_ > V8TEST_NONE)
|
||||
RunStartupTest();
|
||||
if (test_mode_ == V8TEST_CONTEXT_EVAL_CSP_BYPASS_UNSAFE_EVAL ||
|
||||
test_mode_ == V8TEST_CONTEXT_EVAL_CSP_BYPASS_SANDBOX) {
|
||||
browser_ = browser;
|
||||
}
|
||||
}
|
||||
|
||||
CefRefPtr<CefLoadHandler> GetLoadHandler(
|
||||
@@ -1930,7 +1995,7 @@ class V8RendererTest : public ClientAppRenderer::Delegate,
|
||||
CefRefPtr<CefV8Value> retval;
|
||||
CefRefPtr<CefV8Exception> exception;
|
||||
EXPECT_TRUE(browser->GetMainFrame()->GetV8Context()->Eval(
|
||||
"window.close()", retval, exception));
|
||||
"window.close()", CefString(), 0, retval, exception));
|
||||
}
|
||||
|
||||
protected:
|
||||
@@ -1990,7 +2055,27 @@ class V8TestHandler : public TestHandler {
|
||||
|
||||
void RunTest() override {
|
||||
// Nested script tag forces creation of the V8 context.
|
||||
if (test_mode_ == V8TEST_CONTEXT_ENTERED) {
|
||||
if (test_mode_ == V8TEST_CONTEXT_EVAL_CSP_BYPASS_UNSAFE_EVAL ||
|
||||
test_mode_ == V8TEST_CONTEXT_EVAL_CSP_BYPASS_SANDBOX) {
|
||||
std::string url;
|
||||
ResourceContent::HeaderMap headers;
|
||||
if (test_mode_ == V8TEST_CONTEXT_EVAL_CSP_BYPASS_UNSAFE_EVAL) {
|
||||
url = kV8ContextEvalCspBypassUnsafeEval;
|
||||
headers.insert(std::pair<std::string, std::string>(
|
||||
"Content-Security-Policy", "script-src 'self'"));
|
||||
} else if (test_mode_ == V8TEST_CONTEXT_EVAL_CSP_BYPASS_SANDBOX) {
|
||||
url = kV8ContextEvalCspBypassSandbox;
|
||||
headers.insert(std::pair<std::string, std::string>(
|
||||
"Content-Security-Policy", "sandbox"));
|
||||
} else {
|
||||
NOTREACHED();
|
||||
}
|
||||
AddResource(url, "<html><body>"
|
||||
+ url +
|
||||
"<p id='result' style='display:none'>CSP_BYPASSED</p>"
|
||||
"</body></html>", "text/html", headers);
|
||||
CreateBrowser(test_url_);
|
||||
} else if (test_mode_ == V8TEST_CONTEXT_ENTERED) {
|
||||
AddResource(kV8ContextParentTestUrl, "<html><body>"
|
||||
"<script>var i = 0;</script><iframe src=\"" +
|
||||
std::string(kV8ContextChildTestUrl) + "\" id=\"f\"></iframe></body>"
|
||||
@@ -2161,6 +2246,12 @@ V8_TEST(FunctionHandlerWithContext, V8TEST_FUNCTION_HANDLER_WITH_CONTEXT);
|
||||
V8_TEST(FunctionHandlerEmptyString, V8TEST_FUNCTION_HANDLER_EMPTY_STRING);
|
||||
V8_TEST(ContextEval, V8TEST_CONTEXT_EVAL);
|
||||
V8_TEST(ContextEvalException, V8TEST_CONTEXT_EVAL_EXCEPTION);
|
||||
V8_TEST_EX(ContextEvalCspBypassUnsafeEval,
|
||||
V8TEST_CONTEXT_EVAL_CSP_BYPASS_UNSAFE_EVAL,
|
||||
kV8ContextEvalCspBypassUnsafeEval);
|
||||
V8_TEST_EX(ContextEvalCspBypassSandbox,
|
||||
V8TEST_CONTEXT_EVAL_CSP_BYPASS_SANDBOX,
|
||||
kV8ContextEvalCspBypassSandbox);
|
||||
V8_TEST_EX(ContextEntered, V8TEST_CONTEXT_ENTERED, NULL);
|
||||
V8_TEST(ContextInvalid, V8TEST_CONTEXT_INVALID);
|
||||
V8_TEST_EX(Binding, V8TEST_BINDING, kV8BindingTestUrl);
|
||||
|
Reference in New Issue
Block a user