blob: 02786259d864266342bbb8cb75515d61549d6ebd [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
Garrick Evans3388a032020-03-24 11:25:55 +09005#include "patchpanel/adb_proxy.h"
Garrick Evans3cbac7c2019-04-18 15:31:31 +09006
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>
Jason Jeremy Imanf4156cb2019-11-14 15:36:22 +090010#include <sys/un.h>
Garrick Evansaa4f1ce2019-11-29 13:25:39 +090011#include <sysexits.h>
Garrick Evans3cbac7c2019-04-18 15:31:31 +090012
Jason Jeremy Iman510bd3d2019-12-16 13:05:30 +090013#include <set>
Jason Jeremy Imanf4156cb2019-11-14 15:36:22 +090014#include <string>
Garrick Evans3cbac7c2019-04-18 15:31:31 +090015#include <utility>
Jason Jeremy Imanf4156cb2019-11-14 15:36:22 +090016#include <vector>
Garrick Evans3cbac7c2019-04-18 15:31:31 +090017
18#include <base/bind.h>
19#include <base/logging.h>
Jason Jeremy Imanf4156cb2019-11-14 15:36:22 +090020#include <base/strings/string_number_conversions.h>
Garrick Evans3cbac7c2019-04-18 15:31:31 +090021#include <base/strings/stringprintf.h>
Jason Jeremy Iman378930a2020-12-11 05:40:08 +090022#include <base/threading/thread_task_runner_handle.h>
Jason Jeremy Imanf4156cb2019-11-14 15:36:22 +090023#include <brillo/key_value_store.h>
Jason Jeremy Iman378930a2020-12-11 05:40:08 +090024#include <chromeos/dbus/service_constants.h>
25#include <dbus/message.h>
26#include <dbus/object_path.h>
27#include <vboot/crossystem.h>
Garrick Evans3cbac7c2019-04-18 15:31:31 +090028
Garrick Evans3388a032020-03-24 11:25:55 +090029#include "patchpanel/manager.h"
30#include "patchpanel/minijailed_process_runner.h"
31#include "patchpanel/net_util.h"
Hugo Benichi2ac4d072019-05-28 14:51:23 +090032
Garrick Evans3388a032020-03-24 11:25:55 +090033namespace patchpanel {
Garrick Evans3cbac7c2019-04-18 15:31:31 +090034namespace {
Jason Jeremy Imanfa8b6d22020-02-20 03:44:21 +000035// adb-proxy will connect to adbd on its standard TCP port.
Garrick Evansa7556db2019-05-07 11:22:40 +090036constexpr uint16_t kTcpConnectPort = 5555;
Hugo Benichi2ac4d072019-05-28 14:51:23 +090037constexpr uint32_t kTcpAddr = Ipv4Addr(100, 115, 92, 2);
jasongustaman14076282019-05-20 15:38:41 +090038constexpr uint32_t kVsockPort = 5555;
Garrick Evans3cbac7c2019-04-18 15:31:31 +090039constexpr int kMaxConn = 16;
Jason Jeremy Imanf4156cb2019-11-14 15:36:22 +090040// Reference: "device/google/cheets2/init.usb.rc".
41constexpr char kUnixConnectAddr[] = "/run/arc/adb/adb.sock";
Jason Jeremy Iman378930a2020-12-11 05:40:08 +090042constexpr int kDbusTimeoutMs = 200;
43// The maximum number of ADB sideloading query failures before stopping.
44constexpr int kAdbSideloadMaxTry = 5;
45constexpr base::TimeDelta kAdbSideloadUpdateDelay =
46 base::TimeDelta::FromMilliseconds(5000);
Jason Jeremy Imanf4156cb2019-11-14 15:36:22 +090047
Garrick Evansb05a7ff2020-02-18 12:59:55 +090048const std::set<GuestMessage::GuestType> kArcGuestTypes{GuestMessage::ARC,
49 GuestMessage::ARC_VM};
Jason Jeremy Iman378930a2020-12-11 05:40:08 +090050
51bool IsDevModeEnabled() {
52 return VbGetSystemPropertyInt("cros_debug") == 1;
53}
Garrick Evans3cbac7c2019-04-18 15:31:31 +090054} // namespace
55
Garrick Evans96e03042019-05-28 14:30:52 +090056AdbProxy::AdbProxy(base::ScopedFD control_fd)
Garrick Evansbdf1f982019-06-07 09:46:49 +090057 : msg_dispatcher_(std::move(control_fd)),
Garrick Evans1cce71a2019-06-21 10:43:14 +090058 arc_type_(GuestMessage::UNKNOWN_GUEST),
59 arcvm_vsock_cid_(-1) {
Garrick Evans96e03042019-05-28 14:30:52 +090060 msg_dispatcher_.RegisterFailureHandler(
61 base::Bind(&AdbProxy::OnParentProcessExit, weak_factory_.GetWeakPtr()));
62
63 msg_dispatcher_.RegisterGuestMessageHandler(
64 base::Bind(&AdbProxy::OnGuestMessage, weak_factory_.GetWeakPtr()));
65}
Garrick Evans3cbac7c2019-04-18 15:31:31 +090066
Hidehiko Abede129222019-08-16 00:55:04 +090067AdbProxy::~AdbProxy() = default;
Garrick Evans3cbac7c2019-04-18 15:31:31 +090068
69int AdbProxy::OnInit() {
70 // Prevent the main process from sending us any signals.
71 if (setsid() < 0) {
72 PLOG(ERROR) << "Failed to created a new session with setsid; exiting";
Garrick Evansaa4f1ce2019-11-29 13:25:39 +090073 return EX_OSERR;
Garrick Evans3cbac7c2019-04-18 15:31:31 +090074 }
Jason Jeremy Imand89b5f52019-10-24 10:39:17 +090075 EnterChildProcessJail();
Jason Jeremy Iman378930a2020-12-11 05:40:08 +090076 // Run after DBusDaemon::OnInit().
77 base::ThreadTaskRunnerHandle::Get()->PostTask(
78 FROM_HERE,
79 base::Bind(&AdbProxy::InitialSetup, weak_factory_.GetWeakPtr()));
80 return DBusDaemon::OnInit();
81}
82
83void AdbProxy::InitialSetup() {
84 dev_mode_enabled_ = IsDevModeEnabled();
85 if (dev_mode_enabled_) {
86 return;
87 }
88 CheckAdbSideloadingStatus(0 /*num_try*/);
Garrick Evans3cbac7c2019-04-18 15:31:31 +090089}
90
Garrick Evansbdf1f982019-06-07 09:46:49 +090091void AdbProxy::Reset() {
Hidehiko Abede129222019-08-16 00:55:04 +090092 src_watcher_.reset();
Garrick Evansbdf1f982019-06-07 09:46:49 +090093 src_.reset();
94 fwd_.clear();
Garrick Evans1cce71a2019-06-21 10:43:14 +090095 arcvm_vsock_cid_ = -1;
96 arc_type_ = GuestMessage::UNKNOWN_GUEST;
Garrick Evansbdf1f982019-06-07 09:46:49 +090097}
98
Garrick Evans96e03042019-05-28 14:30:52 +090099void AdbProxy::OnParentProcessExit() {
100 LOG(ERROR) << "Quitting because the parent process died";
Garrick Evansbdf1f982019-06-07 09:46:49 +0900101 Reset();
Garrick Evans96e03042019-05-28 14:30:52 +0900102 Quit();
103}
104
Hidehiko Abede129222019-08-16 00:55:04 +0900105void AdbProxy::OnFileCanReadWithoutBlocking() {
Hugo Benichidcc32392020-02-27 09:14:40 +0900106 struct sockaddr_storage client_src = {};
107 socklen_t sockaddr_len = sizeof(client_src);
108 if (auto client_conn =
109 src_->Accept((struct sockaddr*)&client_src, &sockaddr_len)) {
110 LOG(INFO) << "new adb connection from " << client_src;
111 if (auto adbd_conn = Connect()) {
Garrick Evans3cbac7c2019-04-18 15:31:31 +0900112 auto fwd = std::make_unique<SocketForwarder>(
Hugo Benichidcc32392020-02-27 09:14:40 +0900113 base::StringPrintf("adbp%d-%d", client_conn->fd(), adbd_conn->fd()),
114 std::move(client_conn), std::move(adbd_conn));
Garrick Evans3cbac7c2019-04-18 15:31:31 +0900115 fwd->Start();
116 fwd_.emplace_back(std::move(fwd));
117 }
118 }
119
120 // Cleanup any defunct forwarders.
121 for (auto it = fwd_.begin(); it != fwd_.end();) {
Garrick Evans088cd0e2019-06-04 15:20:43 +0900122 if (!(*it)->IsRunning() && (*it)->HasBeenStarted())
Garrick Evans3cbac7c2019-04-18 15:31:31 +0900123 it = fwd_.erase(it);
Garrick Evans4e96fad2019-05-17 10:19:38 +0900124 else
125 ++it;
Garrick Evans3cbac7c2019-04-18 15:31:31 +0900126 }
127}
128
129std::unique_ptr<Socket> AdbProxy::Connect() const {
Garrick Evansbdf1f982019-06-07 09:46:49 +0900130 switch (arc_type_) {
Jason Jeremy Imanf4156cb2019-11-14 15:36:22 +0900131 case GuestMessage::ARC: {
Jason Jeremy Imane50426d2020-02-19 15:28:57 +0900132 struct sockaddr_un addr_un = {0};
133 addr_un.sun_family = AF_UNIX;
134 snprintf(addr_un.sun_path, sizeof(addr_un.sun_path), "%s",
135 kUnixConnectAddr);
136 auto dst = std::make_unique<Socket>(AF_UNIX, SOCK_STREAM);
Hugo Benichidcc32392020-02-27 09:14:40 +0900137 if (dst->Connect((const struct sockaddr*)&addr_un, sizeof(addr_un))) {
138 LOG(INFO) << "Established adbd connection to " << addr_un;
Jason Jeremy Imane50426d2020-02-19 15:28:57 +0900139 return dst;
Hugo Benichidcc32392020-02-27 09:14:40 +0900140 }
Garrick Evansb05a7ff2020-02-18 12:59:55 +0900141
142 LOG(WARNING) << "Failed to connect to UNIX domain socket: "
143 << kUnixConnectAddr << " - falling back to TCP";
144
Garrick Evansbdf1f982019-06-07 09:46:49 +0900145 struct sockaddr_in addr_in = {0};
146 addr_in.sin_family = AF_INET;
147 addr_in.sin_port = htons(kTcpConnectPort);
148 addr_in.sin_addr.s_addr = kTcpAddr;
Garrick Evansb05a7ff2020-02-18 12:59:55 +0900149 dst = std::make_unique<Socket>(AF_INET, SOCK_STREAM);
Hugo Benichidcc32392020-02-27 09:14:40 +0900150 if (!dst->Connect((const struct sockaddr*)&addr_in, sizeof(addr_in)))
151 return nullptr;
152 LOG(INFO) << "Established adbd connection to " << addr_in;
153 return dst;
Garrick Evansbdf1f982019-06-07 09:46:49 +0900154 }
155 case GuestMessage::ARC_VM: {
156 struct sockaddr_vm addr_vm = {0};
157 addr_vm.svm_family = AF_VSOCK;
158 addr_vm.svm_port = kVsockPort;
Garrick Evans1cce71a2019-06-21 10:43:14 +0900159 addr_vm.svm_cid = arcvm_vsock_cid_;
Garrick Evansbdf1f982019-06-07 09:46:49 +0900160 auto dst = std::make_unique<Socket>(AF_VSOCK, SOCK_STREAM);
Hugo Benichidcc32392020-02-27 09:14:40 +0900161 if (!dst->Connect((const struct sockaddr*)&addr_vm, sizeof(addr_vm)))
162 return nullptr;
163 LOG(INFO) << "Established adbd connection to " << addr_vm;
164 return dst;
Garrick Evansbdf1f982019-06-07 09:46:49 +0900165 }
166 default:
167 LOG(DFATAL) << "Unexpected connect - no ARC guest";
168 return nullptr;
169 }
Garrick Evans3cbac7c2019-04-18 15:31:31 +0900170}
171
Garrick Evans96e03042019-05-28 14:30:52 +0900172void AdbProxy::OnGuestMessage(const GuestMessage& msg) {
Garrick Evans1cce71a2019-06-21 10:43:14 +0900173 if (msg.type() == GuestMessage::UNKNOWN_GUEST) {
174 LOG(DFATAL) << "Unexpected message from unknown guest";
Garrick Evans96e03042019-05-28 14:30:52 +0900175 return;
Garrick Evans1cce71a2019-06-21 10:43:14 +0900176 }
Garrick Evans96e03042019-05-28 14:30:52 +0900177
Jason Jeremy Iman510bd3d2019-12-16 13:05:30 +0900178 if (kArcGuestTypes.find(msg.type()) == kArcGuestTypes.end()) {
179 return;
180 }
181
Jason Jeremy Iman378930a2020-12-11 05:40:08 +0900182 // On ARC down, cull any open connections and stop listening.
183 if (msg.event() == GuestMessage::STOP) {
184 Reset();
185 return;
186 }
187
Garrick Evansbdf1f982019-06-07 09:46:49 +0900188 arc_type_ = msg.type();
Garrick Evans1cce71a2019-06-21 10:43:14 +0900189 arcvm_vsock_cid_ = msg.arcvm_vsock_cid();
Garrick Evansbdf1f982019-06-07 09:46:49 +0900190
Garrick Evans96e03042019-05-28 14:30:52 +0900191 // On ARC up, start accepting connections.
192 if (msg.event() == GuestMessage::START) {
Jason Jeremy Iman378930a2020-12-11 05:40:08 +0900193 Listen();
194 }
195}
Garrick Evans584210b2019-05-27 14:25:43 +0900196
Jason Jeremy Iman378930a2020-12-11 05:40:08 +0900197void AdbProxy::Listen() {
198 // Only start listening on either developer mode or sideloading on.
199 if (!dev_mode_enabled_ && !adb_sideloading_enabled_) {
200 return;
201 }
202 // ADB proxy is already listening.
203 if (src_) {
204 return;
205 }
206 // Listen on IPv4 and IPv6. Listening on AF_INET explicitly is not needed
207 // because net.ipv6.bindv6only sysctl is defaulted to 0 and is not
208 // explicitly turned on in the codebase.
209 std::unique_ptr<Socket> src =
210 std::make_unique<Socket>(AF_INET6, SOCK_STREAM | SOCK_NONBLOCK);
211 // Need to set this to reuse the port.
212 int on = 1;
213 if (setsockopt(src->fd(), SOL_SOCKET, SO_REUSEADDR, &on, sizeof(int)) < 0) {
214 PLOG(ERROR) << "setsockopt(SO_REUSEADDR) failed";
215 return;
216 }
217 struct sockaddr_in6 addr = {0};
218 addr.sin6_family = AF_INET6;
219 addr.sin6_port = htons(kAdbProxyTcpListenPort);
220 addr.sin6_addr = in6addr_any;
221 if (!src->Bind((const struct sockaddr*)&addr, sizeof(addr))) {
222 LOG(ERROR) << "Cannot bind source socket to " << addr;
Garrick Evans96e03042019-05-28 14:30:52 +0900223 return;
Garrick Evans584210b2019-05-27 14:25:43 +0900224 }
225
Jason Jeremy Iman378930a2020-12-11 05:40:08 +0900226 if (!src->Listen(kMaxConn)) {
227 LOG(ERROR) << "Cannot listen on " << addr;
228 return;
229 }
230
231 src_ = std::move(src);
232
233 // Run the accept loop.
234 LOG(INFO) << "Accepting connections on " << addr;
235 src_watcher_ = base::FileDescriptorWatcher::WatchReadable(
236 src_->fd(), base::BindRepeating(&AdbProxy::OnFileCanReadWithoutBlocking,
237 base::Unretained(this)));
238 return;
239}
240
241void AdbProxy::CheckAdbSideloadingStatus(int num_try) {
242 if (num_try >= kAdbSideloadMaxTry) {
243 LOG(WARNING) << "Failed to get ADB sideloading status after " << num_try
244 << " tries. ADB sideloading will not work";
245 return;
246 }
247
248 dbus::ObjectProxy* proxy = bus_->GetObjectProxy(
249 login_manager::kSessionManagerServiceName,
250 dbus::ObjectPath(login_manager::kSessionManagerServicePath));
251 dbus::MethodCall method_call(login_manager::kSessionManagerInterface,
252 login_manager::kSessionManagerQueryAdbSideload);
253 std::unique_ptr<dbus::Response> dbus_response =
254 proxy->CallMethodAndBlock(&method_call, kDbusTimeoutMs);
255
256 if (!dbus_response) {
257 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
258 FROM_HERE,
259 base::BindOnce(&AdbProxy::CheckAdbSideloadingStatus,
260 weak_factory_.GetWeakPtr(), num_try + 1),
261 kAdbSideloadUpdateDelay);
262 return;
263 }
264
265 dbus::MessageReader reader(dbus_response.get());
266 reader.PopBool(&adb_sideloading_enabled_);
267 if (!adb_sideloading_enabled_) {
268 LOG(INFO) << "Chrome OS is not in developer mode and ADB sideloading is "
269 "not enabled. ADB proxy is not listening";
270 return;
271 }
272
273 // If ADB sideloading is enabled and ARC guest is started, start listening.
274 if (arc_type_ != GuestMessage::UNKNOWN_GUEST) {
275 Listen();
Garrick Evans584210b2019-05-27 14:25:43 +0900276 }
Garrick Evans3cbac7c2019-04-18 15:31:31 +0900277}
278
Garrick Evans3388a032020-03-24 11:25:55 +0900279} // namespace patchpanel