You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by bm...@apache.org on 2024/07/26 21:38:37 UTC
(mesos) 02/04: [cgroups2] Helper to check device access.
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 <ja...@gmail.com>
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 {