• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2019 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/policy.h"
16 
17 #include <syscall.h>
18 
19 #include <cerrno>
20 #include <cstdlib>
21 #include <memory>
22 #include <string>
23 #include <utility>
24 #include <vector>
25 
26 #include "gmock/gmock.h"
27 #include "gtest/gtest.h"
28 #include "absl/strings/string_view.h"
29 #include "sandboxed_api/config.h"
30 #include "sandboxed_api/sandbox2/executor.h"
31 #include "sandboxed_api/sandbox2/policybuilder.h"
32 #include "sandboxed_api/sandbox2/result.h"
33 #include "sandboxed_api/sandbox2/sandbox2.h"
34 #include "sandboxed_api/sandbox2/util/bpf_helper.h"
35 #include "sandboxed_api/testing.h"
36 #include "sandboxed_api/util/status_matchers.h"
37 
38 namespace sandbox2 {
39 namespace {
40 
41 using ::sapi::CreateDefaultPermissiveTestPolicy;
42 using ::sapi::GetTestSourcePath;
43 using ::testing::Eq;
44 
45 #ifdef SAPI_X86_64
46 
47 // Test that 32-bit syscalls from 64-bit are disallowed.
TEST(PolicyTest,AMD64Syscall32PolicyAllowed)48 TEST(PolicyTest, AMD64Syscall32PolicyAllowed) {
49   const std::string path = GetTestSourcePath("sandbox2/testcases/policy");
50 
51   std::vector<std::string> args = {path, "1"};
52 
53   SAPI_ASSERT_OK_AND_ASSIGN(auto policy,
54                             CreateDefaultPermissiveTestPolicy(path).TryBuild());
55   Sandbox2 s2(std::make_unique<Executor>(path, args), std::move(policy));
56   auto result = s2.Run();
57 
58   ASSERT_THAT(result.final_status(), Eq(Result::VIOLATION));
59   EXPECT_THAT(result.reason_code(), Eq(1));  // __NR_exit in 32-bit
60   EXPECT_THAT(result.GetSyscallArch(), Eq(sapi::cpu::kX86));
61 }
62 
63 // Test that 32-bit syscalls from 64-bit for FS checks are disallowed.
TEST(PolicyTest,AMD64Syscall32FsAllowed)64 TEST(PolicyTest, AMD64Syscall32FsAllowed) {
65   const std::string path = GetTestSourcePath("sandbox2/testcases/policy");
66   std::vector<std::string> args = {path, "2"};
67 
68   SAPI_ASSERT_OK_AND_ASSIGN(auto policy,
69                             CreateDefaultPermissiveTestPolicy(path).TryBuild());
70   Sandbox2 s2(std::make_unique<Executor>(path, args), std::move(policy));
71   auto result = s2.Run();
72 
73   ASSERT_THAT(result.final_status(), Eq(Result::VIOLATION));
74   EXPECT_THAT(result.reason_code(),
75               Eq(33));  // __NR_access in 32-bit
76   EXPECT_THAT(result.GetSyscallArch(), Eq(sapi::cpu::kX86));
77 }
78 #endif
79 
80 // Test that ptrace(2) is disallowed.
TEST(PolicyTest,PtraceDisallowed)81 TEST(PolicyTest, PtraceDisallowed) {
82   const std::string path = GetTestSourcePath("sandbox2/testcases/policy");
83   std::vector<std::string> args = {path, "3"};
84 
85   SAPI_ASSERT_OK_AND_ASSIGN(auto policy,
86                             CreateDefaultPermissiveTestPolicy(path).TryBuild());
87   Sandbox2 s2(std::make_unique<Executor>(path, args), std::move(policy));
88   auto result = s2.Run();
89 
90   ASSERT_THAT(result.final_status(), Eq(Result::VIOLATION));
91   EXPECT_THAT(result.reason_code(), Eq(__NR_ptrace));
92 }
93 
94 // Test that clone(2) with flag CLONE_UNTRACED is disallowed.
TEST(PolicyTest,CloneUntracedDisallowed)95 TEST(PolicyTest, CloneUntracedDisallowed) {
96   const std::string path = GetTestSourcePath("sandbox2/testcases/policy");
97   std::vector<std::string> args = {path, "4"};
98   SAPI_ASSERT_OK_AND_ASSIGN(auto policy,
99                             CreateDefaultPermissiveTestPolicy(path).TryBuild());
100   Sandbox2 s2(std::make_unique<Executor>(path, args), std::move(policy));
101   auto result = s2.Run();
102 
103   ASSERT_THAT(result.final_status(), Eq(Result::VIOLATION));
104   EXPECT_THAT(result.reason_code(), Eq(__NR_clone));
105 }
106 
107 // Test that bpf(2) is disallowed.
TEST(PolicyTest,BpfDisallowed)108 TEST(PolicyTest, BpfDisallowed) {
109   const std::string path = GetTestSourcePath("sandbox2/testcases/policy");
110   std::vector<std::string> args = {path, "5"};
111   SAPI_ASSERT_OK_AND_ASSIGN(auto policy,
112                             CreateDefaultPermissiveTestPolicy(path).TryBuild());
113   Sandbox2 s2(std::make_unique<Executor>(path, args), std::move(policy));
114   auto result = s2.Run();
115 
116   ASSERT_THAT(result.final_status(), Eq(Result::VIOLATION));
117   EXPECT_THAT(result.reason_code(), Eq(__NR_bpf));
118 }
119 
120 // Test that ptrace/bpf can return EPERM.
TEST(PolicyTest,BpfPtracePermissionDenied)121 TEST(PolicyTest, BpfPtracePermissionDenied) {
122   const std::string path = GetTestSourcePath("sandbox2/testcases/policy");
123   std::vector<std::string> args = {path, "7"};
124 
125   SAPI_ASSERT_OK_AND_ASSIGN(
126       auto policy, CreateDefaultPermissiveTestPolicy(path)
127                        .BlockSyscallsWithErrno({__NR_ptrace, __NR_bpf}, EPERM)
128                        .TryBuild());
129   Sandbox2 s2(std::make_unique<Executor>(path, args), std::move(policy));
130   auto result = s2.Run();
131 
132   // ptrace/bpf is not a violation due to explicit policy.  EPERM is expected.
133   ASSERT_THAT(result.final_status(), Eq(Result::OK));
134   EXPECT_THAT(result.reason_code(), Eq(0));
135 }
136 
TEST(PolicyTest,IsattyAllowed)137 TEST(PolicyTest, IsattyAllowed) {
138   SKIP_SANITIZERS;
139   PolicyBuilder builder;
140   builder.AllowStaticStartup()
141       .AllowExit()
142       .AllowRead()
143       .AllowWrite()
144       .AllowTCGETS()
145       .AllowLlvmCoverage();
146   const std::string path = GetTestSourcePath("sandbox2/testcases/policy");
147   std::vector<std::string> args = {path, "6"};
148   SAPI_ASSERT_OK_AND_ASSIGN(auto policy, builder.TryBuild());
149   Sandbox2 s2(std::make_unique<Executor>(path, args), std::move(policy));
150   auto result = s2.Run();
151 
152   ASSERT_THAT(result.final_status(), Eq(Result::OK));
153 }
154 
PosixTimersPolicyBuilder(absl::string_view path)155 PolicyBuilder PosixTimersPolicyBuilder(absl::string_view path) {
156   return PolicyBuilder()
157       // Required by google infra / logging.
158       .AllowDynamicStartup()
159       .AllowWrite()
160       .AllowSyscall(__NR_getcwd)
161       .AllowMmap()
162       .AllowMlock()
163       .AllowMkdir()
164       .AllowGetIDs()
165       .AllowExit()
166       .AllowRestartableSequences(PolicyBuilder::kAllowSlowFences)
167       .AllowSyscall(__NR_rt_sigtimedwait)
168       // Features used by the binary.
169       .AllowHandleSignals()
170       .AllowGetPIDs()
171       .AllowTime()
172       .AllowSleep()
173       .AllowAlarm()
174       // Posix timers themselves.
175       .AllowPosixTimers();
176 }
177 
TEST(PolicyTest,PosixTimersWorkIfAllowed)178 TEST(PolicyTest, PosixTimersWorkIfAllowed) {
179   SKIP_SANITIZERS;
180   const std::string path = GetTestSourcePath("sandbox2/testcases/posix_timers");
181   for (absl::string_view kind : {"SIGEV_NONE", "SIGEV_SIGNAL",
182                                  "SIGEV_THREAD_ID", "syscall(SIGEV_THREAD)"}) {
183     std::vector<std::string> args = {path, "--sigev_notify_kind",
184                                      std::string(kind)};
185 
186     SAPI_ASSERT_OK_AND_ASSIGN(auto policy,
187                               PosixTimersPolicyBuilder(path).TryBuild());
188     auto executor = std::make_unique<Executor>(path, args);
189     Sandbox2 sandbox(std::move(executor), std::move(policy));
190     Result result = sandbox.Run();
191     EXPECT_EQ(result.final_status(), Result::OK) << kind;
192   }
193 }
194 
TEST(PolicyTest,PosixTimersCannotCreateThreadsIfThreadsAreProhibited)195 TEST(PolicyTest, PosixTimersCannotCreateThreadsIfThreadsAreProhibited) {
196   SKIP_SANITIZERS;
197   const std::string path = GetTestSourcePath("sandbox2/testcases/posix_timers");
198   std::vector<std::string> args = {
199       path,
200       // SIGEV_THREAD creates a thread as an implementation detail.
201       "--sigev_notify_kind=SIGEV_THREAD",
202   };
203 
204   SAPI_ASSERT_OK_AND_ASSIGN(auto policy,
205                             PosixTimersPolicyBuilder(path).TryBuild());
206   auto executor = std::make_unique<Executor>(path, args);
207   Sandbox2 sandbox(std::move(executor), std::move(policy));
208   Result result = sandbox.Run();
209   EXPECT_EQ(result.final_status(), Result::VIOLATION);
210 }
211 
TEST(PolicyTest,PosixTimersCanCreateThreadsIfThreadsAreAllowed)212 TEST(PolicyTest, PosixTimersCanCreateThreadsIfThreadsAreAllowed) {
213   SKIP_SANITIZERS;
214   const std::string path = GetTestSourcePath("sandbox2/testcases/posix_timers");
215   std::vector<std::string> args = {path, "--sigev_notify_kind=SIGEV_THREAD"};
216 
217   SAPI_ASSERT_OK_AND_ASSIGN(auto policy, PosixTimersPolicyBuilder(path)
218                                              .AllowFork()
219                                              // For Arm.
220                                              .AllowSyscall(__NR_madvise)
221                                              .TryBuild());
222   auto executor = std::make_unique<Executor>(path, args);
223   Sandbox2 sandbox(std::move(executor), std::move(policy));
224   Result result = sandbox.Run();
225   EXPECT_EQ(result.final_status(), Result::OK);
226 }
227 
MinimalTestcasePolicy(absl::string_view path="")228 std::unique_ptr<Policy> MinimalTestcasePolicy(absl::string_view path = "") {
229   PolicyBuilder builder;
230   builder.AllowStaticStartup().AllowExit().AllowLlvmCoverage();
231   return builder.BuildOrDie();
232 }
233 
234 // Test that we can sandbox a minimal static binary returning 0.
235 // If this starts failing, it means something changed, maybe in the way we
236 // compile static binaries, and we need to update the policy just above.
TEST(MinimalTest,MinimalBinaryWorks)237 TEST(MinimalTest, MinimalBinaryWorks) {
238   SKIP_SANITIZERS;
239   const std::string path = GetTestSourcePath("sandbox2/testcases/minimal");
240   std::vector<std::string> args = {path};
241   Sandbox2 s2(std::make_unique<Executor>(path, args),
242               MinimalTestcasePolicy(path));
243   auto result = s2.Run();
244 
245   ASSERT_THAT(result.final_status(), Eq(Result::OK));
246   EXPECT_THAT(result.reason_code(), Eq(EXIT_SUCCESS));
247 }
248 
249 // Test that we can sandbox a minimal non-static binary returning 0.
TEST(MinimalTest,MinimalSharedBinaryWorks)250 TEST(MinimalTest, MinimalSharedBinaryWorks) {
251   SKIP_SANITIZERS;
252   const std::string path =
253       GetTestSourcePath("sandbox2/testcases/minimal_dynamic");
254   std::vector<std::string> args = {path};
255 
256   PolicyBuilder builder;
257   builder.AddLibrariesForBinary(path)
258       .AllowDynamicStartup()
259       .AllowExit()
260       .AllowLlvmCoverage();
261   auto policy = builder.BuildOrDie();
262 
263   Sandbox2 s2(std::make_unique<Executor>(path, args), std::move(policy));
264   auto result = s2.Run();
265 
266   ASSERT_THAT(result.final_status(), Eq(Result::OK));
267   EXPECT_THAT(result.reason_code(), Eq(EXIT_SUCCESS));
268 }
269 
270 // Test that the AllowSystemMalloc helper works as expected.
TEST(MallocTest,SystemMallocWorks)271 TEST(MallocTest, SystemMallocWorks) {
272   SKIP_SANITIZERS;
273   const std::string path =
274       GetTestSourcePath("sandbox2/testcases/malloc_system");
275   std::vector<std::string> args = {path};
276 
277   PolicyBuilder builder;
278   builder.AllowStaticStartup()
279       .AllowSystemMalloc()
280       .AllowExit()
281       .AllowLlvmCoverage();
282   auto policy = builder.BuildOrDie();
283 
284   Sandbox2 s2(std::make_unique<Executor>(path, args), std::move(policy));
285   auto result = s2.Run();
286 
287   ASSERT_THAT(result.final_status(), Eq(Result::OK));
288   EXPECT_THAT(result.reason_code(), Eq(EXIT_SUCCESS));
289 }
290 
291 // Complicated test to see that AddPolicyOnSyscalls work as
292 // expected. Specifically a worrisome corner-case would be that the logic was
293 // almost correct, but that the jump targets were off slightly. This uses the
294 // AddPolicyOnSyscall multiple times in a row to make any miscalculation
295 // unlikely to pass this check.
TEST(MultipleSyscalls,AddPolicyOnSyscallsWorks)296 TEST(MultipleSyscalls, AddPolicyOnSyscallsWorks) {
297   SKIP_SANITIZERS_AND_COVERAGE;
298   const std::string path =
299       GetTestSourcePath("sandbox2/testcases/add_policy_on_syscalls");
300   std::vector<std::string> args = {path};
301 
302   PolicyBuilder builder;
303   builder.AllowStaticStartup()
304       .AllowTcMalloc()
305       .AllowExit()
306       .AddPolicyOnSyscalls(
307           {
308               __NR_getuid,
309               __NR_getgid,
310               __NR_geteuid,
311               __NR_getegid,
312 #ifdef __NR_getuid32
313               __NR_getuid32,
314 #endif
315 #ifdef __NR_getgid32
316               __NR_getgid32,
317 #endif
318 #ifdef __NR_geteuid32
319               __NR_geteuid32,
320 #endif
321 #ifdef __NR_getegid32
322               __NR_getegid32,
323 #endif
324           },
325           {ALLOW})
326       .AddPolicyOnSyscalls(
327           {
328               __NR_getresuid,
329               __NR_getresgid,
330 #ifdef __NR_getresuid32
331               __NR_getresuid32,
332 #endif
333 #ifdef __NR_getresgid32
334               __NR_getresgid32,
335 #endif
336           },
337           {ERRNO(42)})
338       .AddPolicyOnSyscalls({__NR_write}, {ERRNO(43)})
339       .AddPolicyOnSyscall(__NR_umask, {DENY});
340   auto policy = builder.BuildOrDie();
341 
342   Sandbox2 s2(std::make_unique<Executor>(path, args), std::move(policy));
343   auto result = s2.Run();
344 
345   ASSERT_THAT(result.final_status(), Eq(Result::VIOLATION));
346   EXPECT_THAT(result.reason_code(), Eq(__NR_umask));
347 }
348 
349 // Test that util::kMagicSyscallNo is returns ENOSYS or util::kMagicSyscallErr.
TEST(PolicyTest,DetectSandboxSyscall)350 TEST(PolicyTest, DetectSandboxSyscall) {
351   const std::string path =
352       GetTestSourcePath("sandbox2/testcases/sandbox_detection");
353   std::vector<std::string> args = {path};
354 
355   SAPI_ASSERT_OK_AND_ASSIGN(auto policy,
356                             CreateDefaultPermissiveTestPolicy(path).TryBuild());
357   auto executor = std::make_unique<Executor>(path, args);
358   executor->set_enable_sandbox_before_exec(false);
359   Sandbox2 s2(std::move(executor), std::move(policy));
360   auto result = s2.Run();
361 
362   // The test binary should exit with success.
363   ASSERT_THAT(result.final_status(), Eq(Result::OK));
364   EXPECT_THAT(result.reason_code(), Eq(0));
365 }
366 
367 }  // namespace
368 }  // namespace sandbox2
369