|
16 | 16 | * SPDX-License-Identifier: Apache-2.0 |
17 | 17 | */ |
18 | 18 |
|
| 19 | +#include <sys/stat.h> |
| 20 | +#include <unistd.h> |
| 21 | + |
19 | 22 | #include <gtest/gtest.h> |
20 | 23 |
|
| 24 | +#include <fstream> |
21 | 25 | #include <string> |
22 | 26 | #include <vector> |
23 | 27 |
|
| 28 | +#include "src/common/testing/temp_dir.h" |
24 | 29 | #include "src/common/testing/testing.h" |
25 | 30 | #include "src/shared/metadata/cgroup_path_resolver.h" |
26 | 31 |
|
@@ -390,5 +395,68 @@ TEST(CGroupPathResolver, Cgroup2Format) { |
390 | 395 | * 4. cgroup1+cgroup2 w/ cgroup1 succeeding |
391 | 396 | */ |
392 | 397 |
|
| 398 | +// Test that FindSelfCGroupProcs gracefully handles permission-denied directories |
| 399 | +// (e.g. CrowdStrike Falcon's sandbox.falcon) instead of crashing with an uncaught exception. |
| 400 | +TEST(FindSelfCGroupProcs, SkipsPermissionDeniedDirectories) { |
| 401 | + // This test requires running as non-root, since root bypasses permission checks. |
| 402 | + if (getuid() == 0) { |
| 403 | + GTEST_SKIP() << "Test requires non-root user"; |
| 404 | + } |
| 405 | + |
| 406 | + px::testing::TempDir tmp_dir; |
| 407 | + auto base_path = tmp_dir.path(); |
| 408 | + |
| 409 | + // Create a directory structure with an accessible cgroup.procs containing our PID, |
| 410 | + // and a restricted directory that simulates CrowdStrike Falcon's sandbox. |
| 411 | + auto accessible_dir = base_path / "kubepods" / "pod1234"; |
| 412 | + std::filesystem::create_directories(accessible_dir); |
| 413 | + |
| 414 | + // Write our PID to cgroup.procs so FindSelfCGroupProcs can find it. |
| 415 | + { |
| 416 | + std::ofstream ofs((accessible_dir / "cgroup.procs").string()); |
| 417 | + ofs << getpid(); |
| 418 | + } |
| 419 | + |
| 420 | + // Create a restricted directory that the iterator cannot enter. |
| 421 | + auto restricted_dir = base_path / "system.slice" / "falcon-sensor.service" / "sandbox.falcon"; |
| 422 | + std::filesystem::create_directories(restricted_dir); |
| 423 | + // Remove all permissions on the sandbox directory. |
| 424 | + chmod(restricted_dir.c_str(), 0000); |
| 425 | + |
| 426 | + // FindSelfCGroupProcs should succeed and find our cgroup.procs, |
| 427 | + // skipping the restricted directory instead of throwing. |
| 428 | + ASSERT_OK_AND_ASSIGN(auto result, FindSelfCGroupProcs(base_path.string())); |
| 429 | + EXPECT_EQ(result, (accessible_dir / "cgroup.procs").string()); |
| 430 | + |
| 431 | + // Restore permissions so TempDir cleanup can remove it. |
| 432 | + chmod(restricted_dir.c_str(), 0755); |
| 433 | +} |
| 434 | + |
| 435 | +// Test that FindSelfCGroupProcs returns NotFound (not a crash) when the only |
| 436 | +// cgroup.procs is behind a restricted directory. |
| 437 | +TEST(FindSelfCGroupProcs, ReturnsNotFoundWhenAllPathsRestricted) { |
| 438 | + if (getuid() == 0) { |
| 439 | + GTEST_SKIP() << "Test requires non-root user"; |
| 440 | + } |
| 441 | + |
| 442 | + px::testing::TempDir tmp_dir; |
| 443 | + auto base_path = tmp_dir.path(); |
| 444 | + |
| 445 | + // Put cgroup.procs inside a restricted directory so it's unreachable. |
| 446 | + auto restricted_dir = base_path / "restricted"; |
| 447 | + std::filesystem::create_directories(restricted_dir); |
| 448 | + { |
| 449 | + std::ofstream ofs((restricted_dir / "cgroup.procs").string()); |
| 450 | + ofs << getpid(); |
| 451 | + } |
| 452 | + chmod(restricted_dir.c_str(), 0000); |
| 453 | + |
| 454 | + // Should return NotFound, not crash. |
| 455 | + auto result = FindSelfCGroupProcs(base_path.string()); |
| 456 | + EXPECT_NOT_OK(result); |
| 457 | + |
| 458 | + chmod(restricted_dir.c_str(), 0755); |
| 459 | +} |
| 460 | + |
393 | 461 | } // namespace md |
394 | 462 | } // namespace px |
0 commit comments