0
Files
src/content/browser/mojo_binder_policy_applier_unittest.cc
Peter Boström fc7ddc185b Migrate to NOTREACHED() in content/
NOTREACHED() and NOTREACHED_IN_MIGRATION() are both CHECK-fatal now.
The former is [[noreturn]] so this CL also performs dead-code removal
after the NOTREACHED().

This CL does not attempt to do additional rewrites of any surrounding
code, like:

if (!foo) {
  NOTREACHED();
}

to CHECK(foo);

Those transforms take a non-trivial amount of time (and there are
thousands of instances). Cleanup can be left as an exercise for the
reader.

This does clean up kCrashOnDanglingBrowserContext as both paths of the
kill switch are currently fatal. This has been rolled out for a long
time.

Bug: 40580068, 40062641
Change-Id: Ib88e710d003e2e48df3fc502ca54d2341d157a0e
Cq-Include-Trybots: luci.chromium.try:linux-dcheck-off-rel
Low-Coverage-Reason: OTHER Should-be-unreachable code
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5974816
Reviewed-by: Łukasz Anforowicz <lukasza@chromium.org>
Commit-Queue: Łukasz Anforowicz <lukasza@chromium.org>
Reviewed-by: Rakina Zata Amni <rakina@chromium.org>
Auto-Submit: Peter Boström <pbos@chromium.org>
Reviewed-by: Sam McNally <sammc@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1376522}
2024-10-31 19:37:21 +00:00

375 lines
15 KiB
C++

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