xref: /aosp_15_r20/external/sandboxed-api/sandboxed_api/sandbox2/notify_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/notify.h"
16 
17 #include <sys/types.h>
18 #include <syscall.h>
19 
20 #include <memory>
21 #include <string>
22 #include <utility>
23 #include <vector>
24 
25 #include "gmock/gmock.h"
26 #include "gtest/gtest.h"
27 #include "absl/log/log.h"
28 #include "absl/strings/str_join.h"
29 #include "absl/strings/string_view.h"
30 #include "sandboxed_api/sandbox2/comms.h"
31 #include "sandboxed_api/sandbox2/executor.h"
32 #include "sandboxed_api/sandbox2/policy.h"
33 #include "sandboxed_api/sandbox2/policybuilder.h"
34 #include "sandboxed_api/sandbox2/sandbox2.h"
35 #include "sandboxed_api/sandbox2/syscall.h"
36 #include "sandboxed_api/sandbox2/trace_all_syscalls.h"
37 #include "sandboxed_api/testing.h"
38 
39 namespace sandbox2 {
40 namespace {
41 
42 using ::sapi::CreateDefaultPermissiveTestPolicy;
43 using ::sapi::GetTestSourcePath;
44 using ::testing::Eq;
45 
46 // Allow typical syscalls and call SECCOMP_RET_TRACE for personality syscall,
47 // chosen because unlikely to be called by a regular program.
NotifyTestcasePolicy(absl::string_view path)48 std::unique_ptr<Policy> NotifyTestcasePolicy(absl::string_view path) {
49   return CreateDefaultPermissiveTestPolicy(path)
50       .AddPolicyOnSyscall(__NR_personality, {SANDBOX2_TRACE})
51       .BuildOrDie();
52 }
53 
54 // If syscall and its arguments don't match the expected ones, return the
55 // opposite of the requested values (allow/disallow) to indicate an error.
56 class PersonalityNotify : public Notify {
57  public:
PersonalityNotify(bool allow)58   explicit PersonalityNotify(bool allow) : allow_(allow) {}
59 
EventSyscallTrap(const Syscall & syscall)60   bool EventSyscallTrap(const Syscall& syscall) override {
61     if (syscall.nr() != __NR_personality) {
62       LOG(ERROR) << "kSyscall==" << syscall.nr();
63       return (!allow_);
64     }
65     Syscall::Args expected_args = {0x1, 0x2, 0x3, 0x4, 0x5, 0x6};
66     if (syscall.args() != expected_args) {
67       LOG(ERROR) << "args=={" << absl::StrJoin(syscall.args(), ", ") << "}";
68       return (!allow_);
69     }
70     return allow_;
71   }
72 
73  private:
74   // The intended return value from EventSyscallTrap in case all registers
75   // match.
76   bool allow_;
77 };
78 
79 // Print the newly created PID, and exchange data over Comms before sandboxing.
80 class PidCommsNotify : public Notify {
81  public:
EventStarted(pid_t pid,Comms * comms)82   bool EventStarted(pid_t pid, Comms* comms) final {
83     LOG(INFO) << "The newly created PID: " << pid;
84     bool v;
85     return comms->RecvBool(&v);
86   }
87 };
88 
89 // Test EventSyscallTrap on personality syscall and allow it.
TEST(NotifyTest,AllowPersonality)90 TEST(NotifyTest, AllowPersonality) {
91   const std::string path = GetTestSourcePath("sandbox2/testcases/personality");
92   std::vector<std::string> args = {path};
93   Sandbox2 s2(std::make_unique<Executor>(path, args),
94               NotifyTestcasePolicy(path),
95               std::make_unique<PersonalityNotify>(/*allow=*/true));
96   auto result = s2.Run();
97 
98   ASSERT_THAT(result.final_status(), Eq(Result::OK));
99   EXPECT_THAT(result.reason_code(), Eq(22));
100 }
101 
102 // Test EventSyscallTrap on personality syscall and disallow it.
TEST(NotifyTest,DisallowPersonality)103 TEST(NotifyTest, DisallowPersonality) {
104   const std::string path = GetTestSourcePath("sandbox2/testcases/personality");
105   std::vector<std::string> args = {path};
106   Sandbox2 s2(std::make_unique<Executor>(path, args),
107               NotifyTestcasePolicy(path),
108               std::make_unique<PersonalityNotify>(/*allow=*/false));
109   auto result = s2.Run();
110 
111   ASSERT_THAT(result.final_status(), Eq(Result::VIOLATION));
112   EXPECT_THAT(result.reason_code(), Eq(__NR_personality));
113 }
114 
115 // Test EventStarted by exchanging data after started but before sandboxed.
TEST(NotifyTest,PrintPidAndComms)116 TEST(NotifyTest, PrintPidAndComms) {
117   const std::string path = GetTestSourcePath("sandbox2/testcases/pidcomms");
118   std::vector<std::string> args = {path};
119   auto executor = std::make_unique<Executor>(path, args);
120   executor->set_enable_sandbox_before_exec(false);
121 
122   Sandbox2 s2(std::move(executor), NotifyTestcasePolicy(path),
123               std::make_unique<PidCommsNotify>());
124   auto result = s2.Run();
125 
126   ASSERT_THAT(result.final_status(), Eq(Result::OK));
127   EXPECT_THAT(result.reason_code(), Eq(33));
128 }
129 
130 // Test EventSyscallTrap on personality syscall through TraceAllSyscalls
TEST(NotifyTest,TraceAllAllowPersonality)131 TEST(NotifyTest, TraceAllAllowPersonality) {
132   const std::string path = GetTestSourcePath("sandbox2/testcases/personality");
133   std::vector<std::string> args = {path};
134   auto policy = CreateDefaultPermissiveTestPolicy(path)
135                     .DefaultAction(TraceAllSyscalls())
136                     .BuildOrDie();
137   Sandbox2 s2(std::make_unique<Executor>(path, args),
138               NotifyTestcasePolicy(path),
139               std::make_unique<PersonalityNotify>(/*allow=*/true));
140   auto result = s2.Run();
141 
142   ASSERT_THAT(result.final_status(), Eq(Result::OK));
143   EXPECT_THAT(result.reason_code(), Eq(22));
144 }
145 
146 }  // namespace
147 }  // namespace sandbox2
148