// 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