1*ec63e07aSXin Li // Copyright 2019 Google LLC
2*ec63e07aSXin Li //
3*ec63e07aSXin Li // Licensed under the Apache License, Version 2.0 (the "License");
4*ec63e07aSXin Li // you may not use this file except in compliance with the License.
5*ec63e07aSXin Li // You may obtain a copy of the License at
6*ec63e07aSXin Li //
7*ec63e07aSXin Li // https://www.apache.org/licenses/LICENSE-2.0
8*ec63e07aSXin Li //
9*ec63e07aSXin Li // Unless required by applicable law or agreed to in writing, software
10*ec63e07aSXin Li // distributed under the License is distributed on an "AS IS" BASIS,
11*ec63e07aSXin Li // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*ec63e07aSXin Li // See the License for the specific language governing permissions and
13*ec63e07aSXin Li // limitations under the License.
14*ec63e07aSXin Li
15*ec63e07aSXin Li #include "sandboxed_api/sandbox2/policy.h"
16*ec63e07aSXin Li
17*ec63e07aSXin Li #include <syscall.h>
18*ec63e07aSXin Li
19*ec63e07aSXin Li #include <cerrno>
20*ec63e07aSXin Li #include <cstdlib>
21*ec63e07aSXin Li #include <memory>
22*ec63e07aSXin Li #include <string>
23*ec63e07aSXin Li #include <utility>
24*ec63e07aSXin Li #include <vector>
25*ec63e07aSXin Li
26*ec63e07aSXin Li #include "gmock/gmock.h"
27*ec63e07aSXin Li #include "gtest/gtest.h"
28*ec63e07aSXin Li #include "absl/strings/string_view.h"
29*ec63e07aSXin Li #include "sandboxed_api/config.h"
30*ec63e07aSXin Li #include "sandboxed_api/sandbox2/executor.h"
31*ec63e07aSXin Li #include "sandboxed_api/sandbox2/policybuilder.h"
32*ec63e07aSXin Li #include "sandboxed_api/sandbox2/result.h"
33*ec63e07aSXin Li #include "sandboxed_api/sandbox2/sandbox2.h"
34*ec63e07aSXin Li #include "sandboxed_api/sandbox2/util/bpf_helper.h"
35*ec63e07aSXin Li #include "sandboxed_api/testing.h"
36*ec63e07aSXin Li #include "sandboxed_api/util/status_matchers.h"
37*ec63e07aSXin Li
38*ec63e07aSXin Li namespace sandbox2 {
39*ec63e07aSXin Li namespace {
40*ec63e07aSXin Li
41*ec63e07aSXin Li using ::sapi::CreateDefaultPermissiveTestPolicy;
42*ec63e07aSXin Li using ::sapi::GetTestSourcePath;
43*ec63e07aSXin Li using ::testing::Eq;
44*ec63e07aSXin Li
45*ec63e07aSXin Li #ifdef SAPI_X86_64
46*ec63e07aSXin Li // Test that 32-bit syscalls from 64-bit are disallowed.
TEST(PolicyTest,AMD64Syscall32PolicyAllowed)47*ec63e07aSXin Li TEST(PolicyTest, AMD64Syscall32PolicyAllowed) {
48*ec63e07aSXin Li SKIP_ANDROID;
49*ec63e07aSXin Li const std::string path = GetTestSourcePath("sandbox2/testcases/policy");
50*ec63e07aSXin Li
51*ec63e07aSXin Li std::vector<std::string> args = {path, "1"};
52*ec63e07aSXin Li
53*ec63e07aSXin Li SAPI_ASSERT_OK_AND_ASSIGN(auto policy,
54*ec63e07aSXin Li CreateDefaultPermissiveTestPolicy(path).TryBuild());
55*ec63e07aSXin Li Sandbox2 s2(std::make_unique<Executor>(path, args), std::move(policy));
56*ec63e07aSXin Li auto result = s2.Run();
57*ec63e07aSXin Li
58*ec63e07aSXin Li ASSERT_THAT(result.final_status(), Eq(Result::VIOLATION));
59*ec63e07aSXin Li EXPECT_THAT(result.reason_code(), Eq(1)); // __NR_exit in 32-bit
60*ec63e07aSXin Li EXPECT_THAT(result.GetSyscallArch(), Eq(sapi::cpu::kX86));
61*ec63e07aSXin Li }
62*ec63e07aSXin Li
63*ec63e07aSXin Li // Test that 32-bit syscalls from 64-bit for FS checks are disallowed.
TEST(PolicyTest,AMD64Syscall32FsAllowed)64*ec63e07aSXin Li TEST(PolicyTest, AMD64Syscall32FsAllowed) {
65*ec63e07aSXin Li SKIP_ANDROID;
66*ec63e07aSXin Li const std::string path = GetTestSourcePath("sandbox2/testcases/policy");
67*ec63e07aSXin Li std::vector<std::string> args = {path, "2"};
68*ec63e07aSXin Li
69*ec63e07aSXin Li SAPI_ASSERT_OK_AND_ASSIGN(auto policy,
70*ec63e07aSXin Li CreateDefaultPermissiveTestPolicy(path).TryBuild());
71*ec63e07aSXin Li Sandbox2 s2(std::make_unique<Executor>(path, args), std::move(policy));
72*ec63e07aSXin Li auto result = s2.Run();
73*ec63e07aSXin Li
74*ec63e07aSXin Li ASSERT_THAT(result.final_status(), Eq(Result::VIOLATION));
75*ec63e07aSXin Li EXPECT_THAT(result.reason_code(),
76*ec63e07aSXin Li Eq(33)); // __NR_access in 32-bit
77*ec63e07aSXin Li EXPECT_THAT(result.GetSyscallArch(), Eq(sapi::cpu::kX86));
78*ec63e07aSXin Li }
79*ec63e07aSXin Li #endif
80*ec63e07aSXin Li
81*ec63e07aSXin Li // Test that ptrace(2) is disallowed.
TEST(PolicyTest,PtraceDisallowed)82*ec63e07aSXin Li TEST(PolicyTest, PtraceDisallowed) {
83*ec63e07aSXin Li const std::string path = GetTestSourcePath("sandbox2/testcases/policy");
84*ec63e07aSXin Li std::vector<std::string> args = {path, "3"};
85*ec63e07aSXin Li
86*ec63e07aSXin Li SAPI_ASSERT_OK_AND_ASSIGN(auto policy,
87*ec63e07aSXin Li CreateDefaultPermissiveTestPolicy(path).TryBuild());
88*ec63e07aSXin Li Sandbox2 s2(std::make_unique<Executor>(path, args), std::move(policy));
89*ec63e07aSXin Li auto result = s2.Run();
90*ec63e07aSXin Li
91*ec63e07aSXin Li ASSERT_THAT(result.final_status(), Eq(Result::VIOLATION));
92*ec63e07aSXin Li EXPECT_THAT(result.reason_code(), Eq(__NR_ptrace));
93*ec63e07aSXin Li }
94*ec63e07aSXin Li
95*ec63e07aSXin Li // Test that clone(2) with flag CLONE_UNTRACED is disallowed.
TEST(PolicyTest,CloneUntracedDisallowed)96*ec63e07aSXin Li TEST(PolicyTest, CloneUntracedDisallowed) {
97*ec63e07aSXin Li const std::string path = GetTestSourcePath("sandbox2/testcases/policy");
98*ec63e07aSXin Li std::vector<std::string> args = {path, "4"};
99*ec63e07aSXin Li SAPI_ASSERT_OK_AND_ASSIGN(auto policy,
100*ec63e07aSXin Li CreateDefaultPermissiveTestPolicy(path).TryBuild());
101*ec63e07aSXin Li Sandbox2 s2(std::make_unique<Executor>(path, args), std::move(policy));
102*ec63e07aSXin Li auto result = s2.Run();
103*ec63e07aSXin Li
104*ec63e07aSXin Li ASSERT_THAT(result.final_status(), Eq(Result::VIOLATION));
105*ec63e07aSXin Li EXPECT_THAT(result.reason_code(), Eq(__NR_clone));
106*ec63e07aSXin Li }
107*ec63e07aSXin Li
108*ec63e07aSXin Li // Test that bpf(2) is disallowed.
TEST(PolicyTest,BpfDisallowed)109*ec63e07aSXin Li TEST(PolicyTest, BpfDisallowed) {
110*ec63e07aSXin Li const std::string path = GetTestSourcePath("sandbox2/testcases/policy");
111*ec63e07aSXin Li std::vector<std::string> args = {path, "5"};
112*ec63e07aSXin Li SAPI_ASSERT_OK_AND_ASSIGN(auto policy,
113*ec63e07aSXin Li CreateDefaultPermissiveTestPolicy(path).TryBuild());
114*ec63e07aSXin Li Sandbox2 s2(std::make_unique<Executor>(path, args), std::move(policy));
115*ec63e07aSXin Li auto result = s2.Run();
116*ec63e07aSXin Li
117*ec63e07aSXin Li ASSERT_THAT(result.final_status(), Eq(Result::VIOLATION));
118*ec63e07aSXin Li EXPECT_THAT(result.reason_code(), Eq(__NR_bpf));
119*ec63e07aSXin Li }
120*ec63e07aSXin Li
121*ec63e07aSXin Li // Test that ptrace/bpf can return EPERM.
TEST(PolicyTest,BpfPtracePermissionDenied)122*ec63e07aSXin Li TEST(PolicyTest, BpfPtracePermissionDenied) {
123*ec63e07aSXin Li const std::string path = GetTestSourcePath("sandbox2/testcases/policy");
124*ec63e07aSXin Li std::vector<std::string> args = {path, "7"};
125*ec63e07aSXin Li
126*ec63e07aSXin Li SAPI_ASSERT_OK_AND_ASSIGN(
127*ec63e07aSXin Li auto policy, CreateDefaultPermissiveTestPolicy(path)
128*ec63e07aSXin Li .BlockSyscallsWithErrno({__NR_ptrace, __NR_bpf}, EPERM)
129*ec63e07aSXin Li .TryBuild());
130*ec63e07aSXin Li Sandbox2 s2(std::make_unique<Executor>(path, args), std::move(policy));
131*ec63e07aSXin Li auto result = s2.Run();
132*ec63e07aSXin Li
133*ec63e07aSXin Li // ptrace/bpf is not a violation due to explicit policy. EPERM is expected.
134*ec63e07aSXin Li ASSERT_THAT(result.final_status(), Eq(Result::OK));
135*ec63e07aSXin Li EXPECT_THAT(result.reason_code(), Eq(0));
136*ec63e07aSXin Li }
137*ec63e07aSXin Li
TEST(PolicyTest,IsattyAllowed)138*ec63e07aSXin Li TEST(PolicyTest, IsattyAllowed) {
139*ec63e07aSXin Li SKIP_SANITIZERS;
140*ec63e07aSXin Li PolicyBuilder builder;
141*ec63e07aSXin Li if constexpr (sapi::host_os::IsAndroid()) {
142*ec63e07aSXin Li builder.DisableNamespaces().AllowDynamicStartup();
143*ec63e07aSXin Li }
144*ec63e07aSXin Li builder.AllowStaticStartup()
145*ec63e07aSXin Li .AllowExit()
146*ec63e07aSXin Li .AllowRead()
147*ec63e07aSXin Li .AllowWrite()
148*ec63e07aSXin Li .AllowTCGETS()
149*ec63e07aSXin Li .AllowLlvmCoverage();
150*ec63e07aSXin Li const std::string path = GetTestSourcePath("sandbox2/testcases/policy");
151*ec63e07aSXin Li std::vector<std::string> args = {path, "6"};
152*ec63e07aSXin Li SAPI_ASSERT_OK_AND_ASSIGN(auto policy, builder.TryBuild());
153*ec63e07aSXin Li Sandbox2 s2(std::make_unique<Executor>(path, args), std::move(policy));
154*ec63e07aSXin Li auto result = s2.Run();
155*ec63e07aSXin Li
156*ec63e07aSXin Li ASSERT_THAT(result.final_status(), Eq(Result::OK));
157*ec63e07aSXin Li }
158*ec63e07aSXin Li
MinimalTestcasePolicy(absl::string_view path="")159*ec63e07aSXin Li std::unique_ptr<Policy> MinimalTestcasePolicy(absl::string_view path = "") {
160*ec63e07aSXin Li PolicyBuilder builder;
161*ec63e07aSXin Li
162*ec63e07aSXin Li if constexpr (sapi::host_os::IsAndroid()) {
163*ec63e07aSXin Li builder.AllowDynamicStartup();
164*ec63e07aSXin Li builder.DisableNamespaces();
165*ec63e07aSXin Li }
166*ec63e07aSXin Li
167*ec63e07aSXin Li builder.AllowStaticStartup().AllowExit().AllowLlvmCoverage();
168*ec63e07aSXin Li return builder.BuildOrDie();
169*ec63e07aSXin Li }
170*ec63e07aSXin Li
171*ec63e07aSXin Li // Test that we can sandbox a minimal static binary returning 0.
172*ec63e07aSXin Li // If this starts failing, it means something changed, maybe in the way we
173*ec63e07aSXin Li // compile static binaries, and we need to update the policy just above.
TEST(MinimalTest,MinimalBinaryWorks)174*ec63e07aSXin Li TEST(MinimalTest, MinimalBinaryWorks) {
175*ec63e07aSXin Li SKIP_ANDROID;
176*ec63e07aSXin Li SKIP_SANITIZERS;
177*ec63e07aSXin Li const std::string path = GetTestSourcePath("sandbox2/testcases/minimal");
178*ec63e07aSXin Li std::vector<std::string> args = {path};
179*ec63e07aSXin Li Sandbox2 s2(std::make_unique<Executor>(path, args),
180*ec63e07aSXin Li MinimalTestcasePolicy(path));
181*ec63e07aSXin Li auto result = s2.Run();
182*ec63e07aSXin Li
183*ec63e07aSXin Li ASSERT_THAT(result.final_status(), Eq(Result::OK));
184*ec63e07aSXin Li EXPECT_THAT(result.reason_code(), Eq(EXIT_SUCCESS));
185*ec63e07aSXin Li }
186*ec63e07aSXin Li
187*ec63e07aSXin Li // Test that we can sandbox a minimal non-static binary returning 0.
TEST(MinimalTest,MinimalSharedBinaryWorks)188*ec63e07aSXin Li TEST(MinimalTest, MinimalSharedBinaryWorks) {
189*ec63e07aSXin Li SKIP_SANITIZERS;
190*ec63e07aSXin Li const std::string path =
191*ec63e07aSXin Li GetTestSourcePath("sandbox2/testcases/minimal_dynamic");
192*ec63e07aSXin Li std::vector<std::string> args = {path};
193*ec63e07aSXin Li
194*ec63e07aSXin Li PolicyBuilder builder;
195*ec63e07aSXin Li
196*ec63e07aSXin Li if constexpr (sapi::host_os::IsAndroid()) {
197*ec63e07aSXin Li builder.DisableNamespaces();
198*ec63e07aSXin Li } else {
199*ec63e07aSXin Li builder.AddLibrariesForBinary(path);
200*ec63e07aSXin Li }
201*ec63e07aSXin Li
202*ec63e07aSXin Li builder.AllowDynamicStartup().AllowExit().AllowLlvmCoverage();
203*ec63e07aSXin Li auto policy = builder.BuildOrDie();
204*ec63e07aSXin Li
205*ec63e07aSXin Li Sandbox2 s2(std::make_unique<Executor>(path, args), std::move(policy));
206*ec63e07aSXin Li auto result = s2.Run();
207*ec63e07aSXin Li
208*ec63e07aSXin Li ASSERT_THAT(result.final_status(), Eq(Result::OK));
209*ec63e07aSXin Li EXPECT_THAT(result.reason_code(), Eq(EXIT_SUCCESS));
210*ec63e07aSXin Li }
211*ec63e07aSXin Li
212*ec63e07aSXin Li // Test that the AllowSystemMalloc helper works as expected.
TEST(MallocTest,SystemMallocWorks)213*ec63e07aSXin Li TEST(MallocTest, SystemMallocWorks) {
214*ec63e07aSXin Li SKIP_SANITIZERS;
215*ec63e07aSXin Li const std::string path =
216*ec63e07aSXin Li GetTestSourcePath("sandbox2/testcases/malloc_system");
217*ec63e07aSXin Li std::vector<std::string> args = {path};
218*ec63e07aSXin Li
219*ec63e07aSXin Li PolicyBuilder builder;
220*ec63e07aSXin Li
221*ec63e07aSXin Li if constexpr (sapi::host_os::IsAndroid()) {
222*ec63e07aSXin Li builder.DisableNamespaces();
223*ec63e07aSXin Li builder.AllowDynamicStartup();
224*ec63e07aSXin Li builder.AllowSyscalls({
225*ec63e07aSXin Li __NR_madvise,
226*ec63e07aSXin Li });
227*ec63e07aSXin Li }
228*ec63e07aSXin Li
229*ec63e07aSXin Li builder.AllowStaticStartup()
230*ec63e07aSXin Li .AllowSystemMalloc()
231*ec63e07aSXin Li .AllowExit()
232*ec63e07aSXin Li .AllowLlvmCoverage();
233*ec63e07aSXin Li auto policy = builder.BuildOrDie();
234*ec63e07aSXin Li
235*ec63e07aSXin Li Sandbox2 s2(std::make_unique<Executor>(path, args), std::move(policy));
236*ec63e07aSXin Li auto result = s2.Run();
237*ec63e07aSXin Li
238*ec63e07aSXin Li ASSERT_THAT(result.final_status(), Eq(Result::OK));
239*ec63e07aSXin Li EXPECT_THAT(result.reason_code(), Eq(EXIT_SUCCESS));
240*ec63e07aSXin Li }
241*ec63e07aSXin Li
242*ec63e07aSXin Li // Complicated test to see that AddPolicyOnSyscalls work as
243*ec63e07aSXin Li // expected. Specifically a worrisome corner-case would be that the logic was
244*ec63e07aSXin Li // almost correct, but that the jump targets were off slightly. This uses the
245*ec63e07aSXin Li // AddPolicyOnSyscall multiple times in a row to make any miscalculation
246*ec63e07aSXin Li // unlikely to pass this check.
TEST(MultipleSyscalls,AddPolicyOnSyscallsWorks)247*ec63e07aSXin Li TEST(MultipleSyscalls, AddPolicyOnSyscallsWorks) {
248*ec63e07aSXin Li SKIP_SANITIZERS_AND_COVERAGE;
249*ec63e07aSXin Li const std::string path =
250*ec63e07aSXin Li GetTestSourcePath("sandbox2/testcases/add_policy_on_syscalls");
251*ec63e07aSXin Li std::vector<std::string> args = {path};
252*ec63e07aSXin Li
253*ec63e07aSXin Li PolicyBuilder builder;
254*ec63e07aSXin Li if constexpr (sapi::host_os::IsAndroid()) {
255*ec63e07aSXin Li builder.DisableNamespaces();
256*ec63e07aSXin Li builder.AllowDynamicStartup();
257*ec63e07aSXin Li }
258*ec63e07aSXin Li
259*ec63e07aSXin Li builder.AllowStaticStartup()
260*ec63e07aSXin Li .AllowTcMalloc()
261*ec63e07aSXin Li .AllowExit()
262*ec63e07aSXin Li .AddPolicyOnSyscalls(
263*ec63e07aSXin Li {
264*ec63e07aSXin Li __NR_getuid,
265*ec63e07aSXin Li __NR_getgid,
266*ec63e07aSXin Li __NR_geteuid,
267*ec63e07aSXin Li __NR_getegid,
268*ec63e07aSXin Li #ifdef __NR_getuid32
269*ec63e07aSXin Li __NR_getuid32,
270*ec63e07aSXin Li #endif
271*ec63e07aSXin Li #ifdef __NR_getgid32
272*ec63e07aSXin Li __NR_getgid32,
273*ec63e07aSXin Li #endif
274*ec63e07aSXin Li #ifdef __NR_geteuid32
275*ec63e07aSXin Li __NR_geteuid32,
276*ec63e07aSXin Li #endif
277*ec63e07aSXin Li #ifdef __NR_getegid32
278*ec63e07aSXin Li __NR_getegid32,
279*ec63e07aSXin Li #endif
280*ec63e07aSXin Li },
281*ec63e07aSXin Li {ALLOW})
282*ec63e07aSXin Li .AddPolicyOnSyscalls(
283*ec63e07aSXin Li {
284*ec63e07aSXin Li __NR_getresuid,
285*ec63e07aSXin Li __NR_getresgid,
286*ec63e07aSXin Li #ifdef __NR_getresuid32
287*ec63e07aSXin Li __NR_getresuid32,
288*ec63e07aSXin Li #endif
289*ec63e07aSXin Li #ifdef __NR_getresgid32
290*ec63e07aSXin Li __NR_getresgid32,
291*ec63e07aSXin Li #endif
292*ec63e07aSXin Li },
293*ec63e07aSXin Li {ERRNO(42)})
294*ec63e07aSXin Li .AddPolicyOnSyscalls({__NR_write}, {ERRNO(43)})
295*ec63e07aSXin Li .AddPolicyOnSyscall(__NR_umask, {DENY});
296*ec63e07aSXin Li auto policy = builder.BuildOrDie();
297*ec63e07aSXin Li
298*ec63e07aSXin Li Sandbox2 s2(std::make_unique<Executor>(path, args), std::move(policy));
299*ec63e07aSXin Li auto result = s2.Run();
300*ec63e07aSXin Li
301*ec63e07aSXin Li ASSERT_THAT(result.final_status(), Eq(Result::VIOLATION));
302*ec63e07aSXin Li EXPECT_THAT(result.reason_code(), Eq(__NR_umask));
303*ec63e07aSXin Li }
304*ec63e07aSXin Li
305*ec63e07aSXin Li } // namespace
306*ec63e07aSXin Li } // namespace sandbox2
307