1 // Copyright 2023 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 <syscall.h>
16
17 #include <cstdlib>
18 #include <memory>
19 #include <string>
20 #include <tuple>
21 #include <utility>
22 #include <vector>
23
24 #include "gmock/gmock.h"
25 #include "gtest/gtest.h"
26 #include "absl/status/status.h"
27 #include "absl/time/time.h"
28 #include "sandboxed_api/sandbox2/executor.h"
29 #include "sandboxed_api/sandbox2/network_proxy/testing.h"
30 #include "sandboxed_api/sandbox2/policybuilder.h"
31 #include "sandboxed_api/sandbox2/result.h"
32 #include "sandboxed_api/sandbox2/sandbox2.h"
33 #include "sandboxed_api/testing.h"
34 #include "sandboxed_api/util/status_matchers.h"
35
36 namespace sandbox2 {
37 namespace {
38
39 using ::sapi::GetTestSourcePath;
40 using ::sapi::StatusIs;
41 using ::testing::Eq;
42
TEST(NetworkProxyTest,NoDoublePolicy)43 TEST(NetworkProxyTest, NoDoublePolicy) {
44 PolicyBuilder builder;
45 builder.AddNetworkProxyHandlerPolicy().AddNetworkProxyPolicy();
46 EXPECT_THAT(builder.TryBuild(),
47 StatusIs(absl::StatusCode::kFailedPrecondition));
48 }
49
TEST(NetworkProxyTest,NoDoublePolicyHandler)50 TEST(NetworkProxyTest, NoDoublePolicyHandler) {
51 PolicyBuilder builder;
52 builder.AddNetworkProxyPolicy().AddNetworkProxyHandlerPolicy();
53 EXPECT_THAT(builder.TryBuild(),
54 StatusIs(absl::StatusCode::kFailedPrecondition));
55 }
56
TEST(NetworkProxyTest,NoNetworkPolicyIpv4)57 TEST(NetworkProxyTest, NoNetworkPolicyIpv4) {
58 PolicyBuilder builder;
59 builder.AllowIPv4("127.0.0.1");
60 EXPECT_THAT(builder.TryBuild(),
61 StatusIs(absl::StatusCode::kFailedPrecondition));
62 }
63
TEST(NetworkProxyTest,NoNetworkPolicyIpv6)64 TEST(NetworkProxyTest, NoNetworkPolicyIpv6) {
65 PolicyBuilder builder;
66 builder.AllowIPv6("::1");
67 EXPECT_THAT(builder.TryBuild(),
68 StatusIs(absl::StatusCode::kFailedPrecondition));
69 }
70
TEST(NetworkProxyTest,WrongIPv4)71 TEST(NetworkProxyTest, WrongIPv4) {
72 PolicyBuilder builder;
73 builder.AddNetworkProxyPolicy().AllowIPv4("256.256.256.256");
74 EXPECT_THAT(builder.TryBuild(), StatusIs(absl::StatusCode::kInvalidArgument));
75 }
76
TEST(NetworkProxyTest,WrongIPv6)77 TEST(NetworkProxyTest, WrongIPv6) {
78 PolicyBuilder builder;
79 builder.AddNetworkProxyPolicy().AllowIPv6("127.0.0.1");
80 EXPECT_THAT(builder.TryBuild(), StatusIs(absl::StatusCode::kInvalidArgument));
81 }
82
83 using NetworkProxyTest = ::testing::TestWithParam<std::tuple<bool, bool>>;
84
TEST_P(NetworkProxyTest,ProxyWithHandlerAllowed)85 TEST_P(NetworkProxyTest, ProxyWithHandlerAllowed) {
86 SKIP_SANITIZERS;
87 const auto [ipv6, use_unotify] = GetParam();
88 const std::string path =
89 GetTestSourcePath("sandbox2/testcases/network_proxy");
90 std::vector<std::string> args = {"network_proxy"};
91 if (ipv6) {
92 args.push_back("--ipv6");
93 }
94 auto executor = std::make_unique<Executor>(path, args);
95 executor->limits()->set_walltime_limit(absl::Seconds(3));
96
97 PolicyBuilder builder;
98 builder.AllowDynamicStartup()
99 .AllowWrite()
100 .AllowRead()
101 .AllowExit()
102 .AllowSyscall(__NR_sendto)
103 .AllowTcMalloc()
104 .AddNetworkProxyHandlerPolicy()
105 .AllowLlvmCoverage()
106 .AddLibrariesForBinary(path);
107
108 if (use_unotify) {
109 builder.CollectStacktracesOnSignal(false);
110 }
111 if (ipv6) {
112 builder.AllowIPv6("::1");
113 } else {
114 builder.AllowIPv4("127.0.0.1");
115 }
116
117 SAPI_ASSERT_OK_AND_ASSIGN(auto policy, builder.TryBuild());
118
119 Sandbox2 s2(std::move(executor), std::move(policy));
120 if (use_unotify) {
121 ASSERT_THAT(s2.EnableUnotifyMonitor(), sapi::IsOk());
122 }
123 ASSERT_TRUE(s2.RunAsync());
124
125 SAPI_ASSERT_OK_AND_ASSIGN(auto server, NetworkProxyTestServer::Start(ipv6));
126 ASSERT_TRUE(s2.comms()->SendInt32(server->port()));
127
128 sandbox2::Result result = s2.AwaitResult();
129 ASSERT_THAT(result.final_status(), Eq(Result::OK));
130 EXPECT_THAT(result.reason_code(), Eq(EXIT_SUCCESS));
131 }
132
TEST_P(NetworkProxyTest,ProxyWithHandlerNotAllowed)133 TEST_P(NetworkProxyTest, ProxyWithHandlerNotAllowed) {
134 SKIP_SANITIZERS;
135 const auto [ipv6, use_unotify] = GetParam();
136 const std::string path =
137 GetTestSourcePath("sandbox2/testcases/network_proxy");
138 std::vector<std::string> args = {"network_proxy"};
139 if (ipv6) {
140 args.push_back("--ipv6");
141 }
142 auto executor = std::make_unique<Executor>(path, args);
143 executor->limits()->set_walltime_limit(absl::Seconds(3));
144
145 PolicyBuilder builder;
146 builder.AllowDynamicStartup()
147 .AllowWrite()
148 .AllowRead()
149 .AllowExit()
150 .AllowSyscall(__NR_sendto)
151 .AllowTcMalloc()
152 .AddNetworkProxyHandlerPolicy()
153 .AllowLlvmCoverage()
154 .AddLibrariesForBinary(path);
155 if (use_unotify) {
156 builder.CollectStacktracesOnSignal(false);
157 }
158 SAPI_ASSERT_OK_AND_ASSIGN(auto policy, builder.TryBuild());
159
160 Sandbox2 s2(std::move(executor), std::move(policy));
161 if (use_unotify) {
162 ASSERT_THAT(s2.EnableUnotifyMonitor(), sapi::IsOk());
163 }
164 ASSERT_TRUE(s2.RunAsync());
165
166 SAPI_ASSERT_OK_AND_ASSIGN(auto server, NetworkProxyTestServer::Start(ipv6));
167 ASSERT_TRUE(s2.comms()->SendInt32(server->port()));
168
169 sandbox2::Result result = s2.AwaitResult();
170 ASSERT_THAT(result.final_status(), Eq(Result::VIOLATION));
171 EXPECT_THAT(result.reason_code(), Eq(Result::VIOLATION_NETWORK));
172 }
173
TEST_P(NetworkProxyTest,ProxyWithoutHandlerAllowed)174 TEST_P(NetworkProxyTest, ProxyWithoutHandlerAllowed) {
175 SKIP_SANITIZERS;
176 const auto [ipv6, use_unotify] = GetParam();
177 const std::string path =
178 GetTestSourcePath("sandbox2/testcases/network_proxy");
179 std::vector<std::string> args = {"network_proxy", "--noconnect_with_handler"};
180 if (ipv6) {
181 args.push_back("--ipv6");
182 }
183 auto executor = std::make_unique<Executor>(path, args);
184 executor->limits()->set_walltime_limit(absl::Seconds(3));
185
186 PolicyBuilder builder;
187 builder.AllowDynamicStartup()
188 .AllowExit()
189 .AllowWrite()
190 .AllowRead()
191 .AllowSyscall(__NR_sendto)
192 .AllowTcMalloc()
193 .AddNetworkProxyHandlerPolicy()
194 .AllowLlvmCoverage()
195 .AddLibrariesForBinary(path);
196 if (use_unotify) {
197 builder.CollectStacktracesOnSignal(false);
198 }
199 if (ipv6) {
200 builder.AllowIPv6("::1");
201 } else {
202 builder.AllowIPv4("127.0.0.1");
203 }
204
205 SAPI_ASSERT_OK_AND_ASSIGN(auto policy, builder.TryBuild());
206
207 Sandbox2 s2(std::move(executor), std::move(policy));
208 if (use_unotify) {
209 ASSERT_THAT(s2.EnableUnotifyMonitor(), sapi::IsOk());
210 }
211 ASSERT_TRUE(s2.RunAsync());
212
213 SAPI_ASSERT_OK_AND_ASSIGN(auto server, NetworkProxyTestServer::Start(ipv6));
214 ASSERT_TRUE(s2.comms()->SendInt32(server->port()));
215
216 sandbox2::Result result = s2.AwaitResult();
217 ASSERT_THAT(result.final_status(), Eq(Result::OK));
218 EXPECT_THAT(result.reason_code(), Eq(EXIT_SUCCESS));
219 }
220
TEST(NetworkProxyTest,ProxyNonExistantAddress)221 TEST(NetworkProxyTest, ProxyNonExistantAddress) {
222 // Creates a IPv6 server tries to connect with IPv4
223 SKIP_SANITIZERS;
224 const std::string path =
225 GetTestSourcePath("sandbox2/testcases/network_proxy");
226 std::vector<std::string> args = {"network_proxy", "--noconnect_with_handler"};
227 auto executor = std::make_unique<Executor>(path, args);
228 executor->limits()->set_walltime_limit(absl::Seconds(3));
229
230 PolicyBuilder builder;
231 builder.AllowDynamicStartup()
232 .AllowExit()
233 .AllowWrite()
234 .AllowRead()
235 .AllowSyscall(__NR_sendto)
236 .AllowTcMalloc()
237 .AddNetworkProxyHandlerPolicy()
238 .AllowLlvmCoverage()
239 .AddLibrariesForBinary(path)
240 .AllowIPv4("127.0.0.1");
241
242 SAPI_ASSERT_OK_AND_ASSIGN(auto policy, builder.TryBuild());
243
244 Sandbox2 s2(std::move(executor), std::move(policy));
245 ASSERT_TRUE(s2.RunAsync());
246
247 SAPI_ASSERT_OK_AND_ASSIGN(auto server,
248 NetworkProxyTestServer::Start(/*ipv6=*/true));
249 ASSERT_TRUE(s2.comms()->SendInt32(server->port()));
250
251 sandbox2::Result result = s2.AwaitResult();
252 ASSERT_THAT(result.final_status(), Eq(Result::OK));
253 EXPECT_THAT(result.reason_code(), Eq(3));
254 }
255
256 INSTANTIATE_TEST_SUITE_P(NetworkProxyTest, NetworkProxyTest,
257 ::testing::Combine(::testing::Bool(),
258 ::testing::Bool()));
259
260 } // namespace
261 } // namespace sandbox2
262