blob: a78c43615a4c7ff3d68b60e3b0865c959f041fa6 [file] [log] [blame]
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/mojo_binder_policy_applier.h"
#include "base/functional/callback.h"
#include "base/memory/weak_ptr.h"
#include "base/test/bind.h"
#include "base/test/task_environment.h"
#include "content/browser/mojo_binder_policy_map_impl.h"
#include "content/public/test/mojo_capability_control_test_interfaces.mojom.h"
#include "mojo/public/cpp/bindings/generic_pending_receiver.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace content {
// A test class that implements test interfaces and provides verification
// methods.
class TestReceiverCollector : public mojom::TestInterfaceForDefer,
public mojom::TestInterfaceForGrant,
public mojom::TestInterfaceForCancel,
public mojom::TestInterfaceForUnexpected {
public:
TestReceiverCollector() = default;
~TestReceiverCollector() override = default;
// Deletes copy and move operations.
TestReceiverCollector(const TestReceiverCollector& other) = delete;
TestReceiverCollector& operator=(const TestReceiverCollector& other) = delete;
TestReceiverCollector(TestReceiverCollector&&) = delete;
TestReceiverCollector& operator=(TestReceiverCollector&&) = delete;
void BindDeferInterface(
mojo::PendingReceiver<mojom::TestInterfaceForDefer> receiver) {
ASSERT_FALSE(defer_receiver_.is_bound());
defer_receiver_.Bind(std::move(receiver));
}
void BindGrantInterface(
mojo::PendingReceiver<mojom::TestInterfaceForGrant> receiver) {
ASSERT_FALSE(grant_receiver_.is_bound());
grant_receiver_.Bind(std::move(receiver));
}
void BindCancelInterface(
mojo::PendingReceiver<mojom::TestInterfaceForCancel> receiver) {
ASSERT_FALSE(cancel_receiver_.is_bound());
cancel_receiver_.Bind(std::move(receiver));
}
void BindUnexpectedInterface(
mojo::PendingReceiver<mojom::TestInterfaceForUnexpected> receiver) {
ASSERT_FALSE(unexpected_receiver_.is_bound());
unexpected_receiver_.Bind(std::move(receiver));
}
// mojom::TestInterfaceForDefer implementation.
void Ping(PingCallback callback) override { NOTREACHED(); }
// Will be called when MojoBinderPolicyApplier::ApplyPolicyToBinder()
// handles a kCancel binding request.
void Cancel(const std::string& interface_name) {
is_cancelled_ = true;
cancelled_interface_ = interface_name;
}
// Used to check if the cancel_closure of MojoBinderPolicyApplier was
// executed.
bool IsCancelled() { return is_cancelled_; }
const std::string& cancelled_interface() const {
return cancelled_interface_;
}
bool IsDeferReceiverBound() const { return defer_receiver_.is_bound(); }
bool IsGrantReceiverBound() const { return grant_receiver_.is_bound(); }
bool IsCancelReceiverBound() const { return cancel_receiver_.is_bound(); }
bool IsUnexpectedReceiverBound() const {
return unexpected_receiver_.is_bound();
}
private:
mojo::Receiver<mojom::TestInterfaceForDefer> defer_receiver_{this};
mojo::Receiver<mojom::TestInterfaceForGrant> grant_receiver_{this};
mojo::Receiver<mojom::TestInterfaceForCancel> cancel_receiver_{this};
mojo::Receiver<mojom::TestInterfaceForUnexpected> unexpected_receiver_{this};
bool is_cancelled_ = false;
std::string cancelled_interface_;
};
class MojoBinderPolicyApplierTest : public testing::Test,
mojom::MojoContextProvider {
public:
MojoBinderPolicyApplierTest() = default;
// mojom::MojoContextProvider
void GrantAll() override { policy_applier_.GrantAll(); }
protected:
std::vector<base::OnceClosure>& deferred_binders() {
return policy_applier_.deferred_binders_;
}
// Calls MojoBinderPolicyApplier::GrantAll() inside a Mojo message dispatch
// stack.
void RunGrantAll() {
DCHECK(!receiver_.is_bound());
receiver_.Bind(remote_.BindNewPipeAndPassReceiver());
remote_->GrantAll();
remote_.FlushForTesting();
}
const MojoBinderPolicyMapImpl policy_map_{
{{"content.mojom.TestInterfaceForDefer",
MojoBinderNonAssociatedPolicy::kDefer},
{"content.mojom.TestInterfaceForGrant",
MojoBinderNonAssociatedPolicy::kGrant},
{"content.mojom.TestInterfaceForCancel",
MojoBinderNonAssociatedPolicy::kCancel},
{"content.mojom.TestInterfaceForUnexpected",
MojoBinderNonAssociatedPolicy::kUnexpected}}};
TestReceiverCollector collector_{};
MojoBinderPolicyApplier policy_applier_{
&policy_map_, base::BindOnce(&TestReceiverCollector::Cancel,
base::Unretained(&collector_))};
private:
base::test::TaskEnvironment task_environment_;
mojo::Remote<mojom::MojoContextProvider> remote_;
mojo::Receiver<mojom::MojoContextProvider> receiver_{this};
};
// Verifies that interfaces whose policies are kGrant can be bound immediately.
TEST_F(MojoBinderPolicyApplierTest, GrantInEnforce) {
// Initialize Mojo interfaces.
mojo::Remote<mojom::TestInterfaceForGrant> grant_remote;
mojo::GenericPendingReceiver grant_receiver(
grant_remote.BindNewPipeAndPassReceiver());
// Bind the interface immediately if the policy is kGrant.
const std::string interface_name = grant_receiver.interface_name().value();
EXPECT_FALSE(collector_.IsCancelled());
EXPECT_FALSE(collector_.IsGrantReceiverBound());
policy_applier_.ApplyPolicyToNonAssociatedBinder(
interface_name,
base::BindOnce(&TestReceiverCollector::BindGrantInterface,
base::Unretained(&collector_),
grant_receiver.As<mojom::TestInterfaceForGrant>()));
EXPECT_TRUE(collector_.IsGrantReceiverBound());
EXPECT_FALSE(collector_.IsCancelled());
}
// Verifies that interfaces whose policies are kDefer cannot be bound until
// GrantAll() is called.
TEST_F(MojoBinderPolicyApplierTest, DeferInEnforce) {
// Initialize Mojo interfaces.
mojo::Remote<mojom::TestInterfaceForDefer> defer_remote;
mojo::GenericPendingReceiver defer_receiver(
defer_remote.BindNewPipeAndPassReceiver());
// Delay binding the interface until GrantAll() is called.
const std::string interface_name = defer_receiver.interface_name().value();
EXPECT_FALSE(collector_.IsCancelled());
policy_applier_.ApplyPolicyToNonAssociatedBinder(
interface_name,
base::BindOnce(&TestReceiverCollector::BindDeferInterface,
base::Unretained(&collector_),
defer_receiver.As<mojom::TestInterfaceForDefer>()));
EXPECT_FALSE(collector_.IsDeferReceiverBound());
EXPECT_EQ(1U, deferred_binders().size());
RunGrantAll();
EXPECT_EQ(0U, deferred_binders().size());
EXPECT_TRUE(collector_.IsDeferReceiverBound());
EXPECT_FALSE(collector_.IsCancelled());
}
// Verifies that MojoBinderPolicyApplier will run `cancel_closure` when running
// in the kEnforce mode and receiving an interface whose policy is kCancel,
TEST_F(MojoBinderPolicyApplierTest, CancelInEnforce) {
// Initialize Mojo interfaces.
mojo::Remote<mojom::TestInterfaceForCancel> cancel_remote;
mojo::GenericPendingReceiver cancel_receiver(
cancel_remote.BindNewPipeAndPassReceiver());
const std::string interface_name = cancel_receiver.interface_name().value();
EXPECT_FALSE(collector_.IsCancelled());
EXPECT_FALSE(collector_.IsCancelReceiverBound());
policy_applier_.ApplyPolicyToNonAssociatedBinder(
interface_name,
base::BindOnce(&TestReceiverCollector::BindCancelInterface,
base::Unretained(&collector_),
cancel_receiver.As<mojom::TestInterfaceForCancel>()));
EXPECT_TRUE(collector_.IsCancelled());
EXPECT_EQ(collector_.cancelled_interface(),
"content.mojom.TestInterfaceForCancel");
EXPECT_FALSE(collector_.IsCancelReceiverBound());
}
// When MojoBinderPolicyApplier runs in the kPrepareToGrantAll mode, verifies it
// applies kGrant for kGrant interfaces.
TEST_F(MojoBinderPolicyApplierTest, GrantInPrepareToGrantAll) {
// Initialize Mojo interfaces.
mojo::Remote<mojom::TestInterfaceForGrant> grant_remote;
mojo::GenericPendingReceiver grant_receiver(
grant_remote.BindNewPipeAndPassReceiver());
policy_applier_.PrepareToGrantAll();
const std::string grant_interface_name =
grant_receiver.interface_name().value();
policy_applier_.ApplyPolicyToNonAssociatedBinder(
grant_interface_name,
base::BindOnce(&TestReceiverCollector::BindGrantInterface,
base::Unretained(&collector_),
grant_receiver.As<mojom::TestInterfaceForGrant>()));
EXPECT_TRUE(collector_.IsGrantReceiverBound());
}
// When MojoBinderPolicyApplier runs in the kPrepareToGrantAll mode, verifies it
// applies kDefer for kDefer interfaces.
TEST_F(MojoBinderPolicyApplierTest, DeferInPrepareToGrantAll) {
// Initialize Mojo interfaces.
mojo::Remote<mojom::TestInterfaceForDefer> defer_remote;
mojo::GenericPendingReceiver defer_receiver(
defer_remote.BindNewPipeAndPassReceiver());
policy_applier_.PrepareToGrantAll();
const std::string defer_interface_name =
defer_receiver.interface_name().value();
policy_applier_.ApplyPolicyToNonAssociatedBinder(
defer_interface_name,
base::BindOnce(&TestReceiverCollector::BindDeferInterface,
base::Unretained(&collector_),
defer_receiver.As<mojom::TestInterfaceForDefer>()));
EXPECT_FALSE(collector_.IsDeferReceiverBound());
EXPECT_EQ(1U, deferred_binders().size());
RunGrantAll();
EXPECT_TRUE(collector_.IsDeferReceiverBound());
EXPECT_EQ(0U, deferred_binders().size());
}
// When MojoBinderPolicyApplier runs in the kPrepareToGrantAll mode, verifies it
// applies kGrant rather than kCancel policy when receiving a kCancel interface
// binding request.
TEST_F(MojoBinderPolicyApplierTest, CancelInPrepareToGrantAll) {
// Initialize Mojo interfaces.
mojo::Remote<mojom::TestInterfaceForCancel> cancel_remote;
mojo::GenericPendingReceiver cancel_receiver(
cancel_remote.BindNewPipeAndPassReceiver());
policy_applier_.PrepareToGrantAll();
const std::string cancel_interface_name =
cancel_receiver.interface_name().value();
policy_applier_.ApplyPolicyToNonAssociatedBinder(
cancel_interface_name,
base::BindOnce(&TestReceiverCollector::BindCancelInterface,
base::Unretained(&collector_),
cancel_receiver.As<mojom::TestInterfaceForCancel>()));
EXPECT_FALSE(collector_.IsCancelled());
EXPECT_TRUE(collector_.IsCancelReceiverBound());
}
TEST_F(MojoBinderPolicyApplierTest, UnexpectedInPrepareToGrantAll) {
// Initialize Mojo interfaces.
mojo::Remote<mojom::TestInterfaceForUnexpected> unexpected_remote;
mojo::GenericPendingReceiver unexpected_receiver(
unexpected_remote.BindNewPipeAndPassReceiver());
policy_applier_.PrepareToGrantAll();
const std::string interface_name =
unexpected_receiver.interface_name().value();
policy_applier_.ApplyPolicyToNonAssociatedBinder(
interface_name,
base::BindOnce(
&TestReceiverCollector::BindUnexpectedInterface,
base::Unretained(&collector_),
unexpected_receiver.As<mojom::TestInterfaceForUnexpected>()));
EXPECT_FALSE(collector_.IsCancelled());
EXPECT_TRUE(collector_.IsUnexpectedReceiverBound());
}
// Verifies that all interfaces are bound immediately if GrantAll() is called,
// regardless of policies.
TEST_F(MojoBinderPolicyApplierTest, BindInterfacesAfterResolving) {
// Initialize Mojo interfaces.
mojo::Remote<mojom::TestInterfaceForDefer> defer_remote;
mojo::GenericPendingReceiver defer_receiver(
defer_remote.BindNewPipeAndPassReceiver());
mojo::Remote<mojom::TestInterfaceForGrant> grant_remote;
mojo::GenericPendingReceiver grant_receiver(
grant_remote.BindNewPipeAndPassReceiver());
mojo::Remote<mojom::TestInterfaceForCancel> cancel_remote;
mojo::GenericPendingReceiver cancel_receiver(
cancel_remote.BindNewPipeAndPassReceiver());
mojo::Remote<mojom::TestInterfaceForUnexpected> unexpected_remote;
mojo::GenericPendingReceiver unexpected_receiver(
unexpected_remote.BindNewPipeAndPassReceiver());
RunGrantAll();
// All interfaces should be bound immediately.
const std::string defer_interface_name =
defer_receiver.interface_name().value();
const std::string grant_interface_name =
grant_receiver.interface_name().value();
const std::string cancel_interface_name =
cancel_receiver.interface_name().value();
const std::string unexpected_interface_name =
unexpected_receiver.interface_name().value();
EXPECT_FALSE(collector_.IsCancelled());
EXPECT_FALSE(collector_.IsGrantReceiverBound());
EXPECT_FALSE(collector_.IsDeferReceiverBound());
EXPECT_FALSE(collector_.IsCancelReceiverBound());
EXPECT_FALSE(collector_.IsUnexpectedReceiverBound());
policy_applier_.ApplyPolicyToNonAssociatedBinder(
defer_interface_name,
base::BindOnce(&TestReceiverCollector::BindDeferInterface,
base::Unretained(&collector_),
defer_receiver.As<mojom::TestInterfaceForDefer>()));
policy_applier_.ApplyPolicyToNonAssociatedBinder(
grant_interface_name,
base::BindOnce(&TestReceiverCollector::BindGrantInterface,
base::Unretained(&collector_),
grant_receiver.As<mojom::TestInterfaceForGrant>()));
policy_applier_.ApplyPolicyToNonAssociatedBinder(
cancel_interface_name,
base::BindOnce(&TestReceiverCollector::BindCancelInterface,
base::Unretained(&collector_),
cancel_receiver.As<mojom::TestInterfaceForCancel>()));
policy_applier_.ApplyPolicyToNonAssociatedBinder(
unexpected_interface_name,
base::BindOnce(
&TestReceiverCollector::BindUnexpectedInterface,
base::Unretained(&collector_),
unexpected_receiver.As<mojom::TestInterfaceForUnexpected>()));
EXPECT_TRUE(collector_.IsGrantReceiverBound());
EXPECT_TRUE(collector_.IsDeferReceiverBound());
EXPECT_TRUE(collector_.IsCancelReceiverBound());
EXPECT_TRUE(collector_.IsUnexpectedReceiverBound());
EXPECT_FALSE(collector_.IsCancelled());
EXPECT_EQ(0U, deferred_binders().size());
}
// Verifies that DropDeferredBinders() deletes all deferred binders.
TEST_F(MojoBinderPolicyApplierTest, DropDeferredBinders) {
// Initialize Mojo interfaces.
mojo::Remote<mojom::TestInterfaceForDefer> defer_remote;
mojo::GenericPendingReceiver defer_receiver(
defer_remote.BindNewPipeAndPassReceiver());
const std::string interface_name = defer_receiver.interface_name().value();
EXPECT_FALSE(collector_.IsCancelled());
policy_applier_.ApplyPolicyToNonAssociatedBinder(
interface_name,
base::BindOnce(&TestReceiverCollector::BindDeferInterface,
base::Unretained(&collector_),
defer_receiver.As<mojom::TestInterfaceForDefer>()));
EXPECT_FALSE(collector_.IsDeferReceiverBound());
EXPECT_EQ(1U, deferred_binders().size());
policy_applier_.DropDeferredBinders();
EXPECT_EQ(0U, deferred_binders().size());
RunGrantAll();
EXPECT_FALSE(collector_.IsDeferReceiverBound());
}
} // namespace content