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