1 // This file is an example of a network sandboxed binary inside a network
2 // namespace. It can't connect with the server directly, but the executor can
3 // establish a connection and pass the connected socket to the sandboxee.
4
5 #include <arpa/inet.h>
6 #include <netinet/in.h>
7 #include <sys/socket.h>
8 #include <sys/types.h>
9 #include <unistd.h>
10
11 #include <cerrno>
12 #include <cstring>
13
14 #include "absl/base/log_severity.h"
15 #include "absl/flags/flag.h"
16 #include "absl/flags/parse.h"
17 #include "absl/log/globals.h"
18 #include "absl/log/initialize.h"
19 #include "absl/log/log.h"
20 #include "absl/status/status.h"
21 #include "absl/status/statusor.h"
22 #include "absl/strings/str_format.h"
23 #include "absl/strings/string_view.h"
24 #include "sandboxed_api/sandbox2/client.h"
25 #include "sandboxed_api/sandbox2/comms.h"
26 #include "sandboxed_api/sandbox2/network_proxy/client.h"
27 #include "sandboxed_api/util/fileops.h"
28 #include "sandboxed_api/util/status_macros.h"
29
30 ABSL_FLAG(bool, connect_with_handler, true, "Connect using automatic mode.");
31
32 namespace {
33
34 static sandbox2::NetworkProxyClient* g_proxy_client;
35
ReadFromFd(int fd,uint8_t * buf,size_t size)36 ssize_t ReadFromFd(int fd, uint8_t* buf, size_t size) {
37 ssize_t received = 0;
38 while (received < size) {
39 ssize_t read_status =
40 TEMP_FAILURE_RETRY(read(fd, &buf[received], size - received));
41 if (read_status == 0) {
42 break;
43 }
44 if (read_status < 0) {
45 return -1;
46 }
47 received += read_status;
48 }
49 return received;
50 }
51
CommunicationTest(int sock)52 absl::Status CommunicationTest(int sock) {
53 char received[1025] = {0};
54
55 if (ReadFromFd(sock, reinterpret_cast<uint8_t*>(received),
56 sizeof(received) - 1) <= 0) {
57 return absl::InternalError("Data receiving error");
58 }
59 absl::PrintF("Sandboxee received data from the server:\n\n%s\n", received);
60 if (strcmp(received, "Hello World\n")) {
61 return absl::InternalError("Data receiving error");
62 }
63 return absl::OkStatus();
64 }
65
CreateAddres(int port)66 absl::StatusOr<struct sockaddr_in6> CreateAddres(int port) {
67 static struct sockaddr_in6 saddr {};
68 saddr.sin6_family = AF_INET6;
69 saddr.sin6_port = htons(port);
70
71 if (int err = inet_pton(AF_INET6, "::1", &saddr.sin6_addr); err <= 0) {
72 return absl::ErrnoToStatus(errno, "socket()");
73 }
74 return saddr;
75 }
76
ConnectManually(int s,const struct sockaddr_in6 & saddr)77 absl::Status ConnectManually(int s, const struct sockaddr_in6& saddr) {
78 return g_proxy_client->Connect(
79 s, reinterpret_cast<const struct sockaddr*>(&saddr), sizeof(saddr));
80 }
81
ConnectWithHandler(int s,const struct sockaddr_in6 & saddr)82 absl::Status ConnectWithHandler(int s, const struct sockaddr_in6& saddr) {
83 int err = connect(s, reinterpret_cast<const struct sockaddr*>(&saddr),
84 sizeof(saddr));
85 if (err != 0) {
86 return absl::InternalError("connect() failed");
87 }
88
89 return absl::OkStatus();
90 }
91
ConnectToServer(int port)92 absl::StatusOr<int> ConnectToServer(int port) {
93 SAPI_ASSIGN_OR_RETURN(struct sockaddr_in6 saddr, CreateAddres(port));
94
95 sapi::file_util::fileops::FDCloser s(socket(AF_INET6, SOCK_STREAM, 0));
96 if (s.get() < 0) {
97 return absl::ErrnoToStatus(errno, "socket()");
98 }
99
100 if (absl::GetFlag(FLAGS_connect_with_handler)) {
101 SAPI_RETURN_IF_ERROR(ConnectWithHandler(s.get(), saddr));
102 } else {
103 SAPI_RETURN_IF_ERROR(ConnectManually(s.get(), saddr));
104 }
105
106 LOG(INFO) << "Connected to the server";
107 return s.Release();
108 }
109
110 } // namespace
111
main(int argc,char * argv[])112 int main(int argc, char* argv[]) {
113 absl::SetStderrThreshold(absl::LogSeverityAtLeast::kInfo);
114 absl::ParseCommandLine(argc, argv);
115 absl::InitializeLog();
116
117 // Set-up the sandbox2::Client object, using a file descriptor (1023).
118 sandbox2::Comms comms(sandbox2::Comms::kDefaultConnection);
119 sandbox2::Client sandbox2_client(&comms);
120
121 // Enable sandboxing from here.
122 sandbox2_client.SandboxMeHere();
123
124 if (absl::GetFlag(FLAGS_connect_with_handler)) {
125 if (auto status = sandbox2_client.InstallNetworkProxyHandler();
126 !status.ok()) {
127 LOG(ERROR) << "InstallNetworkProxyHandler() failed: " << status.message();
128 return 1;
129 }
130 } else {
131 g_proxy_client = sandbox2_client.GetNetworkProxyClient();
132 }
133
134 // Receive port number of the server
135 int port;
136 if (!comms.RecvInt32(&port)) {
137 LOG(ERROR) << "Failed to receive port number";
138 return 2;
139 }
140
141 absl::StatusOr<int> sock_s = ConnectToServer(port);
142 if (!sock_s.ok()) {
143 LOG(ERROR) << sock_s.status().message();
144 return 3;
145 }
146 sapi::file_util::fileops::FDCloser client(sock_s.value());
147
148 if (auto status = CommunicationTest(client.get()); !status.ok()) {
149 LOG(ERROR) << status.message();
150 return 4;
151 }
152 return 0;
153 }
154