| // Copyright 2024 The Fuchsia 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 "src/devices/bin/driver_manager/tests/driver_runner_test_fixture.h" |
| |
| namespace driver_runner { |
| |
| // BEGIN DEATH TESTS |
| // _________-----_____ |
| // _____------ __ ----_ |
| // ___---- ___------ \ |
| // ----________ ---- \ |
| // -----__ | _____) |
| // __- / \ |
| // _______----- ___-- \ /)\ |
| // ------_______ ---____ \__/ / |
| // -----__ \ -- _ /\ |
| // --__--__ \_____/ \_/\ |
| // ----| / | |
| // | |___________| |
| // | | ((_(_)| )_) |
| // | \_((_(_)|/(_) |
| // \ ( |
| // \_____________) |
| // |
| // These tests test the allowlist for the fuchsia.device/Controller |
| // interface. They first test the interface with an class name that |
| // is on the allowlist, then with a classname that is not on the allowlist |
| // to make sure it fails. |
| |
| const char* kAllowedClassName = "driver_runner_test"; |
| const char* kDisallowedClassName = "Not_on_allowlist"; |
| |
| const char* kAllowedChildName = "node-1"; |
| const char* kBannedChildName = "node-0"; |
| |
| // This type of test creates two children, one with an allowed class name |
| // and the other without. |
| class DriverRunnerDeathTest : public DriverRunnerTest { |
| public: |
| void SetUp() override { |
| SetupDriverRunner(); |
| root_driver_ = StartRootDriver(); |
| ASSERT_EQ(ZX_OK, root_driver_.status_value()); |
| allowed_child_ = |
| root_driver_->driver->AddChild(kAllowedChildName, true, false, kAllowedClassName); |
| banned_child_ = |
| root_driver_->driver->AddChild(kBannedChildName, true, false, kDisallowedClassName); |
| EXPECT_TRUE(RunLoopUntilIdle()); |
| allowed_controller_ = ConnectToDeviceController(kAllowedChildName); |
| banned_controller_ = ConnectToDeviceController(kBannedChildName); |
| } |
| |
| protected: |
| zx::result<StartDriverResult> root_driver_; |
| std::shared_ptr<CreatedChild> allowed_child_, banned_child_; |
| fidl::WireClient<fuchsia_device::Controller> allowed_controller_, banned_controller_; |
| }; |
| |
| void TryConnectToController(fidl::WireClient<fuchsia_device::Controller>& controller, |
| async::TestLoop& loop) { |
| auto controller_endpoints = fidl::Endpoints<fuchsia_device::Controller>::Create(); |
| fidl::OneWayStatus result = |
| controller->ConnectToController(std::move(controller_endpoints.server)); |
| ASSERT_TRUE(loop.RunUntilIdle()); |
| ASSERT_EQ(result.status(), ZX_OK); |
| } |
| |
| // Start the root driver, add a child node, and verify that the child node's device controller is |
| // reachable. |
| TEST_F(DriverRunnerDeathTest, AllowlistCausesConnectToControllerToFail) { |
| TryConnectToController(allowed_controller_, test_loop()); |
| |
| ASSERT_DEATH(TryConnectToController(banned_controller_, test_loop()), |
| "Undeclared DEVFS_USAGE detected"); |
| } |
| |
| void TryConnectToDeviceFidl(fidl::WireClient<fuchsia_device::Controller>& controller, |
| async::TestLoop& loop) { |
| auto controller_endpoints = fidl::Endpoints<fuchsia_device::Controller>::Create(); |
| fidl::OneWayStatus result = |
| controller->ConnectToDeviceFidl(controller_endpoints.server.TakeChannel()); |
| ASSERT_TRUE(loop.RunUntilIdle()); |
| ASSERT_EQ(result.status(), ZX_OK); |
| } |
| |
| // This just verifies that the call was able to be made and now blocked by the allowlist. It does |
| // not check that the device actually connected an interface. |
| TEST_F(DriverRunnerDeathTest, AllowlistCausesConnectToDeviceFidlToFail) { |
| TryConnectToDeviceFidl(allowed_controller_, test_loop()); |
| |
| ASSERT_DEATH(TryConnectToDeviceFidl(banned_controller_, test_loop()), |
| "Undeclared DEVFS_USAGE detected"); |
| } |
| |
| void TryBind(fidl::WireClient<fuchsia_device::Controller>& controller, async::TestLoop& loop) { |
| auto controller_endpoints = fidl::Endpoints<fuchsia_device::Controller>::Create(); |
| controller->Bind(fidl::StringView::FromExternal(second_driver_url)) |
| .Then([](fidl::WireUnownedResult<fuchsia_device::Controller::Bind>& reply) { |
| ASSERT_EQ(reply.status(), ZX_OK); |
| }); |
| ASSERT_TRUE(loop.RunUntilIdle()); |
| } |
| |
| TEST_F(DriverRunnerDeathTest, AllowlistCausesBindToFail) { |
| PrepareRealmForDriverComponentStart("dev.node-1", second_driver_url); |
| driver_index().set_match_callback([](auto args) -> zx::result<FakeDriverIndex::MatchResult> { |
| EXPECT_EQ(args.driver_url_suffix().get(), second_driver_url); |
| return zx::ok(FakeDriverIndex::MatchResult{ |
| .url = second_driver_url, |
| }); |
| }); |
| |
| TryBind(allowed_controller_, test_loop()); |
| |
| ASSERT_DEATH(TryBind(banned_controller_, test_loop()), "Undeclared DEVFS_USAGE detected"); |
| } |
| |
| void TryScheduleUnbind(fidl::WireClient<fuchsia_device::Controller>& controller, |
| async::TestLoop& loop) { |
| auto controller_endpoints = fidl::Endpoints<fuchsia_device::Controller>::Create(); |
| controller->ScheduleUnbind().Then( |
| [](fidl::WireUnownedResult<fuchsia_device::Controller::ScheduleUnbind>& reply) { |
| ASSERT_EQ(reply.status(), ZX_OK); |
| }); |
| ASSERT_TRUE(loop.RunUntilIdle()); |
| } |
| |
| TEST_F(DriverRunnerDeathTest, AllowlistCausesScheduleUnbindToFail) { |
| TryScheduleUnbind(allowed_controller_, test_loop()); |
| |
| ASSERT_DEATH(TryScheduleUnbind(banned_controller_, test_loop()), |
| "Undeclared DEVFS_USAGE detected"); |
| } |
| |
| void TryUnbindChildren(fidl::WireClient<fuchsia_device::Controller>& controller, |
| async::TestLoop& loop) { |
| auto controller_endpoints = fidl::Endpoints<fuchsia_device::Controller>::Create(); |
| controller->UnbindChildren().Then( |
| [](fidl::WireUnownedResult<fuchsia_device::Controller::UnbindChildren>& reply) { |
| ASSERT_EQ(reply.status(), ZX_OK); |
| }); |
| ASSERT_TRUE(loop.RunUntilIdle()); |
| } |
| |
| TEST_F(DriverRunnerDeathTest, AllowlistCausesUnbindChildrenToFail) { |
| TryUnbindChildren(allowed_controller_, test_loop()); |
| |
| ASSERT_DEATH(TryUnbindChildren(banned_controller_, test_loop()), |
| "Undeclared DEVFS_USAGE detected"); |
| } |
| } // namespace driver_runner |