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