OLD | NEW |
(Empty) | |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include <errno.h> |
| 6 #include <fcntl.h> |
| 7 #include <sys/ptrace.h> |
| 8 #include <sys/stat.h> |
| 9 #include <sys/types.h> |
| 10 #include <unistd.h> |
| 11 |
| 12 #include "base/bind.h" |
| 13 #include "base/compiler_specific.h" |
| 14 #include "base/posix/eintr_wrapper.h" |
| 15 #include "sandbox/linux/services/scoped_process.h" |
| 16 #include "sandbox/linux/services/yama.h" |
| 17 #include "sandbox/linux/tests/unit_tests.h" |
| 18 #include "testing/gtest/include/gtest/gtest.h" |
| 19 |
| 20 namespace sandbox { |
| 21 |
| 22 namespace { |
| 23 |
| 24 bool CanPtrace(pid_t pid) { |
| 25 int ret; |
| 26 ret = ptrace(PTRACE_ATTACH, pid, NULL, NULL); |
| 27 if (ret == -1) { |
| 28 CHECK_EQ(EPERM, errno); |
| 29 return false; |
| 30 } |
| 31 // Wait for the process to be stopped so that it can be detached. |
| 32 siginfo_t process_info; |
| 33 int wait_ret = HANDLE_EINTR(waitid(P_PID, pid, &process_info, WSTOPPED)); |
| 34 PCHECK(0 == wait_ret); |
| 35 PCHECK(0 == ptrace(PTRACE_DETACH, pid, NULL, NULL)); |
| 36 return true; |
| 37 } |
| 38 |
| 39 // _exit(0) if pid can be ptraced by the current process. |
| 40 // _exit(1) otherwise. |
| 41 void ExitZeroIfCanPtrace(pid_t pid) { |
| 42 if (CanPtrace(pid)) { |
| 43 _exit(0); |
| 44 } else { |
| 45 _exit(1); |
| 46 } |
| 47 } |
| 48 |
| 49 bool CanSubProcessPtrace(pid_t pid) { |
| 50 ScopedProcess process(base::Bind(&ExitZeroIfCanPtrace, pid)); |
| 51 bool signaled; |
| 52 int exit_code = process.WaitForExit(&signaled); |
| 53 CHECK(!signaled); |
| 54 return 0 == exit_code; |
| 55 } |
| 56 |
| 57 // The tests below assume that the system-level configuration will not change |
| 58 // while they run. |
| 59 |
| 60 TEST(Yama, GetStatus) { |
| 61 int status1 = Yama::GetStatus(); |
| 62 |
| 63 // Check that the value is a possible bitmask. |
| 64 ASSERT_LE(0, status1); |
| 65 ASSERT_GE(Yama::STATUS_KNOWN | Yama::STATUS_PRESENT | Yama::STATUS_ENFORCING | |
| 66 Yama::STATUS_STRICT_ENFORCING, |
| 67 status1); |
| 68 |
| 69 // The status should not just be a random value. |
| 70 int status2 = Yama::GetStatus(); |
| 71 EXPECT_EQ(status1, status2); |
| 72 |
| 73 // This test is not running sandboxed, there is no reason to not know the |
| 74 // status. |
| 75 EXPECT_NE(0, Yama::STATUS_KNOWN & status1); |
| 76 |
| 77 if (status1 & Yama::STATUS_STRICT_ENFORCING) { |
| 78 // If Yama is strictly enforcing, it is also enforcing. |
| 79 EXPECT_TRUE(status1 & Yama::STATUS_ENFORCING); |
| 80 } |
| 81 |
| 82 if (status1 & Yama::STATUS_ENFORCING) { |
| 83 // If Yama is enforcing, Yama is present. |
| 84 EXPECT_NE(0, status1 & Yama::STATUS_PRESENT); |
| 85 } |
| 86 |
| 87 // Verify that the helper functions work as intended. |
| 88 EXPECT_EQ(static_cast<bool>(status1 & Yama::STATUS_ENFORCING), |
| 89 Yama::IsEnforcing()); |
| 90 EXPECT_EQ(static_cast<bool>(status1 & Yama::STATUS_PRESENT), |
| 91 Yama::IsPresent()); |
| 92 |
| 93 fprintf(stdout, |
| 94 "Yama present: %s - enforcing: %s\n", |
| 95 Yama::IsPresent() ? "Y" : "N", |
| 96 Yama::IsEnforcing() ? "Y" : "N"); |
| 97 } |
| 98 |
| 99 SANDBOX_TEST(Yama, RestrictPtraceSucceedsWhenYamaPresent) { |
| 100 // This call will succeed iff Yama is present. |
| 101 bool restricted = Yama::RestrictPtracersToAncestors(); |
| 102 CHECK_EQ(restricted, Yama::IsPresent()); |
| 103 } |
| 104 |
| 105 // Attempts to enable or disable Yama restrictions. |
| 106 void SetYamaRestrictions(bool enable_restriction) { |
| 107 if (enable_restriction) { |
| 108 Yama::RestrictPtracersToAncestors(); |
| 109 } else { |
| 110 Yama::DisableYamaRestrictions(); |
| 111 } |
| 112 } |
| 113 |
| 114 TEST(Yama, RestrictPtraceWorks) { |
| 115 ScopedProcess process1(base::Bind(&SetYamaRestrictions, true)); |
| 116 ASSERT_TRUE(process1.WaitForClosureToRun()); |
| 117 |
| 118 if (Yama::IsEnforcing()) { |
| 119 // A sibling process cannot ptrace process1. |
| 120 ASSERT_FALSE(CanSubProcessPtrace(process1.GetPid())); |
| 121 } |
| 122 |
| 123 if (!(Yama::GetStatus() & Yama::STATUS_STRICT_ENFORCING)) { |
| 124 // However, parent can ptrace process1. |
| 125 ASSERT_TRUE(CanPtrace(process1.GetPid())); |
| 126 |
| 127 // A sibling can ptrace process2 which disables any Yama protection. |
| 128 ScopedProcess process2(base::Bind(&SetYamaRestrictions, false)); |
| 129 ASSERT_TRUE(process2.WaitForClosureToRun()); |
| 130 ASSERT_TRUE(CanSubProcessPtrace(process2.GetPid())); |
| 131 } |
| 132 } |
| 133 |
| 134 void DoNothing() {} |
| 135 |
| 136 SANDBOX_TEST(Yama, RestrictPtraceIsDefault) { |
| 137 if (!Yama::IsPresent()) |
| 138 return; |
| 139 |
| 140 CHECK(Yama::DisableYamaRestrictions()); |
| 141 ScopedProcess process1(base::Bind(&DoNothing)); |
| 142 |
| 143 if (Yama::IsEnforcing()) { |
| 144 // Check that process1 is protected by Yama, even though it has |
| 145 // been created from a process that disabled Yama. |
| 146 CHECK(!CanSubProcessPtrace(process1.GetPid())); |
| 147 } |
| 148 } |
| 149 |
| 150 } // namespace |
| 151 |
| 152 } // namespace sandbox |
OLD | NEW |