xref: /aosp_15_r20/external/sandboxed-api/sandboxed_api/sandbox2/policybuilder_test.cc (revision ec63e07ab9515d95e79c211197c445ef84cefa6a)
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/policybuilder.h"
16 
17 #include <syscall.h>
18 #include <unistd.h>
19 
20 #include <cerrno>
21 #include <memory>
22 #include <string>
23 #include <vector>
24 
25 #include "gmock/gmock.h"
26 #include "gtest/gtest.h"
27 #include "absl/status/status.h"
28 #include "absl/status/statusor.h"
29 #include "absl/strings/string_view.h"
30 #include "sandboxed_api/sandbox2/policy.h"
31 #include "sandboxed_api/sandbox2/util/bpf_helper.h"
32 #include "sandboxed_api/sandbox2/violation.pb.h"
33 #include "sandboxed_api/util/status_matchers.h"
34 
35 namespace sandbox2 {
36 
37 class PolicyBuilderPeer {
38  public:
PolicyBuilderPeer(PolicyBuilder * builder)39   explicit PolicyBuilderPeer(PolicyBuilder* builder) : builder_{builder} {}
40 
policy_size() const41   int policy_size() const { return builder_->user_policy_.size(); }
42 
ValidateAbsolutePath(absl::string_view path)43   static absl::StatusOr<std::string> ValidateAbsolutePath(
44       absl::string_view path) {
45     return PolicyBuilder::ValidateAbsolutePath(path);
46   }
47 
48  private:
49   PolicyBuilder* builder_;
50 };
51 
52 namespace {
53 
54 using ::sapi::IsOk;
55 using ::sapi::StatusIs;
56 using ::testing::Eq;
57 using ::testing::Lt;
58 using ::testing::StartsWith;
59 using ::testing::StrEq;
60 
TEST(PolicyBuilderTest,Testpolicy_size)61 TEST(PolicyBuilderTest, Testpolicy_size) {
62   ssize_t last_size = 0;
63   PolicyBuilder builder;
64   PolicyBuilderPeer builder_peer{&builder};
65 
66   auto assert_increased = [&last_size, &builder_peer]() {
67     ASSERT_THAT(last_size, Lt(builder_peer.policy_size()));
68     last_size = builder_peer.policy_size();
69   };
70 
71   auto assert_same = [&last_size, &builder_peer]() {
72     ASSERT_THAT(last_size, Eq(builder_peer.policy_size()));
73   };
74 
75   // clang-format off
76   assert_same();
77 
78   builder.AllowSyscall(__NR_chroot); assert_increased();
79   builder.AllowSyscall(__NR_chroot); assert_same();
80   builder.AllowSyscall(__NR_umask); assert_increased();
81   builder.AllowSyscall(__NR_umask); assert_same();
82   builder.AllowSyscall(__NR_chroot); assert_same();
83   builder.AllowSyscall(__NR_chroot); assert_same();
84 
85   builder.AllowSystemMalloc(); assert_increased();
86   builder.AllowSyscall(__NR_munmap); assert_same();
87   builder.BlockSyscallWithErrno(__NR_munmap, 1); assert_same();
88   builder.BlockSyscallWithErrno(__NR_openat, 1);
89   assert_increased();
90 
91   builder.AllowTCGETS(); assert_increased();
92   builder.AllowTCGETS(); assert_increased();
93   builder.AllowTCGETS(); assert_increased();
94 
95   builder.AddPolicyOnSyscall(__NR_fchmod, { ALLOW }); assert_increased();
96   builder.AddPolicyOnSyscall(__NR_fchmod, { ALLOW }); assert_increased();
97 
98   builder.AddPolicyOnSyscalls({ __NR_fchmod, __NR_chdir }, { ALLOW });
99   assert_increased();
100   builder.AddPolicyOnSyscalls({ __NR_fchmod, __NR_chdir }, { ALLOW });
101   assert_increased();
102 
103   // This might change in the future if we implement an optimization.
104   builder.AddPolicyOnSyscall(__NR_umask, { ALLOW }); assert_increased();
105   builder.AddPolicyOnSyscall(__NR_umask, { ALLOW }); assert_increased();
106 
107   // None of the namespace functions should alter the seccomp policy.
108   builder.AddFile("/usr/bin/find"); assert_same();
109   builder.AddDirectory("/bin"); assert_same();
110   builder.AddTmpfs("/tmp", /*size=*/4ULL << 20 /* 4 MiB */); assert_same();
111   builder.AllowUnrestrictedNetworking(); assert_same();
112   // clang-format on
113 }
114 
TEST(PolicyBuilderTest,TestValidateAbsolutePath)115 TEST(PolicyBuilderTest, TestValidateAbsolutePath) {
116   for (auto const& bad_path : {
117            "..",
118            "a",
119            "a/b",
120            "a/b/c",
121            "/a/b/c/../d",
122            "/a/b/c/./d",
123            "/a/b/c//d",
124            "/a/b/c/d/",
125            "/a/bAAAAAAAAAAAAAAAAAAAAAA/c/d/",
126        }) {
127     EXPECT_THAT(PolicyBuilderPeer::ValidateAbsolutePath(bad_path),
128                 StatusIs(absl::StatusCode::kInvalidArgument));
129   }
130 
131   for (auto const& good_path :
132        {"/", "/a/b/c/d", "/a/b/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"}) {
133     SAPI_ASSERT_OK_AND_ASSIGN(
134         std::string path, PolicyBuilderPeer::ValidateAbsolutePath(good_path));
135     EXPECT_THAT(path, StrEq(good_path));
136   }
137 }
138 
TEST(PolicyBuilderTest,TestCanOnlyBuildOnce)139 TEST(PolicyBuilderTest, TestCanOnlyBuildOnce) {
140   PolicyBuilder b;
141   ASSERT_THAT(b.TryBuild(), IsOk());
142   EXPECT_THAT(b.TryBuild(), StatusIs(absl::StatusCode::kFailedPrecondition,
143                                      "Can only build policy once."));
144 }
145 
TEST(PolicyBuilderTest,TestIsCopyable)146 TEST(PolicyBuilderTest, TestIsCopyable) {
147   PolicyBuilder builder;
148   builder.AllowSyscall(__NR_getpid);
149 
150   PolicyBuilder copy = builder;
151   ASSERT_EQ(PolicyBuilderPeer(&copy).policy_size(),
152             PolicyBuilderPeer(&builder).policy_size());
153 
154   // Both can be built.
155   EXPECT_THAT(builder.TryBuild(), IsOk());
156   EXPECT_THAT(copy.TryBuild(), IsOk());
157 }
158 
TEST(PolicyBuilderTest,CanBypassPtrace)159 TEST(PolicyBuilderTest, CanBypassPtrace) {
160   PolicyBuilder builder;
161   builder.AddPolicyOnSyscall(__NR_ptrace, {ALLOW})
162       .BlockSyscallWithErrno(__NR_ptrace, ENOENT);
163   EXPECT_THAT(builder.TryBuild(), Not(IsOk()));
164 }
165 
TEST(PolicyBuilderTest,AddPolicyOnSyscallsNoEmptyList)166 TEST(PolicyBuilderTest, AddPolicyOnSyscallsNoEmptyList) {
167   PolicyBuilder builder;
168   builder.AddPolicyOnSyscalls({}, {ALLOW});
169   EXPECT_THAT(builder.TryBuild(), StatusIs(absl::StatusCode::kInvalidArgument));
170 }
171 
TEST(PolicyBuilderTest,AddPolicyOnSyscallJumpOutOfBounds)172 TEST(PolicyBuilderTest, AddPolicyOnSyscallJumpOutOfBounds) {
173   PolicyBuilder builder;
174   builder.AddPolicyOnSyscall(__NR_write,
175                              {BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 1, 2, 0)});
176   EXPECT_THAT(builder.TryBuild(), StatusIs(absl::StatusCode::kInvalidArgument));
177 }
178 }  // namespace
179 }  // namespace sandbox2
180