blob: c46954787e2f90abb54023d392a39e80279a4ba6 [file] [log] [blame]
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/renderer_host/web_database_host_impl.h"
#include "base/strings/utf_string_conversions.h"
#include "content/browser/child_process_security_policy_impl.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "mojo/core/embedder/embedder.h"
#include "storage/common/database/database_identifier.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace content {
namespace {
base::string16 ConstructVfsFileName(const url::Origin& origin,
const base::string16& name,
const base::string16& suffix) {
std::string identifier = storage::GetIdentifierFromOrigin(origin);
return base::UTF8ToUTF16(identifier) + base::ASCIIToUTF16("/") + name +
base::ASCIIToUTF16("#") + suffix;
}
class BadMessageObserver {
public:
BadMessageObserver()
: dummy_message_(0, 0, 0, 0, nullptr), context_(&dummy_message_) {
mojo::core::SetDefaultProcessErrorCallback(base::BindRepeating(
&BadMessageObserver::ReportBadMessage, base::Unretained(this)));
}
~BadMessageObserver() {
mojo::core::SetDefaultProcessErrorCallback(
mojo::core::ProcessErrorCallback());
}
const std::string& last_error() const { return last_error_; }
private:
void ReportBadMessage(const std::string& error) { last_error_ = error; }
mojo::Message dummy_message_;
mojo::internal::MessageDispatchContext context_;
std::string last_error_;
DISALLOW_COPY_AND_ASSIGN(BadMessageObserver);
};
} // namespace
class WebDatabaseHostImplTest : public ::testing::Test {
protected:
WebDatabaseHostImplTest() = default;
~WebDatabaseHostImplTest() override = default;
void SetUp() override {
scoped_refptr<storage::DatabaseTracker> db_tracker =
base::MakeRefCounted<storage::DatabaseTracker>(
base::FilePath(), /*is_incognito=*/false,
/*special_storage_policy=*/nullptr,
/*quota_manager_proxy=*/nullptr);
db_tracker->set_task_runner_for_testing(
base::ThreadTaskRunnerHandle::Get());
host_ = std::make_unique<WebDatabaseHostImpl>(process_id(),
std::move(db_tracker));
}
template <typename Callable>
void CheckUnauthorizedOrigin(const Callable& func) {
BadMessageObserver bad_message_observer;
func();
EXPECT_EQ("Unauthorized origin.", bad_message_observer.last_error());
}
template <typename Callable>
void CheckInvalidOrigin(const Callable& func) {
BadMessageObserver bad_message_observer;
func();
EXPECT_EQ("Invalid origin.", bad_message_observer.last_error());
}
WebDatabaseHostImpl* host() { return host_.get(); }
int process_id() { return kProcessId; }
private:
static constexpr int kProcessId = 1234;
TestBrowserThreadBundle thread_bundle_;
std::unique_ptr<WebDatabaseHostImpl> host_;
DISALLOW_COPY_AND_ASSIGN(WebDatabaseHostImplTest);
};
TEST_F(WebDatabaseHostImplTest, BadMessagesUnauthorized) {
const url::Origin correct_origin =
url::Origin::Create(GURL("http://correct.com"));
const url::Origin incorrect_origin =
url::Origin::Create(GURL("http://incorrect.net"));
const base::string16 db_name(base::ASCIIToUTF16("db_name"));
const base::string16 suffix(base::ASCIIToUTF16("suffix"));
const base::string16 bad_vfs_file_name =
ConstructVfsFileName(incorrect_origin, db_name, suffix);
auto* security_policy = ChildProcessSecurityPolicyImpl::GetInstance();
security_policy->Add(process_id());
security_policy->AddIsolatedOrigins({correct_origin, incorrect_origin});
security_policy->LockToOrigin(process_id(), correct_origin.GetURL());
ASSERT_TRUE(security_policy->CanAccessDataForOrigin(process_id(),
correct_origin.GetURL()));
ASSERT_FALSE(security_policy->CanAccessDataForOrigin(
process_id(), incorrect_origin.GetURL()));
CheckUnauthorizedOrigin([&]() {
host()->OpenFile(bad_vfs_file_name,
/*desired_flags=*/0, base::BindOnce([](base::File) {}));
});
CheckUnauthorizedOrigin([&]() {
host()->DeleteFile(bad_vfs_file_name,
/*sync_dir=*/false, base::BindOnce([](int32_t) {}));
});
CheckUnauthorizedOrigin([&]() {
host()->GetFileAttributes(bad_vfs_file_name,
base::BindOnce([](int32_t) {}));
});
CheckUnauthorizedOrigin([&]() {
host()->GetFileSize(bad_vfs_file_name, base::BindOnce([](int64_t) {}));
});
CheckUnauthorizedOrigin([&]() {
host()->SetFileSize(bad_vfs_file_name, /*expected_size=*/0,
base::BindOnce([](bool) {}));
});
CheckUnauthorizedOrigin([&]() {
host()->GetSpaceAvailable(incorrect_origin, base::BindOnce([](int64_t) {}));
});
CheckUnauthorizedOrigin([&]() {
host()->Opened(incorrect_origin, db_name, base::ASCIIToUTF16("description"),
/*estimated_size=*/0);
});
CheckUnauthorizedOrigin(
[&]() { host()->Modified(incorrect_origin, db_name); });
CheckUnauthorizedOrigin([&]() { host()->Closed(incorrect_origin, db_name); });
CheckUnauthorizedOrigin([&]() {
host()->HandleSqliteError(incorrect_origin, db_name, /*error=*/0);
});
}
TEST_F(WebDatabaseHostImplTest, BadMessagesInvalid) {
const url::Origin opaque_origin;
const base::string16 db_name(base::ASCIIToUTF16("db_name"));
CheckInvalidOrigin([&]() {
host()->GetSpaceAvailable(opaque_origin, base::BindOnce([](int64_t) {}));
});
CheckInvalidOrigin([&]() {
host()->Opened(opaque_origin, db_name, base::ASCIIToUTF16("description"),
/*estimated_size=*/0);
});
CheckInvalidOrigin([&]() { host()->Modified(opaque_origin, db_name); });
CheckInvalidOrigin([&]() { host()->Closed(opaque_origin, db_name); });
CheckInvalidOrigin([&]() {
host()->HandleSqliteError(opaque_origin, db_name, /*error=*/0);
});
}
} // namespace content