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