mirror of
https://github.com/google/sandboxed-api.git
synced 2024-03-22 13:11:30 +08:00
Rework network_proxy related tests/examples
PiperOrigin-RevId: 561632543 Change-Id: I85843cc1cac8348273a5593339b38ae08e07592c
This commit is contained in:
parent
a0eb8d4445
commit
2c9ac02b68
|
@ -1094,3 +1094,21 @@ cc_test(
|
|||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "network_proxy_test",
|
||||
srcs = ["network_proxy_test.cc"],
|
||||
copts = sapi_platform_copts(),
|
||||
data = [
|
||||
"//sandboxed_api/sandbox2/testcases:network_proxy",
|
||||
],
|
||||
tags = ["no_qemu_user_mode"],
|
||||
deps = [
|
||||
":sandbox2",
|
||||
"//sandboxed_api:testing",
|
||||
"//sandboxed_api/sandbox2/network_proxy:testing",
|
||||
"//sandboxed_api/util:status_matchers",
|
||||
"@com_google_absl//absl/strings",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
|
|
@ -1197,6 +1197,27 @@ if(BUILD_TESTING AND SAPI_BUILD_TESTING)
|
|||
ENVIRONMENT "TEST_TMPDIR=/tmp"
|
||||
ENVIRONMENT "TEST_SRCDIR=${PROJECT_BINARY_DIR}"
|
||||
)
|
||||
|
||||
# sandboxed_api/sandbox2:network_proxy_test
|
||||
add_executable(sandbox2_network_proxy_test
|
||||
network_proxy_test.cc
|
||||
)
|
||||
set_target_properties(sandbox2_network_proxy_test PROPERTIES
|
||||
OUTPUT_NAME network_proxy_test
|
||||
)
|
||||
target_link_libraries(sandbox2_network_proxy_test
|
||||
PRIVATE absl::strings
|
||||
sandbox2::sandbox2
|
||||
sandbox2::network_proxy_testing
|
||||
sapi::status_matchers
|
||||
sapi::testing
|
||||
sapi::test_main
|
||||
)
|
||||
gtest_discover_tests_xcompile(sandbox2_bpfdisassembler_test PROPERTIES
|
||||
ENVIRONMENT "TEST_TMPDIR=/tmp"
|
||||
ENVIRONMENT "TEST_SRCDIR=${PROJECT_BINARY_DIR}"
|
||||
)
|
||||
|
||||
endif()
|
||||
|
||||
configure_file(
|
||||
|
|
|
@ -36,14 +36,14 @@ cc_binary(
|
|||
"//sandboxed_api:config",
|
||||
"//sandboxed_api/sandbox2",
|
||||
"//sandboxed_api/sandbox2:comms",
|
||||
"//sandboxed_api/sandbox2/util:bpf_helper",
|
||||
"//sandboxed_api/util:fileops",
|
||||
"//sandboxed_api/sandbox2/network_proxy:testing",
|
||||
"//sandboxed_api/util:runfiles",
|
||||
"@com_google_absl//absl/base:core_headers",
|
||||
"@com_google_absl//absl/flags:parse",
|
||||
"@com_google_absl//absl/log",
|
||||
"@com_google_absl//absl/log:globals",
|
||||
"@com_google_absl//absl/log:initialize",
|
||||
"@com_google_absl//absl/status:statusor",
|
||||
"@com_google_absl//absl/strings:string_view",
|
||||
"@com_google_absl//absl/time",
|
||||
],
|
||||
|
|
|
@ -27,11 +27,12 @@ target_link_libraries(sandbox2_network_sandbox PRIVATE
|
|||
absl::log_globals
|
||||
absl::log_initialize
|
||||
absl::log_severity
|
||||
absl::statusor
|
||||
absl::strings
|
||||
absl::time
|
||||
sandbox2::bpf_helper
|
||||
sandbox2::comms
|
||||
sapi::fileops
|
||||
sandbox2::network_proxy_testing
|
||||
sapi::runfiles
|
||||
sandbox2::sandbox2
|
||||
sapi::base
|
||||
|
|
|
@ -26,22 +26,22 @@
|
|||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/base/macros.h"
|
||||
#include "absl/flags/parse.h"
|
||||
#include "absl/log/globals.h"
|
||||
#include "absl/log/initialize.h"
|
||||
#include "absl/log/log.h"
|
||||
#include "absl/base/log_severity.h"
|
||||
#include "absl/status/statusor.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "absl/time/time.h"
|
||||
#include "sandboxed_api/config.h"
|
||||
#include "sandboxed_api/sandbox2/comms.h"
|
||||
#include "sandboxed_api/sandbox2/executor.h"
|
||||
#include "sandboxed_api/sandbox2/network_proxy/testing.h"
|
||||
#include "sandboxed_api/sandbox2/policy.h"
|
||||
#include "sandboxed_api/sandbox2/policybuilder.h"
|
||||
#include "sandboxed_api/sandbox2/result.h"
|
||||
#include "sandboxed_api/sandbox2/sandbox2.h"
|
||||
#include "sandboxed_api/sandbox2/util/bpf_helper.h"
|
||||
#include "sandboxed_api/util/fileops.h"
|
||||
#include "sandboxed_api/util/runfiles.h"
|
||||
|
||||
namespace {
|
||||
|
@ -60,58 +60,6 @@ std::unique_ptr<sandbox2::Policy> GetPolicy(absl::string_view sandboxee_path) {
|
|||
.BuildOrDie();
|
||||
}
|
||||
|
||||
void Server(int port) {
|
||||
sapi::file_util::fileops::FDCloser s(
|
||||
socket(AF_INET6, SOCK_STREAM | SOCK_CLOEXEC, 0));
|
||||
if (s.get() < 0) {
|
||||
PLOG(ERROR) << "socket() failed";
|
||||
return;
|
||||
}
|
||||
|
||||
if (int enable = 1; setsockopt(s.get(), SOL_SOCKET, SO_REUSEADDR, &enable,
|
||||
sizeof(enable)) < 0) {
|
||||
PLOG(ERROR) << "setsockopt(SO_REUSEADDR) failed";
|
||||
return;
|
||||
}
|
||||
|
||||
// Listen to localhost only.
|
||||
struct sockaddr_in6 addr = {};
|
||||
addr.sin6_family = AF_INET6;
|
||||
addr.sin6_port = htons(port);
|
||||
|
||||
int err = inet_pton(AF_INET6, "::1", &addr.sin6_addr.s6_addr);
|
||||
if (err == 0) {
|
||||
LOG(ERROR) << "inet_pton() failed";
|
||||
return;
|
||||
}
|
||||
if (err == -1) {
|
||||
PLOG(ERROR) << "inet_pton() failed";
|
||||
return;
|
||||
}
|
||||
|
||||
if (bind(s.get(), reinterpret_cast<struct sockaddr*>(&addr), sizeof(addr)) <
|
||||
0) {
|
||||
PLOG(ERROR) << "bind() failed";
|
||||
return;
|
||||
}
|
||||
|
||||
if (listen(s.get(), 1) < 0) {
|
||||
PLOG(ERROR) << "listen() failed";
|
||||
return;
|
||||
}
|
||||
|
||||
sapi::file_util::fileops::FDCloser client(accept(s.get(), 0, 0));
|
||||
if (client.get() < 0) {
|
||||
PLOG(ERROR) << "accept() failed";
|
||||
return;
|
||||
}
|
||||
|
||||
constexpr char kMsg[] = "Hello World\n";
|
||||
if (write(client.get(), kMsg, ABSL_ARRAYSIZE(kMsg) - 1) < 0) {
|
||||
PLOG(ERROR) << "write() failed";
|
||||
}
|
||||
}
|
||||
|
||||
int ConnectToServer(int port) {
|
||||
int s = socket(AF_INET6, SOCK_STREAM, 0);
|
||||
if (s < 0) {
|
||||
|
@ -177,9 +125,12 @@ int main(int argc, char* argv[]) {
|
|||
absl::SetStderrThreshold(absl::LogSeverityAtLeast::kInfo);
|
||||
absl::ParseCommandLine(argc, argv);
|
||||
absl::InitializeLog();
|
||||
int port = 8085;
|
||||
std::thread server_thread{Server,port};
|
||||
server_thread.detach();
|
||||
|
||||
absl::StatusOr<int> port = sandbox2::StartNetworkProxyTestServer();
|
||||
if (!port.ok()) {
|
||||
LOG(ERROR) << port.status();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// Note: In your own code, use sapi::GetDataDependencyFilePath() instead.
|
||||
const std::string path = sapi::internal::GetSapiDataDependencyFilePath(
|
||||
|
@ -214,7 +165,7 @@ int main(int argc, char* argv[]) {
|
|||
return 2;
|
||||
}
|
||||
|
||||
if (!HandleSandboxee(comms, port)) {
|
||||
if (!HandleSandboxee(comms, *port)) {
|
||||
if (!s2.IsTerminated()) {
|
||||
// Kill the sandboxee, because failure to receive the data over the Comms
|
||||
// channel doesn't automatically mean that the sandboxee itself had
|
||||
|
|
|
@ -32,7 +32,7 @@ cc_binary(
|
|||
"//sandboxed_api:config",
|
||||
"//sandboxed_api/sandbox2",
|
||||
"//sandboxed_api/sandbox2:comms",
|
||||
"//sandboxed_api/util:fileops",
|
||||
"//sandboxed_api/sandbox2/network_proxy:testing",
|
||||
"//sandboxed_api/util:runfiles",
|
||||
"@com_google_absl//absl/base:core_headers",
|
||||
"@com_google_absl//absl/flags:flag",
|
||||
|
@ -40,6 +40,7 @@ cc_binary(
|
|||
"@com_google_absl//absl/log",
|
||||
"@com_google_absl//absl/log:globals",
|
||||
"@com_google_absl//absl/log:initialize",
|
||||
"@com_google_absl//absl/status:statusor",
|
||||
"@com_google_absl//absl/strings:string_view",
|
||||
"@com_google_absl//absl/time",
|
||||
],
|
||||
|
|
|
@ -27,11 +27,12 @@ target_link_libraries(sandbox2_networkproxy_sandbox PRIVATE
|
|||
absl::log_globals
|
||||
absl::log_initialize
|
||||
absl::log_severity
|
||||
absl::statusor
|
||||
absl::strings
|
||||
absl::time
|
||||
sandbox2::bpf_helper
|
||||
sandbox2::comms
|
||||
sapi::fileops
|
||||
sandbox2::network_proxy_testing
|
||||
sapi::runfiles
|
||||
sandbox2::sandbox2
|
||||
sapi::base
|
||||
|
|
|
@ -12,22 +12,23 @@
|
|||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/base/macros.h"
|
||||
#include "absl/flags/flag.h"
|
||||
#include "absl/flags/parse.h"
|
||||
#include "absl/log/globals.h"
|
||||
#include "absl/log/initialize.h"
|
||||
#include "absl/log/log.h"
|
||||
#include "absl/base/log_severity.h"
|
||||
#include "absl/status/statusor.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "absl/time/time.h"
|
||||
#include "sandboxed_api/config.h"
|
||||
#include "sandboxed_api/sandbox2/comms.h"
|
||||
#include "sandboxed_api/sandbox2/executor.h"
|
||||
#include "sandboxed_api/sandbox2/network_proxy/testing.h"
|
||||
#include "sandboxed_api/sandbox2/policy.h"
|
||||
#include "sandboxed_api/sandbox2/policybuilder.h"
|
||||
#include "sandboxed_api/sandbox2/result.h"
|
||||
#include "sandboxed_api/sandbox2/sandbox2.h"
|
||||
#include "sandboxed_api/util/fileops.h"
|
||||
#include "sandboxed_api/util/runfiles.h"
|
||||
|
||||
ABSL_FLAG(bool, connect_with_handler, true, "Connect using automatic mode.");
|
||||
|
@ -59,59 +60,6 @@ std::unique_ptr<sandbox2::Policy> GetPolicy(absl::string_view sandboxee_path) {
|
|||
return builder.AllowIPv6("::1").BuildOrDie();
|
||||
}
|
||||
|
||||
void Server(int port) {
|
||||
sapi::file_util::fileops::FDCloser s{
|
||||
socket(AF_INET6, SOCK_STREAM | SOCK_CLOEXEC, 0)};
|
||||
if (s.get() < 0) {
|
||||
PLOG(ERROR) << "socket() failed";
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
int enable = 1;
|
||||
if (setsockopt(s.get(), SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable)) <
|
||||
0) {
|
||||
PLOG(ERROR) << "setsockopt(SO_REUSEADDR) failed";
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Listen to localhost only.
|
||||
struct sockaddr_in6 addr = {};
|
||||
addr.sin6_family = AF_INET6;
|
||||
addr.sin6_port = htons(port);
|
||||
|
||||
int err = inet_pton(AF_INET6, "::1", &addr.sin6_addr.s6_addr);
|
||||
if (err == 0) {
|
||||
LOG(ERROR) << "inet_pton() failed";
|
||||
return;
|
||||
} else if (err == -1) {
|
||||
PLOG(ERROR) << "inet_pton() failed";
|
||||
return;
|
||||
}
|
||||
|
||||
if (bind(s.get(), (struct sockaddr*)&addr, sizeof(addr)) < 0) {
|
||||
PLOG(ERROR) << "bind() failed";
|
||||
return;
|
||||
}
|
||||
|
||||
if (listen(s.get(), 1) < 0) {
|
||||
PLOG(ERROR) << "listen() failed";
|
||||
return;
|
||||
}
|
||||
|
||||
sapi::file_util::fileops::FDCloser client{accept(s.get(), 0, 0)};
|
||||
if (client.get() < 0) {
|
||||
PLOG(ERROR) << "accept() failed";
|
||||
return;
|
||||
}
|
||||
|
||||
constexpr char kMsg[] = "Hello World\n";
|
||||
if (write(client.get(), kMsg, ABSL_ARRAYSIZE(kMsg) - 1) < 0) {
|
||||
PLOG(ERROR) << "write() failed";
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
|
@ -125,9 +73,12 @@ int main(int argc, char* argv[]) {
|
|||
absl::SetStderrThreshold(absl::LogSeverityAtLeast::kInfo);
|
||||
absl::ParseCommandLine(argc, argv);
|
||||
absl::InitializeLog();
|
||||
int port = 8085;
|
||||
std::thread server_thread{Server, port};
|
||||
server_thread.detach();
|
||||
|
||||
absl::StatusOr<int> port = sandbox2::StartNetworkProxyTestServer();
|
||||
if (!port.ok()) {
|
||||
LOG(ERROR) << port.status();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// Note: In your own code, use sapi::GetDataDependencyFilePath() instead.
|
||||
const std::string path =
|
||||
|
@ -157,7 +108,7 @@ int main(int argc, char* argv[]) {
|
|||
|
||||
auto policy = GetPolicy(path);
|
||||
sandbox2::Sandbox2 s2(std::move(executor), std::move(policy));
|
||||
auto* comms = s2.comms();
|
||||
sandbox2::Comms* comms = s2.comms();
|
||||
|
||||
// Let the sandboxee run.
|
||||
if (!s2.RunAsync()) {
|
||||
|
@ -167,7 +118,7 @@ int main(int argc, char* argv[]) {
|
|||
}
|
||||
|
||||
// Send the port number via comms
|
||||
if (!comms->SendInt32(port)) {
|
||||
if (!comms->SendInt32(*port)) {
|
||||
LOG(ERROR) << "sandboxee_comms->SendInt32() failed";
|
||||
return 3;
|
||||
}
|
||||
|
|
|
@ -77,3 +77,16 @@ cc_test(
|
|||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "testing",
|
||||
srcs = ["testing.cc"],
|
||||
hdrs = ["testing.h"],
|
||||
deps = [
|
||||
"//sandboxed_api/util:fileops",
|
||||
"@com_google_absl//absl/log",
|
||||
"@com_google_absl//absl/status",
|
||||
"@com_google_absl//absl/status:statusor",
|
||||
"@com_google_absl//absl/strings",
|
||||
],
|
||||
)
|
||||
|
|
|
@ -60,6 +60,21 @@ target_link_libraries(sandbox2_network_proxy_client PRIVATE
|
|||
sapi::status
|
||||
)
|
||||
|
||||
# sandboxed_api/sandbox2/network_proxy:testing
|
||||
add_library(sandbox2_network_proxy_testing ${SAPI_LIB_TYPE}
|
||||
testing.cc
|
||||
testing.h
|
||||
)
|
||||
add_library(sandbox2::network_proxy_testing ALIAS sandbox2_network_proxy_testing)
|
||||
target_link_libraries(sandbox2_network_proxy_testing PRIVATE
|
||||
absl::log
|
||||
absl::status
|
||||
absl::statusor
|
||||
absl::strings
|
||||
sapi::fileops
|
||||
sapi::base
|
||||
)
|
||||
|
||||
if(BUILD_TESTING AND SAPI_BUILD_TESTING)
|
||||
# sandboxed_api/sandbox2/network_proxy:filtering_test
|
||||
add_executable(sandbox2_filtering_test
|
||||
|
|
91
sandboxed_api/sandbox2/network_proxy/testing.cc
Normal file
91
sandboxed_api/sandbox2/network_proxy/testing.cc
Normal file
|
@ -0,0 +1,91 @@
|
|||
// Copyright 2023 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "sandboxed_api/sandbox2/network_proxy/testing.h"
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <thread>
|
||||
|
||||
#include "absl/log/log.h"
|
||||
#include "absl/status/status.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "sandboxed_api/util/fileops.h"
|
||||
|
||||
namespace sandbox2 {
|
||||
namespace {
|
||||
void ServerThread(int port) {
|
||||
sapi::file_util::fileops::FDCloser s{
|
||||
socket(AF_INET6, SOCK_STREAM | SOCK_CLOEXEC, 0)};
|
||||
if (s.get() < 0) {
|
||||
PLOG(ERROR) << "socket() failed";
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
int enable = 1;
|
||||
if (setsockopt(s.get(), SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable)) <
|
||||
0) {
|
||||
PLOG(ERROR) << "setsockopt(SO_REUSEADDR) failed";
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Listen to localhost only.
|
||||
struct sockaddr_in6 addr = {};
|
||||
addr.sin6_family = AF_INET6;
|
||||
addr.sin6_port = htons(port);
|
||||
|
||||
int err = inet_pton(AF_INET6, "::1", &addr.sin6_addr.s6_addr);
|
||||
if (err == 0) {
|
||||
LOG(ERROR) << "inet_pton() failed";
|
||||
return;
|
||||
} else if (err == -1) {
|
||||
PLOG(ERROR) << "inet_pton() failed";
|
||||
return;
|
||||
}
|
||||
|
||||
if (bind(s.get(), (struct sockaddr*)&addr, sizeof(addr)) < 0) {
|
||||
PLOG(ERROR) << "bind() failed";
|
||||
return;
|
||||
}
|
||||
|
||||
if (listen(s.get(), 1) < 0) {
|
||||
PLOG(ERROR) << "listen() failed";
|
||||
return;
|
||||
}
|
||||
|
||||
sapi::file_util::fileops::FDCloser client{accept(s.get(), 0, 0)};
|
||||
if (client.get() < 0) {
|
||||
PLOG(ERROR) << "accept() failed";
|
||||
return;
|
||||
}
|
||||
|
||||
constexpr absl::string_view kMsg = "Hello World\n";
|
||||
if (write(client.get(), kMsg.data(), kMsg.size()) < 0) {
|
||||
PLOG(ERROR) << "write() failed";
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
absl::StatusOr<int> StartNetworkProxyTestServer() {
|
||||
static int port = 8085;
|
||||
std::thread server_thread([] { ServerThread(++port); });
|
||||
server_thread.detach();
|
||||
return port;
|
||||
}
|
||||
|
||||
} // namespace sandbox2
|
27
sandboxed_api/sandbox2/network_proxy/testing.h
Normal file
27
sandboxed_api/sandbox2/network_proxy/testing.h
Normal file
|
@ -0,0 +1,27 @@
|
|||
// Copyright 2023 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef SANDBOXED_API_SANDBOX2_EXAMPLES_NETWORK_PROXY_NETWORKPROXY_LIB_H_
|
||||
#define SANDBOXED_API_SANDBOX2_EXAMPLES_NETWORK_PROXY_NETWORKPROXY_LIB_H_
|
||||
|
||||
#include "absl/status/statusor.h"
|
||||
|
||||
namespace sandbox2 {
|
||||
|
||||
// Returns the port the server was started on.
|
||||
absl::StatusOr<int> StartNetworkProxyTestServer();
|
||||
|
||||
} // namespace sandbox2
|
||||
|
||||
#endif // SANDBOXED_API_SANDBOX2_EXAMPLES_NETWORK_PROXY_NETWORKPROXY_LIB_H_
|
135
sandboxed_api/sandbox2/network_proxy_test.cc
Normal file
135
sandboxed_api/sandbox2/network_proxy_test.cc
Normal file
|
@ -0,0 +1,135 @@
|
|||
// Copyright 2023 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <syscall.h>
|
||||
|
||||
#include <cstdlib>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "sandboxed_api/sandbox2/executor.h"
|
||||
#include "sandboxed_api/sandbox2/network_proxy/testing.h"
|
||||
#include "sandboxed_api/sandbox2/policybuilder.h"
|
||||
#include "sandboxed_api/sandbox2/result.h"
|
||||
#include "sandboxed_api/sandbox2/sandbox2.h"
|
||||
#include "sandboxed_api/testing.h"
|
||||
#include "sandboxed_api/util/status_matchers.h"
|
||||
|
||||
namespace sandbox2 {
|
||||
namespace {
|
||||
|
||||
using ::sapi::GetTestSourcePath;
|
||||
using ::testing::Eq;
|
||||
|
||||
TEST(NetworkProxy, ProxyWithHandlerAllowed) {
|
||||
SKIP_SANITIZERS;
|
||||
const std::string path =
|
||||
GetTestSourcePath("sandbox2/testcases/network_proxy");
|
||||
std::vector<std::string> args = {"network_proxy"};
|
||||
auto executor = std::make_unique<Executor>(path, args);
|
||||
|
||||
PolicyBuilder builder;
|
||||
builder.AllowDynamicStartup()
|
||||
.AllowWrite()
|
||||
.AllowRead()
|
||||
.AllowExit()
|
||||
.AllowSyscall(__NR_sendto)
|
||||
.AllowTcMalloc()
|
||||
.AddNetworkProxyHandlerPolicy()
|
||||
.AllowLlvmCoverage()
|
||||
.AllowIPv6("::1")
|
||||
.AddLibrariesForBinary(path);
|
||||
|
||||
SAPI_ASSERT_OK_AND_ASSIGN(auto policy, builder.TryBuild());
|
||||
|
||||
Sandbox2 s2(std::move(executor), std::move(policy));
|
||||
ASSERT_TRUE(s2.RunAsync());
|
||||
|
||||
SAPI_ASSERT_OK_AND_ASSIGN(int port, StartNetworkProxyTestServer());
|
||||
ASSERT_TRUE(s2.comms()->SendInt32(port));
|
||||
|
||||
sandbox2::Result result = s2.AwaitResult();
|
||||
ASSERT_THAT(result.final_status(), Eq(Result::OK));
|
||||
EXPECT_THAT(result.reason_code(), Eq(EXIT_SUCCESS));
|
||||
}
|
||||
|
||||
TEST(NetworkProxy, ProxyWithHandlerNotAllowed) {
|
||||
SKIP_SANITIZERS;
|
||||
const std::string path =
|
||||
GetTestSourcePath("sandbox2/testcases/network_proxy");
|
||||
std::vector<std::string> args = {"network_proxy"};
|
||||
auto executor = std::make_unique<Executor>(path, args);
|
||||
|
||||
PolicyBuilder builder;
|
||||
builder.AllowDynamicStartup()
|
||||
.AllowWrite()
|
||||
.AllowRead()
|
||||
.AllowExit()
|
||||
.AllowSyscall(__NR_sendto)
|
||||
.AllowTcMalloc()
|
||||
.AddNetworkProxyHandlerPolicy()
|
||||
.AllowLlvmCoverage()
|
||||
.AddLibrariesForBinary(path);
|
||||
|
||||
SAPI_ASSERT_OK_AND_ASSIGN(auto policy, builder.TryBuild());
|
||||
|
||||
Sandbox2 s2(std::move(executor), std::move(policy));
|
||||
ASSERT_TRUE(s2.RunAsync());
|
||||
|
||||
SAPI_ASSERT_OK_AND_ASSIGN(int port, StartNetworkProxyTestServer());
|
||||
ASSERT_TRUE(s2.comms()->SendInt32(port));
|
||||
|
||||
sandbox2::Result result = s2.AwaitResult();
|
||||
ASSERT_THAT(result.final_status(), Eq(Result::VIOLATION));
|
||||
EXPECT_THAT(result.reason_code(), Eq(Result::VIOLATION_NETWORK));
|
||||
}
|
||||
|
||||
TEST(NetworkProxy, ProxyWithoutHandlerAllowed) {
|
||||
SKIP_SANITIZERS;
|
||||
const std::string path =
|
||||
GetTestSourcePath("sandbox2/testcases/network_proxy");
|
||||
std::vector<std::string> args = {"network_proxy", "--noconnect_with_handler"};
|
||||
auto executor = std::make_unique<Executor>(path, args);
|
||||
|
||||
PolicyBuilder builder;
|
||||
builder.AllowDynamicStartup()
|
||||
.AllowExit()
|
||||
.AllowWrite()
|
||||
.AllowRead()
|
||||
.AllowSyscall(__NR_sendto)
|
||||
.AllowTcMalloc()
|
||||
.AddNetworkProxyHandlerPolicy()
|
||||
.AllowLlvmCoverage()
|
||||
.AllowIPv6("::1")
|
||||
.AddLibrariesForBinary(path);
|
||||
|
||||
SAPI_ASSERT_OK_AND_ASSIGN(auto policy, builder.TryBuild());
|
||||
|
||||
Sandbox2 s2(std::move(executor), std::move(policy));
|
||||
ASSERT_TRUE(s2.RunAsync());
|
||||
|
||||
SAPI_ASSERT_OK_AND_ASSIGN(int port, StartNetworkProxyTestServer());
|
||||
ASSERT_TRUE(s2.comms()->SendInt32(port));
|
||||
|
||||
sandbox2::Result result = s2.AwaitResult();
|
||||
ASSERT_THAT(result.final_status(), Eq(Result::OK));
|
||||
EXPECT_THAT(result.reason_code(), Eq(EXIT_SUCCESS));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace sandbox2
|
|
@ -137,7 +137,7 @@ TEST(PolicyTest, BpfPtracePermissionDenied) {
|
|||
|
||||
TEST(PolicyTest, IsattyAllowed) {
|
||||
SKIP_SANITIZERS;
|
||||
sandbox2::PolicyBuilder builder;
|
||||
PolicyBuilder builder;
|
||||
if constexpr (sapi::host_os::IsAndroid()) {
|
||||
builder.DisableNamespaces().AllowDynamicStartup();
|
||||
}
|
||||
|
@ -157,7 +157,7 @@ TEST(PolicyTest, IsattyAllowed) {
|
|||
}
|
||||
|
||||
std::unique_ptr<Policy> MinimalTestcasePolicy(absl::string_view path = "") {
|
||||
sandbox2::PolicyBuilder builder;
|
||||
PolicyBuilder builder;
|
||||
|
||||
if constexpr (sapi::host_os::IsAndroid()) {
|
||||
builder.AllowDynamicStartup();
|
||||
|
@ -191,7 +191,7 @@ TEST(MinimalTest, MinimalSharedBinaryWorks) {
|
|||
GetTestSourcePath("sandbox2/testcases/minimal_dynamic");
|
||||
std::vector<std::string> args = {path};
|
||||
|
||||
sandbox2::PolicyBuilder builder;
|
||||
PolicyBuilder builder;
|
||||
|
||||
if constexpr (sapi::host_os::IsAndroid()) {
|
||||
builder.DisableNamespaces();
|
||||
|
@ -216,7 +216,7 @@ TEST(MallocTest, SystemMallocWorks) {
|
|||
GetTestSourcePath("sandbox2/testcases/malloc_system");
|
||||
std::vector<std::string> args = {path};
|
||||
|
||||
sandbox2::PolicyBuilder builder;
|
||||
PolicyBuilder builder;
|
||||
|
||||
if constexpr (sapi::host_os::IsAndroid()) {
|
||||
builder.DisableNamespaces();
|
||||
|
@ -250,7 +250,7 @@ TEST(MultipleSyscalls, AddPolicyOnSyscallsWorks) {
|
|||
GetTestSourcePath("sandbox2/testcases/add_policy_on_syscalls");
|
||||
std::vector<std::string> args = {path};
|
||||
|
||||
sandbox2::PolicyBuilder builder;
|
||||
PolicyBuilder builder;
|
||||
if constexpr (sapi::host_os::IsAndroid()) {
|
||||
builder.DisableNamespaces();
|
||||
builder.AllowDynamicStartup();
|
||||
|
|
|
@ -236,3 +236,27 @@ cc_binary(
|
|||
"@com_google_absl//absl/strings",
|
||||
],
|
||||
)
|
||||
|
||||
cc_binary(
|
||||
name = "network_proxy",
|
||||
testonly = True,
|
||||
srcs = ["network_proxy.cc"],
|
||||
copts = sapi_platform_copts(),
|
||||
deps = [
|
||||
"//sandboxed_api/sandbox2:client",
|
||||
"//sandboxed_api/sandbox2:comms",
|
||||
"//sandboxed_api/sandbox2/network_proxy:client",
|
||||
"//sandboxed_api/util:fileops",
|
||||
"//sandboxed_api/util:status",
|
||||
"@com_google_absl//absl/base:log_severity",
|
||||
"@com_google_absl//absl/flags:flag",
|
||||
"@com_google_absl//absl/flags:parse",
|
||||
"@com_google_absl//absl/log",
|
||||
"@com_google_absl//absl/log:globals",
|
||||
"@com_google_absl//absl/log:initialize",
|
||||
"@com_google_absl//absl/status",
|
||||
"@com_google_absl//absl/status:statusor",
|
||||
"@com_google_absl//absl/strings:str_format",
|
||||
"@com_google_absl//absl/strings:string_view",
|
||||
],
|
||||
)
|
||||
|
|
|
@ -292,3 +292,32 @@ target_link_libraries(sandbox2_testcase_namespace PRIVATE
|
|||
sapi::file_base
|
||||
sapi::fileops
|
||||
)
|
||||
|
||||
# sandboxed_api/sandbox2/testcases:network_proxy
|
||||
add_executable(sandbox2_testcase_network_proxy
|
||||
network_proxy.cc
|
||||
)
|
||||
add_executable(sandbox2::testcase_network_proxy ALIAS sandbox2_testcase_network_proxy)
|
||||
set_target_properties(sandbox2_testcase_network_proxy PROPERTIES
|
||||
OUTPUT_NAME network_proxy
|
||||
)
|
||||
target_link_libraries(sandbox2_testcase_network_proxy PRIVATE
|
||||
absl::flags
|
||||
absl::flags_parse
|
||||
absl::log
|
||||
absl::log_globals
|
||||
absl::log_initialize
|
||||
absl::log_severity
|
||||
absl::status
|
||||
absl::statusor
|
||||
absl::strings
|
||||
absl::str_format
|
||||
sandbox2::client
|
||||
sandbox2::comms
|
||||
sandbox2::network_proxy_client
|
||||
sapi::base
|
||||
sapi::file_base
|
||||
sapi::fileops
|
||||
sapi::status
|
||||
)
|
||||
|
||||
|
|
168
sandboxed_api/sandbox2/testcases/network_proxy.cc
Normal file
168
sandboxed_api/sandbox2/testcases/network_proxy.cc
Normal file
|
@ -0,0 +1,168 @@
|
|||
// Copyright 2023 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// A binary doing various malloc calls to check that the malloc policy works as
|
||||
// expected.
|
||||
// This file is an example of a network sandboxed binary inside a network
|
||||
// namespace. It can't connect with the server directly, but the executor can
|
||||
// establish a connection and pass the connected socket to the sandboxee.
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <cerrno>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
|
||||
#include "absl/base/log_severity.h"
|
||||
#include "absl/flags/flag.h"
|
||||
#include "absl/flags/parse.h"
|
||||
#include "absl/log/globals.h"
|
||||
#include "absl/log/initialize.h"
|
||||
#include "absl/log/log.h"
|
||||
#include "absl/status/status.h"
|
||||
#include "absl/status/statusor.h"
|
||||
#include "absl/strings/str_format.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "sandboxed_api/sandbox2/client.h"
|
||||
#include "sandboxed_api/sandbox2/comms.h"
|
||||
#include "sandboxed_api/sandbox2/network_proxy/client.h"
|
||||
#include "sandboxed_api/util/fileops.h"
|
||||
#include "sandboxed_api/util/status_macros.h"
|
||||
|
||||
ABSL_FLAG(bool, connect_with_handler, true, "Connect using automatic mode.");
|
||||
|
||||
namespace {
|
||||
|
||||
using ::sapi::file_util::fileops::FDCloser;
|
||||
|
||||
static sandbox2::NetworkProxyClient* g_proxy_client;
|
||||
|
||||
ssize_t ReadFromFd(int fd, uint8_t* buf, size_t size) {
|
||||
ssize_t received = 0;
|
||||
while (received < size) {
|
||||
ssize_t read_status =
|
||||
TEMP_FAILURE_RETRY(read(fd, &buf[received], size - received));
|
||||
if (read_status == 0) {
|
||||
break;
|
||||
}
|
||||
if (read_status < 0) {
|
||||
return -1;
|
||||
}
|
||||
received += read_status;
|
||||
}
|
||||
return received;
|
||||
}
|
||||
|
||||
absl::Status CommunicationTest(int sock) {
|
||||
char received[1025] = {0};
|
||||
|
||||
if (ReadFromFd(sock, reinterpret_cast<uint8_t*>(received),
|
||||
sizeof(received) - 1) <= 0) {
|
||||
return absl::InternalError("Data receiving error");
|
||||
}
|
||||
absl::PrintF("Sandboxee received data from the server:\n\n%s\n", received);
|
||||
if (strcmp(received, "Hello World\n")) {
|
||||
return absl::InternalError("Data receiving error");
|
||||
}
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
absl::StatusOr<struct sockaddr_in6> CreateAddres(int port) {
|
||||
static struct sockaddr_in6 saddr {};
|
||||
saddr.sin6_family = AF_INET6;
|
||||
saddr.sin6_port = htons(port);
|
||||
|
||||
if (int err = inet_pton(AF_INET6, "::1", &saddr.sin6_addr); err <= 0) {
|
||||
return absl::ErrnoToStatus(errno, "socket()");
|
||||
}
|
||||
return saddr;
|
||||
}
|
||||
|
||||
absl::Status ConnectWithoutHandler(int s, const struct sockaddr_in6& saddr) {
|
||||
return g_proxy_client->Connect(
|
||||
s, reinterpret_cast<const struct sockaddr*>(&saddr), sizeof(saddr));
|
||||
}
|
||||
|
||||
absl::Status ConnectWithHandler(int s, const struct sockaddr_in6& saddr) {
|
||||
int err = connect(s, reinterpret_cast<const struct sockaddr*>(&saddr),
|
||||
sizeof(saddr));
|
||||
if (err != 0) {
|
||||
return absl::InternalError("connect() failed");
|
||||
}
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
absl::StatusOr<FDCloser> ConnectToServer(int port) {
|
||||
SAPI_ASSIGN_OR_RETURN(struct sockaddr_in6 saddr, CreateAddres(port));
|
||||
|
||||
FDCloser s(socket(AF_INET6, SOCK_STREAM, 0));
|
||||
if (s.get() < 0) {
|
||||
return absl::ErrnoToStatus(errno, "socket()");
|
||||
}
|
||||
|
||||
if (absl::GetFlag(FLAGS_connect_with_handler)) {
|
||||
SAPI_RETURN_IF_ERROR(ConnectWithHandler(s.get(), saddr));
|
||||
} else {
|
||||
SAPI_RETURN_IF_ERROR(ConnectWithoutHandler(s.get(), saddr));
|
||||
}
|
||||
|
||||
LOG(INFO) << "Connected to the server";
|
||||
return s;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
absl::SetStderrThreshold(absl::LogSeverityAtLeast::kInfo);
|
||||
absl::ParseCommandLine(argc, argv);
|
||||
absl::InitializeLog();
|
||||
|
||||
// Set-up the sandbox2::Client object, using a file descriptor (1023).
|
||||
sandbox2::Comms comms(sandbox2::Comms::kDefaultConnection);
|
||||
sandbox2::Client sandbox2_client(&comms);
|
||||
|
||||
if (absl::GetFlag(FLAGS_connect_with_handler)) {
|
||||
if (auto status = sandbox2_client.InstallNetworkProxyHandler();
|
||||
!status.ok()) {
|
||||
LOG(ERROR) << "InstallNetworkProxyHandler() failed: " << status;
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
g_proxy_client = sandbox2_client.GetNetworkProxyClient();
|
||||
}
|
||||
|
||||
// Receive port number of the server
|
||||
int port;
|
||||
if (!comms.RecvInt32(&port)) {
|
||||
LOG(ERROR) << "Failed to receive port number";
|
||||
return 2;
|
||||
}
|
||||
|
||||
absl::StatusOr<FDCloser> client = ConnectToServer(port);
|
||||
if (!client.ok()) {
|
||||
LOG(ERROR) << client.status();
|
||||
return 3;
|
||||
}
|
||||
|
||||
if (auto status = CommunicationTest(client->get()); !status.ok()) {
|
||||
LOG(ERROR) << status;
|
||||
return 4;
|
||||
}
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user