blob: 4e16dba387753e728ffba5c01193390c89ba46c5 [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
Hugo Benichi2ac4d072019-05-28 14:51:23 +090018#include "arc/network/net_util.h"
19
Garrick Evans3cbac7c2019-04-18 15:31:31 +090020namespace arc_networkd {
21namespace {
Garrick Evansa7556db2019-05-07 11:22:40 +090022// adb gets confused if we listen on 5555 and thinks there is an emulator
23// running, which in turn ends up confusing our integration test libraries
24// because multiple devices show up.
25constexpr uint16_t kTcpListenPort = 5550;
26// But we still connect to adbd on its standard TCP port.
27constexpr uint16_t kTcpConnectPort = 5555;
Hugo Benichi2ac4d072019-05-28 14:51:23 +090028constexpr uint32_t kTcpAddr = Ipv4Addr(100, 115, 92, 2);
jasongustaman14076282019-05-20 15:38:41 +090029constexpr uint32_t kVsockPort = 5555;
30// Reference: (./src/private-overlays/project-cheets-private/
31// chromeos-base/android-vm-pi/files/run-arcvm)
32constexpr uint32_t kVsockCid = 5;
Garrick Evans3cbac7c2019-04-18 15:31:31 +090033constexpr uint64_t kCapMask = CAP_TO_MASK(CAP_NET_RAW);
34constexpr char kUnprivilegedUser[] = "arc-networkd";
35constexpr int kMaxConn = 16;
36
37} // namespace
38
Garrick Evans96e03042019-05-28 14:30:52 +090039AdbProxy::AdbProxy(base::ScopedFD control_fd)
40 : msg_dispatcher_(std::move(control_fd)), src_watcher_(FROM_HERE) {
41 msg_dispatcher_.RegisterFailureHandler(
42 base::Bind(&AdbProxy::OnParentProcessExit, weak_factory_.GetWeakPtr()));
43
44 msg_dispatcher_.RegisterGuestMessageHandler(
45 base::Bind(&AdbProxy::OnGuestMessage, weak_factory_.GetWeakPtr()));
46}
Garrick Evans3cbac7c2019-04-18 15:31:31 +090047
48AdbProxy::~AdbProxy() {
49 src_watcher_.StopWatchingFileDescriptor();
50}
51
52int AdbProxy::OnInit() {
53 // Prevent the main process from sending us any signals.
54 if (setsid() < 0) {
55 PLOG(ERROR) << "Failed to created a new session with setsid; exiting";
56 return -1;
57 }
58
59 // Run with minimal privileges.
60 brillo::Minijail* m = brillo::Minijail::GetInstance();
61 struct minijail* jail = m->New();
62
63 // Most of these return void, but DropRoot() can fail if the user/group
64 // does not exist.
65 CHECK(m->DropRoot(jail, kUnprivilegedUser, kUnprivilegedUser))
66 << "Could not drop root privileges";
67 m->UseCapabilities(jail, kCapMask);
68 m->Enter(jail);
69 m->Destroy(jail);
70
Garrick Evans3cbac7c2019-04-18 15:31:31 +090071 return Daemon::OnInit();
72}
73
Garrick Evans96e03042019-05-28 14:30:52 +090074void AdbProxy::OnParentProcessExit() {
75 LOG(ERROR) << "Quitting because the parent process died";
76 src_watcher_.StopWatchingFileDescriptor();
77 Quit();
78}
79
Garrick Evans3cbac7c2019-04-18 15:31:31 +090080void AdbProxy::OnFileCanReadWithoutBlocking(int fd) {
81 if (auto conn = src_->Accept()) {
82 if (auto dst = Connect()) {
83 LOG(INFO) << "Connection established: " << *conn << " <-> " << *dst;
84 auto fwd = std::make_unique<SocketForwarder>(
85 base::StringPrintf("adbp%d-%d", conn->fd(), dst->fd()),
86 std::move(conn), std::move(dst));
87 fwd->Start();
88 fwd_.emplace_back(std::move(fwd));
89 }
90 }
91
92 // Cleanup any defunct forwarders.
93 for (auto it = fwd_.begin(); it != fwd_.end();) {
Garrick Evans088cd0e2019-06-04 15:20:43 +090094 if (!(*it)->IsRunning() && (*it)->HasBeenStarted())
Garrick Evans3cbac7c2019-04-18 15:31:31 +090095 it = fwd_.erase(it);
Garrick Evans4e96fad2019-05-17 10:19:38 +090096 else
97 ++it;
Garrick Evans3cbac7c2019-04-18 15:31:31 +090098 }
99}
100
101std::unique_ptr<Socket> AdbProxy::Connect() const {
jasongustaman14076282019-05-20 15:38:41 +0900102 // 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);
Hugo Benichi2ac4d072019-05-28 14:51:23 +0900106 addr_in.sin_addr.s_addr = kTcpAddr;
Garrick Evans3cbac7c2019-04-18 15:31:31 +0900107
Garrick Evans088cd0e2019-06-04 15:20:43 +0900108 auto 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
Garrick Evans088cd0e2019-06-04 15:20:43 +0900112 // Try to connect with VSOCK.
113 struct sockaddr_vm addr_vm = {0};
114 addr_vm.svm_family = AF_VSOCK;
115 addr_vm.svm_port = kVsockPort;
116 addr_vm.svm_cid = kVsockCid;
117
118 dst = std::make_unique<Socket>(AF_VSOCK, SOCK_STREAM);
119 if (dst->Connect((const struct sockaddr*)&addr_vm, sizeof(addr_vm)))
120 return dst;
121
jasongustaman14076282019-05-20 15:38:41 +0900122 return nullptr;
Garrick Evans3cbac7c2019-04-18 15:31:31 +0900123}
124
Garrick Evans96e03042019-05-28 14:30:52 +0900125void AdbProxy::OnGuestMessage(const GuestMessage& msg) {
126 if (msg.type() != GuestMessage::ARC)
127 return;
128
129 // On ARC up, start accepting connections.
130 if (msg.event() == GuestMessage::START) {
Garrick Evans584210b2019-05-27 14:25:43 +0900131 src_ = std::make_unique<Socket>(AF_INET, SOCK_STREAM | SOCK_NONBLOCK);
Garrick Evans20cc37c2019-05-29 17:25:59 +0900132 // Need to set this to reuse the port on localhost.
Garrick Evans20cc37c2019-05-29 17:25:59 +0900133 int on = 1;
134 if (setsockopt(src_->fd(), SOL_SOCKET, SO_REUSEADDR, &on, sizeof(int)) <
135 0) {
136 PLOG(ERROR) << "setsockopt(SO_REUSEADDR) failed";
Garrick Evans96e03042019-05-28 14:30:52 +0900137 return;
Garrick Evans20cc37c2019-05-29 17:25:59 +0900138 }
Garrick Evans584210b2019-05-27 14:25:43 +0900139 struct sockaddr_in addr = {0};
140 addr.sin_family = AF_INET;
Garrick Evansa7556db2019-05-07 11:22:40 +0900141 addr.sin_port = htons(kTcpListenPort);
Garrick Evans584210b2019-05-27 14:25:43 +0900142 addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
143 if (!src_->Bind((const struct sockaddr*)&addr, sizeof(addr))) {
144 LOG(ERROR) << "Cannot bind source socket";
Garrick Evans96e03042019-05-28 14:30:52 +0900145 return;
Garrick Evans584210b2019-05-27 14:25:43 +0900146 }
147
148 if (!src_->Listen(kMaxConn)) {
149 LOG(ERROR) << "Cannot listen on source socket";
Garrick Evans96e03042019-05-28 14:30:52 +0900150 return;
Garrick Evans584210b2019-05-27 14:25:43 +0900151 }
152
153 // Run the accept loop.
154 base::MessageLoopForIO::current()->WatchFileDescriptor(
155 src_->fd(), true, base::MessageLoopForIO::WATCH_READ, &src_watcher_,
156 this);
Garrick Evans96e03042019-05-28 14:30:52 +0900157 return;
Garrick Evans584210b2019-05-27 14:25:43 +0900158 }
159
Garrick Evans96e03042019-05-28 14:30:52 +0900160 // On ARC down, cull any open connections and stop listening.
161 if (msg.event() == GuestMessage::STOP) {
Garrick Evans584210b2019-05-27 14:25:43 +0900162 src_watcher_.StopWatchingFileDescriptor();
Garrick Evans088cd0e2019-06-04 15:20:43 +0900163 src_.reset();
164 fwd_.clear();
Garrick Evans584210b2019-05-27 14:25:43 +0900165 }
Garrick Evans3cbac7c2019-04-18 15:31:31 +0900166}
167
168} // namespace arc_networkd