1 // Copyright 2024 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "sandboxed_api/sandbox2/util/deadline_manager.h"
16
17 #include <sys/syscall.h>
18
19 #include <csignal>
20 #include <ctime>
21
22 #include "gtest/gtest.h"
23 #include "absl/flags/flag.h"
24 #include "absl/log/check.h"
25 #include "absl/time/clock.h"
26 #include "absl/time/time.h"
27 #include "sandboxed_api/util/thread.h"
28
29 namespace sandbox2 {
30 namespace {
31
TEST(DeadlineManagerTest,Basic)32 TEST(DeadlineManagerTest, Basic) {
33 DeadlineManager manager("test");
34 DeadlineRegistration registration(manager);
35 absl::Time start_time = absl::Now();
36 struct timespec ts = absl::ToTimespec(absl::Seconds(1));
37 registration.SetDeadline(start_time + absl::Milliseconds(100));
38 registration.ExecuteBlockingSyscall(
39 [&] { ASSERT_EQ(nanosleep(&ts, nullptr), -1); });
40 absl::Duration elapsed = absl::Now() - start_time;
41 EXPECT_GE(elapsed, absl::Milliseconds(100));
42 EXPECT_LE(elapsed, absl::Milliseconds(200));
43 }
44
TEST(DeadlineManagerTest,NotifiesUntilFunctionReturns)45 TEST(DeadlineManagerTest, NotifiesUntilFunctionReturns) {
46 DeadlineManager manager("test");
47 DeadlineRegistration registration(manager);
48 absl::Time start_time = absl::Now();
49 struct timespec ts = absl::ToTimespec(absl::Seconds(1));
50 registration.SetDeadline(start_time + absl::Milliseconds(100));
51 registration.ExecuteBlockingSyscall([&] {
52 // Double so that it needs to be notified twice.
53 ASSERT_EQ(nanosleep(&ts, nullptr), -1);
54 ASSERT_EQ(nanosleep(&ts, nullptr), -1);
55 });
56 absl::Duration elapsed = absl::Now() - start_time;
57 EXPECT_GE(elapsed, absl::Milliseconds(100));
58 EXPECT_LE(elapsed, absl::Milliseconds(200));
59 }
60
TEST(DeadlineManagerTest,DeadlineInThePast)61 TEST(DeadlineManagerTest, DeadlineInThePast) {
62 DeadlineManager manager("test");
63 DeadlineRegistration registration(manager);
64 registration.SetDeadline(absl::InfinitePast());
65 registration.ExecuteBlockingSyscall(
66 [&] { FAIL() << "Function should not be executed"; });
67 }
68
TEST(DeadlineManagerTest,DeadlineSetConcurrently)69 TEST(DeadlineManagerTest, DeadlineSetConcurrently) {
70 DeadlineManager manager("test");
71 DeadlineRegistration registration(manager);
72 absl::Time start_time = absl::Now();
73 struct timespec ts = absl::ToTimespec(absl::Seconds(1));
74 registration.ExecuteBlockingSyscall([&] {
75 sapi::Thread thread([&] {
76 absl::SleepFor(absl::Milliseconds(10));
77 registration.SetDeadline(start_time + absl::Milliseconds(100));
78 });
79 ASSERT_EQ(nanosleep(&ts, nullptr), -1);
80 thread.Join();
81 });
82 absl::Duration elapsed = absl::Now() - start_time;
83 EXPECT_GE(elapsed, absl::Milliseconds(100));
84 EXPECT_LE(elapsed, absl::Milliseconds(200));
85 }
86
TEST(DeadlineManagerTest,DeadlineInPastSetConcurrently)87 TEST(DeadlineManagerTest, DeadlineInPastSetConcurrently) {
88 DeadlineManager manager("test");
89 DeadlineRegistration registration(manager);
90 absl::Time start_time = absl::Now();
91 struct timespec ts = absl::ToTimespec(absl::Seconds(1));
92 registration.ExecuteBlockingSyscall([&] {
93 sapi::Thread thread([&] {
94 absl::SleepFor(absl::Milliseconds(100));
95 registration.SetDeadline(absl::InfinitePast());
96 });
97 ASSERT_EQ(nanosleep(&ts, nullptr), -1);
98 thread.Join();
99 });
100 absl::Duration elapsed = absl::Now() - start_time;
101 EXPECT_GE(elapsed, absl::Milliseconds(100));
102 EXPECT_LE(elapsed, absl::Milliseconds(200));
103 }
104
TEST(DeadlineManagerTest,DeadlineReset)105 TEST(DeadlineManagerTest, DeadlineReset) {
106 DeadlineManager manager("test");
107 DeadlineRegistration registration(manager);
108 absl::Time start_time = absl::Now();
109 struct timespec ts = absl::ToTimespec(absl::Milliseconds(200));
110 registration.ExecuteBlockingSyscall([&] {
111 registration.SetDeadline(absl::InfiniteFuture());
112 ASSERT_EQ(nanosleep(&ts, nullptr), 0);
113 });
114 absl::Duration elapsed = absl::Now() - start_time;
115 EXPECT_GE(elapsed, absl::Milliseconds(200));
116 }
117
TEST(DeadlineManagerTest,CanBeReusedAfterExpiration)118 TEST(DeadlineManagerTest, CanBeReusedAfterExpiration) {
119 DeadlineManager manager("test");
120 DeadlineRegistration registration(manager);
121 for (int i = 0; i < 3; ++i) {
122 absl::Time start_time = absl::Now();
123 struct timespec ts = absl::ToTimespec(absl::Seconds(1));
124 registration.SetDeadline(start_time + absl::Milliseconds(100));
125 registration.ExecuteBlockingSyscall(
126 [&] { ASSERT_EQ(nanosleep(&ts, nullptr), -1); });
127 absl::Duration elapsed = absl::Now() - start_time;
128 EXPECT_GE(elapsed, absl::Milliseconds(100));
129 EXPECT_LE(elapsed, absl::Milliseconds(200));
130 }
131 }
132
TEST(DeadlineManagerTest,WorksInAThread)133 TEST(DeadlineManagerTest, WorksInAThread) {
134 DeadlineManager manager("test");
135 DeadlineRegistration registration(manager);
136 sapi::Thread thread([&] {
137 absl::Time start_time = absl::Now();
138 struct timespec ts = absl::ToTimespec(absl::Seconds(1));
139 registration.SetDeadline(start_time + absl::Milliseconds(100));
140 registration.ExecuteBlockingSyscall(
141 [&] { ASSERT_EQ(nanosleep(&ts, nullptr), -1); });
142 absl::Duration elapsed = absl::Now() - start_time;
143 EXPECT_GE(elapsed, absl::Milliseconds(100));
144 EXPECT_LE(elapsed, absl::Milliseconds(200));
145 });
146 thread.Join();
147 }
148
TEST(DeadlineManagerTest,DetectsOverridenHandler)149 TEST(DeadlineManagerTest, DetectsOverridenHandler) {
150 DeadlineManager manager("test");
151 DeadlineRegistration registration(manager);
152 EXPECT_DEATH(
153 {
154 struct sigaction sa = {};
155 CHECK_EQ(
156 sigaction(absl::GetFlag(FLAGS_sandbox2_deadline_manager_signal),
157 nullptr, &sa),
158 0);
159 sa.sa_handler = SIG_IGN;
160 CHECK_EQ(
161 sigaction(absl::GetFlag(FLAGS_sandbox2_deadline_manager_signal),
162 &sa, nullptr),
163 0);
164 absl::Time start_time = absl::Now();
165 absl::Time sleep_until = start_time + absl::Seconds(5);
166 registration.SetDeadline(start_time + absl::Milliseconds(100));
167 registration.ExecuteBlockingSyscall([sleep_until] {
168 absl::Duration remaining = sleep_until - absl::Now();
169 while (remaining > absl::ZeroDuration()) {
170 struct timespec ts = absl::ToTimespec(remaining);
171 CHECK_EQ(nanosleep(&ts, nullptr), -1);
172 remaining = sleep_until - absl::Now();
173 }
174 });
175 },
176 "Signal handler was overriden");
177 }
178
TEST(DeadlineManagerTest,DetectsOverridenHandlerFlags)179 TEST(DeadlineManagerTest, DetectsOverridenHandlerFlags) {
180 DeadlineManager manager("test");
181 DeadlineRegistration registration(manager);
182 EXPECT_DEATH(
183 {
184 struct sigaction sa = {};
185 CHECK_EQ(
186 sigaction(absl::GetFlag(FLAGS_sandbox2_deadline_manager_signal),
187 nullptr, &sa),
188 0);
189 sa.sa_flags = SA_RESTART;
190 CHECK_EQ(
191 sigaction(absl::GetFlag(FLAGS_sandbox2_deadline_manager_signal),
192 &sa, nullptr),
193 0);
194 absl::Time start_time = absl::Now();
195 absl::Time sleep_until = start_time + absl::Seconds(5);
196 registration.SetDeadline(start_time + absl::Milliseconds(100));
197 registration.ExecuteBlockingSyscall([sleep_until] {
198 absl::Duration remaining = sleep_until - absl::Now();
199 while (remaining > absl::ZeroDuration()) {
200 struct timespec ts = absl::ToTimespec(remaining);
201 CHECK_EQ(nanosleep(&ts, nullptr), -1);
202 remaining = sleep_until - absl::Now();
203 }
204 });
205 },
206 "SA_RESTART signal handler flag was overriden");
207 }
208
209 } // namespace
210 } // namespace sandbox2
211