This is an automated email from the ASF dual-hosted git repository. bmahler pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/mesos.git
commit 2458d2f9d367f4b4b6a7a79da24bf45ca6f7ebcb Author: Jason Zhou <[email protected]> AuthorDate: Fri Jul 26 17:17:31 2024 -0400 [cgroups2] Helper to check device access. A device access is granted if it is encompassed by an allow entry and does not have access overlaps with any deny entry. The current process of manually checking if a device access would be granted given a state is tedious and leads to worse readability. A new helper function is added to check if an entry would be granted access in a CgroupDeviceAccess instance, and requires the state to be normalized. Review: https://reviews.apache.org/r/75113/ --- .../device_manager/device_manager.cpp | 29 +++++++++++++ .../device_manager/device_manager.hpp | 4 ++ src/tests/device_manager_tests.cpp | 48 ++++++++++++++++++++++ 3 files changed, 81 insertions(+) diff --git a/src/slave/containerizer/device_manager/device_manager.cpp b/src/slave/containerizer/device_manager/device_manager.cpp index 4c9b86393..800e50243 100644 --- a/src/slave/containerizer/device_manager/device_manager.cpp +++ b/src/slave/containerizer/device_manager/device_manager.cpp @@ -340,6 +340,35 @@ DeviceManager::CgroupDeviceAccess DeviceManager::apply_diff( return new_state; } + +bool DeviceManager::CgroupDeviceAccess::is_access_granted( + const Entry& query) const +{ + CHECK(cgroups2::devices::normalized(allow_list)); + CHECK(cgroups2::devices::normalized(deny_list)); + + auto allowed = [&]() { + foreach (const Entry& allow, allow_list) { + if (allow.encompasses(query)) { + return true; + } + } + return false; + }; + + auto denied = [&]() { + foreach (const Entry& deny, deny_list) { + if (deny.selector.encompasses(query.selector) + && deny.access.overlaps(query.access)) { + return true; + } + } + return false; + }; + + return allowed() && !denied(); +} + } // namespace slave { } // namespace internal { } // namespace mesos { diff --git a/src/slave/containerizer/device_manager/device_manager.hpp b/src/slave/containerizer/device_manager/device_manager.hpp index 7c8523d8b..c0ffcc20f 100644 --- a/src/slave/containerizer/device_manager/device_manager.hpp +++ b/src/slave/containerizer/device_manager/device_manager.hpp @@ -68,6 +68,10 @@ public: { std::vector<cgroups::devices::Entry> allow_list; std::vector<cgroups::devices::Entry> deny_list; + + // A device access is granted if it is encompassed by an allow entry + // and does not have access overlaps with any deny entry. + bool is_access_granted(const cgroups::devices::Entry& entry) const; }; static Try<DeviceManager*> create(const Flags& flags); diff --git a/src/tests/device_manager_tests.cpp b/src/tests/device_manager_tests.cpp index 54d464e97..b30618c98 100644 --- a/src/tests/device_manager_tests.cpp +++ b/src/tests/device_manager_tests.cpp @@ -398,6 +398,54 @@ INSTANTIATE_TEST_CASE_P( vector<devices::Entry>{*devices::Entry::parse("c 3:* rm")}, vector<devices::Entry>{*devices::Entry::parse("c 3:1 r")}})); + +TEST(DeviceManagerCgroupDeviceAccessTest, IsAccessGrantedTest) +{ + DeviceManager::CgroupDeviceAccess cgroup_device_access; + + // Character devices with major minor numbers 1:3 can do write only: + cgroup_device_access.allow_list = {*devices::Entry::parse("c 1:3 w")}; + EXPECT_TRUE( + cgroup_device_access.is_access_granted(*devices::Entry::parse("c 1:3 w"))); + EXPECT_FALSE( + cgroup_device_access.is_access_granted(*devices::Entry::parse("c 1:3 rw"))); + EXPECT_FALSE( + cgroup_device_access.is_access_granted(*devices::Entry::parse("b 1:3 w"))); + + // Character devices with minor number 3 can do write only: + cgroup_device_access.allow_list = {*devices::Entry::parse("c *:3 w")}; + EXPECT_TRUE( + cgroup_device_access.is_access_granted(*devices::Entry::parse("c 4:3 w"))); + EXPECT_TRUE( + cgroup_device_access.is_access_granted(*devices::Entry::parse("c *:3 w"))); + + // Character devices with major number 5 can do write only: + cgroup_device_access.allow_list = {(*devices::Entry::parse("c 5:* w"))}; + EXPECT_TRUE( + cgroup_device_access.is_access_granted(*devices::Entry::parse("c 5:* w"))); + EXPECT_TRUE( + cgroup_device_access.is_access_granted(*devices::Entry::parse("c 5:2 w"))); + + // All devices will match the catch-all and can perform all operations: + cgroup_device_access.allow_list = {*devices::Entry::parse("a *:* rwm")}; + EXPECT_TRUE( + cgroup_device_access.is_access_granted(*devices::Entry::parse("c 6:2 w"))); + + // Deny all accesses to character device with major and numbers 1:3. + cgroup_device_access.deny_list = {*devices::Entry::parse("c 1:3 rwm")}; + EXPECT_FALSE( + cgroup_device_access.is_access_granted(*devices::Entry::parse("c 1:3 w"))); + EXPECT_FALSE( + cgroup_device_access.is_access_granted(*devices::Entry::parse("c 1:3 rw"))); + + // Entry should be denied if encompassed by an entry in allow_list and + // overlaps with entry in deny_list. + cgroup_device_access.allow_list = {*devices::Entry::parse("c 1:3 rw")}; + cgroup_device_access.deny_list = {*devices::Entry::parse("c 1:3 w")}; + EXPECT_FALSE( + cgroup_device_access.is_access_granted(*devices::Entry::parse("c 1:3 rw"))); +} + } // namespace tests { } // namespace internal { } // namespace mesos {
