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