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 // A binary doing various malloc calls to check that the malloc policy works as
16 // expected.
17 // This file is an example of a network sandboxed binary inside a network
18 // namespace. It can't connect with the server directly, but the executor can
19 // establish a connection and pass the connected socket to the sandboxee.
20
21 #include <arpa/inet.h>
22 #include <netinet/in.h>
23 #include <sys/socket.h>
24 #include <sys/types.h>
25 #include <unistd.h>
26
27 #include <cerrno>
28 #include <cstdint>
29 #include <cstring>
30 #include <variant>
31
32 #include "absl/base/log_severity.h"
33 #include "absl/flags/flag.h"
34 #include "absl/flags/parse.h"
35 #include "absl/log/check.h"
36 #include "absl/log/globals.h"
37 #include "absl/log/initialize.h"
38 #include "absl/log/log.h"
39 #include "absl/status/status.h"
40 #include "absl/status/statusor.h"
41 #include "absl/strings/str_format.h"
42 #include "absl/strings/string_view.h"
43 #include "sandboxed_api/sandbox2/client.h"
44 #include "sandboxed_api/sandbox2/comms.h"
45 #include "sandboxed_api/sandbox2/network_proxy/client.h"
46 #include "sandboxed_api/util/fileops.h"
47 #include "sandboxed_api/util/status_macros.h"
48
49 ABSL_FLAG(bool, connect_with_handler, true, "Connect using automatic mode.");
50 ABSL_FLAG(bool, ipv6, false, "Use IPv6.");
51
52 namespace {
53
54 using ::sapi::file_util::fileops::FDCloser;
55
56 struct IPAddr {
GetSize__anonb87c6c420111::IPAddr57 size_t GetSize() const {
58 return addr.index() == 0 ? sizeof(sockaddr_in) : sizeof(sockaddr_in6);
59 }
GetPtr__anonb87c6c420111::IPAddr60 const sockaddr* GetPtr() const {
61 return addr.index() == 0
62 ? reinterpret_cast<const sockaddr*>(&std::get<0>(addr))
63 : reinterpret_cast<const sockaddr*>(&std::get<1>(addr));
64 }
65 std::variant<sockaddr_in, sockaddr_in6> addr;
66 };
67
68 static sandbox2::NetworkProxyClient* g_proxy_client;
69
ReadFromFd(int fd,uint8_t * buf,size_t size)70 ssize_t ReadFromFd(int fd, uint8_t* buf, size_t size) {
71 ssize_t received = 0;
72 while (received < size) {
73 ssize_t read_status =
74 TEMP_FAILURE_RETRY(read(fd, &buf[received], size - received));
75 if (read_status == 0) {
76 break;
77 }
78 if (read_status < 0) {
79 return -1;
80 }
81 received += read_status;
82 }
83 return received;
84 }
85
CommunicationTest(int sock)86 absl::Status CommunicationTest(int sock) {
87 char received[1025] = {0};
88
89 if (ReadFromFd(sock, reinterpret_cast<uint8_t*>(received),
90 sizeof(received) - 1) <= 0) {
91 return absl::InternalError("Data receiving error");
92 }
93 absl::PrintF("Sandboxee received data from the server:\n\n%s\n", received);
94 if (strcmp(received, "Hello World\n")) {
95 return absl::InternalError("Data receiving error");
96 }
97 return absl::OkStatus();
98 }
99
CreateAddress(int port)100 IPAddr CreateAddress(int port) {
101 static struct sockaddr_in saddr4 {};
102 static struct sockaddr_in6 saddr6 {};
103 saddr4.sin_family = AF_INET;
104 saddr6.sin6_family = AF_INET6;
105 saddr4.sin_port = saddr6.sin6_port = htons(port);
106 PCHECK(inet_pton(AF_INET6, "::1", &saddr6.sin6_addr) == 1);
107 PCHECK(inet_pton(AF_INET, "127.0.0.1", &saddr4.sin_addr) == 1);
108 return absl::GetFlag(FLAGS_ipv6) ? IPAddr{.addr = saddr6}
109 : IPAddr{.addr = saddr4};
110 }
111
ConnectWithoutHandler(int s,IPAddr saddr)112 absl::Status ConnectWithoutHandler(int s, IPAddr saddr) {
113 return g_proxy_client->Connect(s, saddr.GetPtr(), saddr.GetSize());
114 }
115
ConnectWithHandler(int s,IPAddr saddr)116 absl::Status ConnectWithHandler(int s, IPAddr saddr) {
117 int err = connect(s, saddr.GetPtr(), saddr.GetSize());
118 if (err != 0) {
119 return absl::InternalError("connect() failed");
120 }
121
122 return absl::OkStatus();
123 }
124
ConnectToServer(int port)125 absl::StatusOr<FDCloser> ConnectToServer(int port) {
126 IPAddr addr = CreateAddress(port);
127
128 FDCloser s(
129 socket(absl::GetFlag(FLAGS_ipv6) ? AF_INET6 : AF_INET, SOCK_STREAM, 0));
130 if (s.get() < 0) {
131 return absl::ErrnoToStatus(errno, "socket()");
132 }
133
134 if (absl::GetFlag(FLAGS_connect_with_handler)) {
135 SAPI_RETURN_IF_ERROR(ConnectWithHandler(s.get(), addr));
136 } else {
137 SAPI_RETURN_IF_ERROR(ConnectWithoutHandler(s.get(), addr));
138 }
139
140 LOG(INFO) << "Connected to the server";
141 return s;
142 }
143
144 } // namespace
145
main(int argc,char * argv[])146 int main(int argc, char* argv[]) {
147 absl::SetStderrThreshold(absl::LogSeverityAtLeast::kInfo);
148 absl::ParseCommandLine(argc, argv);
149 absl::InitializeLog();
150
151 // Set-up the sandbox2::Client object, using a file descriptor (1023).
152 sandbox2::Comms comms(sandbox2::Comms::kDefaultConnection);
153 sandbox2::Client sandbox2_client(&comms);
154
155 if (absl::GetFlag(FLAGS_connect_with_handler)) {
156 if (auto status = sandbox2_client.InstallNetworkProxyHandler();
157 !status.ok()) {
158 LOG(ERROR) << "InstallNetworkProxyHandler() failed: " << status;
159 return 1;
160 }
161 } else {
162 g_proxy_client = sandbox2_client.GetNetworkProxyClient();
163 }
164
165 // Receive port number of the server
166 int port;
167 if (!comms.RecvInt32(&port)) {
168 LOG(ERROR) << "Failed to receive port number";
169 return 2;
170 }
171
172 absl::StatusOr<FDCloser> client = ConnectToServer(port);
173 if (!client.ok()) {
174 LOG(ERROR) << client.status();
175 return 3;
176 }
177
178 if (auto status = CommunicationTest(client->get()); !status.ok()) {
179 LOG(ERROR) << status;
180 return 4;
181 }
182 return 0;
183 }
184