From dddf3720ec078fb0e563d6932c4e988d24cf8776 Mon Sep 17 00:00:00 2001 From: Dom Del Nano Date: Fri, 13 Mar 2026 06:00:22 -0700 Subject: [PATCH 1/2] Update recursive_directory_iterator to skip permission denied errors Signed-off-by: Dom Del Nano (cherry picked from commit 6dd0f9aae1473f6bc48aaf685d1d05f0697f12ef) (cherry picked from commit 64e5a721395a51ee44632a44616fd523ac80268b) Signed-off-by: Dom Del Nano --- src/shared/metadata/cgroup_path_resolver.cc | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/shared/metadata/cgroup_path_resolver.cc b/src/shared/metadata/cgroup_path_resolver.cc index bf71cb9a2b9..da6bff6e22f 100644 --- a/src/shared/metadata/cgroup_path_resolver.cc +++ b/src/shared/metadata/cgroup_path_resolver.cc @@ -70,13 +70,24 @@ StatusOr> CGroupBasePaths(std::string_view sysfs_path) StatusOr FindSelfCGroupProcs(std::string_view base_path) { int pid = getpid(); + std::error_code ec; - for (auto& p : std::filesystem::recursive_directory_iterator(base_path)) { - if (p.path().filename() == "cgroup.procs") { - std::string contents = ReadFileToString(p.path().string()).ValueOr(""); + auto it = std::filesystem::recursive_directory_iterator( + base_path, std::filesystem::directory_options::skip_permission_denied, ec); + if (ec) { + return error::Internal("Failed to iterate cgroup path: $0", ec.message()); + } + + for (auto end = std::filesystem::recursive_directory_iterator(); it != end; it.increment(ec)) { + if (ec) { + ec.clear(); + continue; + } + if (it->path().filename() == "cgroup.procs") { + std::string contents = ReadFileToString(it->path().string()).ValueOr(""); int contents_pid; if (absl::SimpleAtoi(contents, &contents_pid) && pid == contents_pid) { - return p.path().string(); + return it->path().string(); } } } From 427fc6ed943e5185f2ff3af133af818906b64445 Mon Sep 17 00:00:00 2001 From: Dom Del Nano Date: Sat, 14 Mar 2026 12:21:18 -0700 Subject: [PATCH 2/2] Add test to cover permission denied case Signed-off-by: Dom Del Nano --- .../metadata/cgroup_path_resolver_test.cc | 68 +++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/src/shared/metadata/cgroup_path_resolver_test.cc b/src/shared/metadata/cgroup_path_resolver_test.cc index 9e57b0aa0b0..0ab46fa9f05 100644 --- a/src/shared/metadata/cgroup_path_resolver_test.cc +++ b/src/shared/metadata/cgroup_path_resolver_test.cc @@ -16,11 +16,16 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include +#include + #include +#include #include #include +#include "src/common/testing/temp_dir.h" #include "src/common/testing/testing.h" #include "src/shared/metadata/cgroup_path_resolver.h" @@ -390,5 +395,68 @@ TEST(CGroupPathResolver, Cgroup2Format) { * 4. cgroup1+cgroup2 w/ cgroup1 succeeding */ +// Test that FindSelfCGroupProcs gracefully handles permission-denied directories +// (e.g. CrowdStrike Falcon's sandbox.falcon) instead of crashing with an uncaught exception. +TEST(FindSelfCGroupProcs, SkipsPermissionDeniedDirectories) { + // This test requires running as non-root, since root bypasses permission checks. + if (getuid() == 0) { + GTEST_SKIP() << "Test requires non-root user"; + } + + px::testing::TempDir tmp_dir; + auto base_path = tmp_dir.path(); + + // Create a directory structure with an accessible cgroup.procs containing our PID, + // and a restricted directory that simulates CrowdStrike Falcon's sandbox. + auto accessible_dir = base_path / "kubepods" / "pod1234"; + std::filesystem::create_directories(accessible_dir); + + // Write our PID to cgroup.procs so FindSelfCGroupProcs can find it. + { + std::ofstream ofs((accessible_dir / "cgroup.procs").string()); + ofs << getpid(); + } + + // Create a restricted directory that the iterator cannot enter. + auto restricted_dir = base_path / "system.slice" / "falcon-sensor.service" / "sandbox.falcon"; + std::filesystem::create_directories(restricted_dir); + // Remove all permissions on the sandbox directory. + chmod(restricted_dir.c_str(), 0000); + + // FindSelfCGroupProcs should succeed and find our cgroup.procs, + // skipping the restricted directory instead of throwing. + ASSERT_OK_AND_ASSIGN(auto result, FindSelfCGroupProcs(base_path.string())); + EXPECT_EQ(result, (accessible_dir / "cgroup.procs").string()); + + // Restore permissions so TempDir cleanup can remove it. + chmod(restricted_dir.c_str(), 0755); +} + +// Test that FindSelfCGroupProcs returns NotFound (not a crash) when the only +// cgroup.procs is behind a restricted directory. +TEST(FindSelfCGroupProcs, ReturnsNotFoundWhenAllPathsRestricted) { + if (getuid() == 0) { + GTEST_SKIP() << "Test requires non-root user"; + } + + px::testing::TempDir tmp_dir; + auto base_path = tmp_dir.path(); + + // Put cgroup.procs inside a restricted directory so it's unreachable. + auto restricted_dir = base_path / "restricted"; + std::filesystem::create_directories(restricted_dir); + { + std::ofstream ofs((restricted_dir / "cgroup.procs").string()); + ofs << getpid(); + } + chmod(restricted_dir.c_str(), 0000); + + // Should return NotFound, not crash. + auto result = FindSelfCGroupProcs(base_path.string()); + EXPECT_NOT_OK(result); + + chmod(restricted_dir.c_str(), 0755); +} + } // namespace md } // namespace px