• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2019 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 "sandboxed_api/sandbox2/network_proxy/client.h"
16 
17 #include <fcntl.h>
18 #include <sys/socket.h>
19 #include <syscall.h>
20 #include <unistd.h>
21 
22 #include <cerrno>
23 #include <cstdint>
24 
25 #include "absl/log/log.h"
26 #include "absl/status/status.h"
27 #include "absl/synchronization/mutex.h"
28 #include "sandboxed_api/sandbox2/util/syscall_trap.h"
29 #include "sandboxed_api/util/fileops.h"
30 #include "sandboxed_api/util/status_macros.h"
31 
32 namespace sandbox2 {
33 using ::sapi::file_util::fileops::FDCloser;
34 
Connect(int sockfd,const struct sockaddr * addr,socklen_t addrlen)35 absl::Status NetworkProxyClient::Connect(int sockfd,
36                                          const struct sockaddr* addr,
37                                          socklen_t addrlen) {
38   int oldflags = fcntl(sockfd, F_GETFL, 0);
39 
40   // Check if socket is SOCK_STREAM
41   int type;
42   socklen_t type_size = sizeof(int);
43   int result = getsockopt(sockfd, SOL_SOCKET, SO_TYPE, &type, &type_size);
44   if (result == -1) {
45     return absl::FailedPreconditionError("Invalid socket FD");
46   }
47   if (type_size != sizeof(int) || type != SOCK_STREAM) {
48     errno = EINVAL;
49     return absl::InvalidArgumentError(
50         "Invalid socket, only SOCK_STREAM is allowed");
51   }
52   SAPI_ASSIGN_OR_RETURN(FDCloser s, ConnectInternal(addr, addrlen));
53   if (fcntl(s.get(), F_SETFL, oldflags) != 0) {
54     return absl::InternalError("Failed to restore socket flags");
55   }
56   if (dup2(s.get(), sockfd) == -1) {
57     return absl::InternalError("Duplicating socket failed");
58   }
59   return absl::OkStatus();
60 }
61 
ConnectInternal(const struct sockaddr * addr,socklen_t addrlen)62 absl::StatusOr<FDCloser> NetworkProxyClient::ConnectInternal(
63     const struct sockaddr* addr, socklen_t addrlen) {
64   absl::MutexLock lock(&mutex_);
65   // Send sockaddr struct
66   if (!comms_.SendBytes(reinterpret_cast<const uint8_t*>(addr), addrlen)) {
67     errno = EIO;
68     return absl::InternalError("Sending data to network proxy failed");
69   }
70 
71   int result;
72   if (!comms_.RecvInt32(&result)) {
73     errno = EIO;
74     return absl::InternalError("Receiving data from the network proxy failed");
75   }
76   if (result != 0) {
77     errno = result;
78     return absl::ErrnoToStatus(errno, "Error in network proxy server");
79   }
80 
81   int sock;
82   if (!comms_.RecvFD(&sock)) {
83     errno = EIO;
84     return absl::InternalError("Receiving fd from network proxy failed");
85   }
86   return FDCloser(sock);
87 }
88 
89 NetworkProxyClient* NetworkProxyHandler::network_proxy_client_ = nullptr;
90 
InstallNetworkProxyHandler(NetworkProxyClient * npc)91 absl::Status NetworkProxyHandler::InstallNetworkProxyHandler(
92     NetworkProxyClient* npc) {
93   if (network_proxy_client_ != nullptr) {
94     return absl::AlreadyExistsError(
95         "Network proxy handler is already installed");
96   }
97   network_proxy_client_ = npc;
98   if (!SyscallTrap::Install([](int nr, SyscallTrap::Args args, uintptr_t* rv) {
99         return ProcessSeccompTrap(nr, args, rv);
100       })) {
101     return absl::InternalError("Could not install syscall trap");
102   }
103   return absl::OkStatus();
104 }
105 
ProcessSeccompTrap(int nr,SyscallTrap::Args args,uintptr_t * rv)106 bool NetworkProxyHandler::ProcessSeccompTrap(int nr, SyscallTrap::Args args,
107                                              uintptr_t* rv) {
108   int sockfd;
109   const struct sockaddr* addr;
110   socklen_t addrlen;
111 
112   if (nr == __NR_connect) {
113     sockfd = static_cast<int>(args[0]);
114     addr = reinterpret_cast<const struct sockaddr*>(args[1]);
115     addrlen = static_cast<socklen_t>(args[2]);
116 #if defined(SAPI_PPC64_LE)
117   } else if (nr == __NR_socketcall &&
118              static_cast<int>(args[0]) == SYS_CONNECT) {
119     auto* connect_args = reinterpret_cast<uint64_t*>(args[1]);
120     sockfd = static_cast<int>(connect_args[0]);
121     addr = reinterpret_cast<const struct sockaddr*>(connect_args[1]);
122     addrlen = static_cast<socklen_t>(connect_args[2]);
123 #endif
124   } else {
125     return false;
126   }
127 
128   absl::Status result = network_proxy_client_->Connect(sockfd, addr, addrlen);
129   if (result.ok()) {
130     *rv = 0;
131   } else {
132     *rv = -errno;
133   }
134   return true;
135 }
136 
137 }  // namespace sandbox2
138