blob: 9d74b311e5ebcc6c8d69730d529a0cb4b23e96d9 [file] [log] [blame]
Garrick Evans3cbac7c2019-04-18 15:31:31 +09001// Copyright 2019 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "arc/network/adb_proxy.h"
6
jasongustaman14076282019-05-20 15:38:41 +09007#include <linux/vm_sockets.h>
Garrick Evans3cbac7c2019-04-18 15:31:31 +09008#include <sys/socket.h>
9#include <sys/types.h>
10
11#include <utility>
12
13#include <base/bind.h>
14#include <base/logging.h>
15#include <base/strings/stringprintf.h>
16#include <brillo/minijail/minijail.h>
17
18namespace arc_networkd {
19namespace {
Garrick Evansa7556db2019-05-07 11:22:40 +090020// adb gets confused if we listen on 5555 and thinks there is an emulator
21// running, which in turn ends up confusing our integration test libraries
22// because multiple devices show up.
23constexpr uint16_t kTcpListenPort = 5550;
24// But we still connect to adbd on its standard TCP port.
25constexpr uint16_t kTcpConnectPort = 5555;
Garrick Evans3cbac7c2019-04-18 15:31:31 +090026constexpr uint32_t kTcpAddr = 0x64735C02; // 100.115.92.2
jasongustaman14076282019-05-20 15:38:41 +090027constexpr uint32_t kVsockPort = 5555;
28// Reference: (./src/private-overlays/project-cheets-private/
29// chromeos-base/android-vm-pi/files/run-arcvm)
30constexpr uint32_t kVsockCid = 5;
Garrick Evans3cbac7c2019-04-18 15:31:31 +090031constexpr uint64_t kCapMask = CAP_TO_MASK(CAP_NET_RAW);
32constexpr char kUnprivilegedUser[] = "arc-networkd";
33constexpr int kMaxConn = 16;
34
35} // namespace
36
37AdbProxy::AdbProxy() : src_watcher_(FROM_HERE) {}
38
39AdbProxy::~AdbProxy() {
40 src_watcher_.StopWatchingFileDescriptor();
41}
42
43int AdbProxy::OnInit() {
44 // Prevent the main process from sending us any signals.
45 if (setsid() < 0) {
46 PLOG(ERROR) << "Failed to created a new session with setsid; exiting";
47 return -1;
48 }
49
50 // Run with minimal privileges.
51 brillo::Minijail* m = brillo::Minijail::GetInstance();
52 struct minijail* jail = m->New();
53
54 // Most of these return void, but DropRoot() can fail if the user/group
55 // does not exist.
56 CHECK(m->DropRoot(jail, kUnprivilegedUser, kUnprivilegedUser))
57 << "Could not drop root privileges";
58 m->UseCapabilities(jail, kCapMask);
59 m->Enter(jail);
60 m->Destroy(jail);
61
Garrick Evans3cbac7c2019-04-18 15:31:31 +090062 RegisterHandler(SIGUSR1,
63 base::Bind(&AdbProxy::OnSignal, base::Unretained(this)));
64 RegisterHandler(SIGUSR2,
65 base::Bind(&AdbProxy::OnSignal, base::Unretained(this)));
66
Garrick Evans3cbac7c2019-04-18 15:31:31 +090067 return Daemon::OnInit();
68}
69
70void AdbProxy::OnFileCanReadWithoutBlocking(int fd) {
71 if (auto conn = src_->Accept()) {
72 if (auto dst = Connect()) {
73 LOG(INFO) << "Connection established: " << *conn << " <-> " << *dst;
74 auto fwd = std::make_unique<SocketForwarder>(
75 base::StringPrintf("adbp%d-%d", conn->fd(), dst->fd()),
76 std::move(conn), std::move(dst));
77 fwd->Start();
78 fwd_.emplace_back(std::move(fwd));
79 }
80 }
81
82 // Cleanup any defunct forwarders.
83 for (auto it = fwd_.begin(); it != fwd_.end();) {
Garrick Evans4e96fad2019-05-17 10:19:38 +090084 if (!(*it)->IsValid() && (*it)->HasBeenStarted())
Garrick Evans3cbac7c2019-04-18 15:31:31 +090085 it = fwd_.erase(it);
Garrick Evans4e96fad2019-05-17 10:19:38 +090086 else
87 ++it;
Garrick Evans3cbac7c2019-04-18 15:31:31 +090088 }
89}
90
91std::unique_ptr<Socket> AdbProxy::Connect() const {
jasongustaman14076282019-05-20 15:38:41 +090092 // Try to connect with VSOCK.
jasongustaman8587cc02019-05-27 15:01:29 +090093 struct sockaddr_vm addr_vm = {0};
jasongustaman14076282019-05-20 15:38:41 +090094 addr_vm.svm_family = AF_VSOCK;
95 addr_vm.svm_port = kVsockPort;
96 addr_vm.svm_cid = kVsockCid;
97
98 auto dst = std::make_unique<Socket>(AF_VSOCK, SOCK_STREAM);
Garrick Evansfa872f62019-05-28 16:49:25 +090099 if (dst->Connect((const struct sockaddr*)&addr_vm, sizeof(addr_vm)))
jasongustaman14076282019-05-20 15:38:41 +0900100 return dst;
101
102 // Try to connect with TCP IPv4.
jasongustaman8587cc02019-05-27 15:01:29 +0900103 struct sockaddr_in addr_in = {0};
Garrick Evans3cbac7c2019-04-18 15:31:31 +0900104 addr_in.sin_family = AF_INET;
Garrick Evansa7556db2019-05-07 11:22:40 +0900105 addr_in.sin_port = htons(kTcpConnectPort);
Garrick Evans3cbac7c2019-04-18 15:31:31 +0900106 addr_in.sin_addr.s_addr = htonl(kTcpAddr);
107
jasongustaman14076282019-05-20 15:38:41 +0900108 dst = std::make_unique<Socket>(AF_INET, SOCK_STREAM);
Garrick Evansfa872f62019-05-28 16:49:25 +0900109 if (dst->Connect((const struct sockaddr*)&addr_in, sizeof(addr_in)))
jasongustaman14076282019-05-20 15:38:41 +0900110 return dst;
111
112 return nullptr;
Garrick Evans3cbac7c2019-04-18 15:31:31 +0900113}
114
115bool AdbProxy::OnSignal(const struct signalfd_siginfo& info) {
Garrick Evans584210b2019-05-27 14:25:43 +0900116 // On guest ARC up, start accepting connections.
117 if (info.ssi_signo == SIGUSR1) {
118 src_ = std::make_unique<Socket>(AF_INET, SOCK_STREAM | SOCK_NONBLOCK);
Garrick Evans20cc37c2019-05-29 17:25:59 +0900119 // Need to set this to reuse the port on localhost.
120 // TODO(garrick): Move this into Socket.
121 int on = 1;
122 if (setsockopt(src_->fd(), SOL_SOCKET, SO_REUSEADDR, &on, sizeof(int)) <
123 0) {
124 PLOG(ERROR) << "setsockopt(SO_REUSEADDR) failed";
125 return false;
126 }
Garrick Evans584210b2019-05-27 14:25:43 +0900127 struct sockaddr_in addr = {0};
128 addr.sin_family = AF_INET;
Garrick Evansa7556db2019-05-07 11:22:40 +0900129 addr.sin_port = htons(kTcpListenPort);
Garrick Evans584210b2019-05-27 14:25:43 +0900130 addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
131 if (!src_->Bind((const struct sockaddr*)&addr, sizeof(addr))) {
132 LOG(ERROR) << "Cannot bind source socket";
133 return false;
134 }
135
136 if (!src_->Listen(kMaxConn)) {
137 LOG(ERROR) << "Cannot listen on source socket";
138 return false;
139 }
140
141 // Run the accept loop.
142 base::MessageLoopForIO::current()->WatchFileDescriptor(
143 src_->fd(), true, base::MessageLoopForIO::WATCH_READ, &src_watcher_,
144 this);
145 }
146
147 // On ARC down cull any open connections and stop listening.
148 if (info.ssi_signo == SIGUSR2) {
Garrick Evans3cbac7c2019-04-18 15:31:31 +0900149 fwd_.clear();
Garrick Evans584210b2019-05-27 14:25:43 +0900150 src_.reset();
151 src_watcher_.StopWatchingFileDescriptor();
152 }
Garrick Evans3cbac7c2019-04-18 15:31:31 +0900153
154 // Stay registered.
155 return false;
156}
157
158} // namespace arc_networkd