1 /*
2 * Copyright (C) 2020 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <arpa/inet.h>
18 #include <cutils/sockets.h>
19 #include <errno.h>
20 #include <netinet/in.h>
21 #include <stdint.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <sys/socket.h>
25 #include <sys/types.h>
26 #include <unistd.h>
27
28 #include <android-base/cmsg.h>
29 #include <android-base/logging.h>
30 #include <android-base/properties.h>
31 #include <android-base/scopeguard.h>
32 #include <fs_mgr/file_wait.h>
33 #include <snapuserd/snapuserd_client.h>
34
35 #include "snapuserd_server.h"
36
37 #define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
38 #include <sys/_system_properties.h>
39
40 namespace android {
41 namespace snapshot {
42
43 using namespace std::string_literals;
44
45 using android::base::borrowed_fd;
46 using android::base::unique_fd;
47
Resolveop(std::string & input)48 DaemonOperations SnapuserdServer::Resolveop(std::string& input) {
49 if (input == "init") return DaemonOperations::INIT;
50 if (input == "start") return DaemonOperations::START;
51 if (input == "stop") return DaemonOperations::STOP;
52 if (input == "query") return DaemonOperations::QUERY;
53 if (input == "delete") return DaemonOperations::DELETE;
54 if (input == "detach") return DaemonOperations::DETACH;
55 if (input == "supports") return DaemonOperations::SUPPORTS;
56
57 return DaemonOperations::INVALID;
58 }
59
~SnapuserdServer()60 SnapuserdServer::~SnapuserdServer() {
61 // Close any client sockets that were added via AcceptClient().
62 for (size_t i = 1; i < watched_fds_.size(); i++) {
63 close(watched_fds_[i].fd);
64 }
65 }
66
GetDaemonStatus()67 std::string SnapuserdServer::GetDaemonStatus() {
68 std::string msg = "";
69
70 if (IsTerminating())
71 msg = "passive";
72 else
73 msg = "active";
74
75 return msg;
76 }
77
Parsemsg(std::string const & msg,const char delim,std::vector<std::string> & out)78 void SnapuserdServer::Parsemsg(std::string const& msg, const char delim,
79 std::vector<std::string>& out) {
80 std::stringstream ss(msg);
81 std::string s;
82
83 while (std::getline(ss, s, delim)) {
84 out.push_back(s);
85 }
86 }
87
ShutdownThreads()88 void SnapuserdServer::ShutdownThreads() {
89 StopThreads();
90 JoinAllThreads();
91 }
92
DmUserHandler(std::shared_ptr<Snapuserd> snapuserd)93 DmUserHandler::DmUserHandler(std::shared_ptr<Snapuserd> snapuserd)
94 : snapuserd_(snapuserd), misc_name_(snapuserd_->GetMiscName()) {}
95
Sendmsg(android::base::borrowed_fd fd,const std::string & msg)96 bool SnapuserdServer::Sendmsg(android::base::borrowed_fd fd, const std::string& msg) {
97 ssize_t ret = TEMP_FAILURE_RETRY(send(fd.get(), msg.data(), msg.size(), MSG_NOSIGNAL));
98 if (ret < 0) {
99 PLOG(ERROR) << "Snapuserd:server: send() failed";
100 return false;
101 }
102
103 if (ret < msg.size()) {
104 LOG(ERROR) << "Partial send; expected " << msg.size() << " bytes, sent " << ret;
105 return false;
106 }
107 return true;
108 }
109
Recv(android::base::borrowed_fd fd,std::string * data)110 bool SnapuserdServer::Recv(android::base::borrowed_fd fd, std::string* data) {
111 char msg[MAX_PACKET_SIZE];
112 ssize_t rv = TEMP_FAILURE_RETRY(recv(fd.get(), msg, sizeof(msg), 0));
113 if (rv < 0) {
114 PLOG(ERROR) << "recv failed";
115 return false;
116 }
117 *data = std::string(msg, rv);
118 return true;
119 }
120
Receivemsg(android::base::borrowed_fd fd,const std::string & str)121 bool SnapuserdServer::Receivemsg(android::base::borrowed_fd fd, const std::string& str) {
122 const char delim = ',';
123
124 std::vector<std::string> out;
125 Parsemsg(str, delim, out);
126 DaemonOperations op = Resolveop(out[0]);
127
128 switch (op) {
129 case DaemonOperations::INIT: {
130 // Message format:
131 // init,<misc_name>,<cow_device_path>,<backing_device>
132 //
133 // Reads the metadata and send the number of sectors
134 if (out.size() != 4) {
135 LOG(ERROR) << "Malformed init message, " << out.size() << " parts";
136 return Sendmsg(fd, "fail");
137 }
138
139 auto handler = AddHandler(out[1], out[2], out[3]);
140 if (!handler) {
141 return Sendmsg(fd, "fail");
142 }
143
144 auto retval = "success," + std::to_string(handler->snapuserd()->GetNumSectors());
145 return Sendmsg(fd, retval);
146 }
147 case DaemonOperations::START: {
148 // Message format:
149 // start,<misc_name>
150 //
151 // Start the new thread which binds to dm-user misc device
152 if (out.size() != 2) {
153 LOG(ERROR) << "Malformed start message, " << out.size() << " parts";
154 return Sendmsg(fd, "fail");
155 }
156
157 std::lock_guard<std::mutex> lock(lock_);
158 auto iter = FindHandler(&lock, out[1]);
159 if (iter == dm_users_.end()) {
160 LOG(ERROR) << "Could not find handler: " << out[1];
161 return Sendmsg(fd, "fail");
162 }
163 if (!(*iter)->snapuserd() || (*iter)->snapuserd()->IsAttached()) {
164 LOG(ERROR) << "Tried to re-attach control device: " << out[1];
165 return Sendmsg(fd, "fail");
166 }
167 if (!StartHandler(*iter)) {
168 return Sendmsg(fd, "fail");
169 }
170 return Sendmsg(fd, "success");
171 }
172 case DaemonOperations::STOP: {
173 // Message format: stop
174 //
175 // Stop all the threads gracefully and then shutdown the
176 // main thread
177 SetTerminating();
178 ShutdownThreads();
179 return true;
180 }
181 case DaemonOperations::QUERY: {
182 // Message format: query
183 //
184 // As part of transition, Second stage daemon will be
185 // created before terminating the first stage daemon. Hence,
186 // for a brief period client may have to distiguish between
187 // first stage daemon and second stage daemon.
188 //
189 // Second stage daemon is marked as active and hence will
190 // be ready to receive control message.
191 return Sendmsg(fd, GetDaemonStatus());
192 }
193 case DaemonOperations::DELETE: {
194 // Message format:
195 // delete,<misc_name>
196 if (out.size() != 2) {
197 LOG(ERROR) << "Malformed delete message, " << out.size() << " parts";
198 return Sendmsg(fd, "fail");
199 }
200 if (!RemoveAndJoinHandler(out[1])) {
201 return Sendmsg(fd, "fail");
202 }
203 return Sendmsg(fd, "success");
204 }
205 case DaemonOperations::DETACH: {
206 terminating_ = true;
207 return true;
208 }
209 case DaemonOperations::SUPPORTS: {
210 if (out.size() != 2) {
211 LOG(ERROR) << "Malformed supports message, " << out.size() << " parts";
212 return Sendmsg(fd, "fail");
213 }
214 if (out[1] == "second_stage_socket_handoff") {
215 return Sendmsg(fd, "success");
216 }
217 return Sendmsg(fd, "fail");
218 }
219 default: {
220 LOG(ERROR) << "Received unknown message type from client";
221 Sendmsg(fd, "fail");
222 return false;
223 }
224 }
225 }
226
RunThread(std::shared_ptr<DmUserHandler> handler)227 void SnapuserdServer::RunThread(std::shared_ptr<DmUserHandler> handler) {
228 LOG(INFO) << "Entering thread for handler: " << handler->misc_name();
229
230 handler->snapuserd()->SetSocketPresent(is_socket_present_);
231 if (!handler->snapuserd()->Start()) {
232 LOG(ERROR) << " Failed to launch all worker threads";
233 }
234
235 handler->snapuserd()->CloseFds();
236 handler->snapuserd()->CheckMergeCompletionStatus();
237 handler->snapuserd()->UnmapBufferRegion();
238
239 auto misc_name = handler->misc_name();
240 LOG(INFO) << "Handler thread about to exit: " << misc_name;
241
242 {
243 std::lock_guard<std::mutex> lock(lock_);
244 auto iter = FindHandler(&lock, handler->misc_name());
245 if (iter == dm_users_.end()) {
246 // RemoveAndJoinHandler() already removed us from the list, and is
247 // now waiting on a join(), so just return. Additionally, release
248 // all the resources held by snapuserd object which are shared
249 // by worker threads. This should be done when the last reference
250 // of "handler" is released; but we will explicitly release here
251 // to make sure snapuserd object is freed as it is the biggest
252 // consumer of memory in the daemon.
253 handler->FreeResources();
254 LOG(INFO) << "Exiting handler thread to allow for join: " << misc_name;
255 return;
256 }
257
258 LOG(INFO) << "Exiting handler thread and freeing resources: " << misc_name;
259
260 if (handler->snapuserd()->IsAttached()) {
261 handler->thread().detach();
262 }
263
264 // Important: free resources within the lock. This ensures that if
265 // WaitForDelete() is called, the handler is either in the list, or
266 // it's not and its resources are guaranteed to be freed.
267 handler->FreeResources();
268 }
269 }
270
Start(const std::string & socketname)271 bool SnapuserdServer::Start(const std::string& socketname) {
272 bool start_listening = true;
273
274 sockfd_.reset(android_get_control_socket(socketname.c_str()));
275 if (sockfd_ < 0) {
276 sockfd_.reset(socket_local_server(socketname.c_str(), ANDROID_SOCKET_NAMESPACE_RESERVED,
277 SOCK_STREAM));
278 if (sockfd_ < 0) {
279 PLOG(ERROR) << "Failed to create server socket " << socketname;
280 return false;
281 }
282 start_listening = false;
283 }
284 return StartWithSocket(start_listening);
285 }
286
StartWithSocket(bool start_listening)287 bool SnapuserdServer::StartWithSocket(bool start_listening) {
288 if (start_listening && listen(sockfd_.get(), 4) < 0) {
289 PLOG(ERROR) << "listen socket failed";
290 return false;
291 }
292
293 AddWatchedFd(sockfd_, POLLIN);
294 is_socket_present_ = true;
295
296 // If started in first-stage init, the property service won't be online.
297 if (access("/dev/socket/property_service", F_OK) == 0) {
298 if (!android::base::SetProperty("snapuserd.ready", "true")) {
299 LOG(ERROR) << "Failed to set snapuserd.ready property";
300 return false;
301 }
302 }
303
304 LOG(DEBUG) << "Snapuserd server now accepting connections";
305 return true;
306 }
307
Run()308 bool SnapuserdServer::Run() {
309 LOG(INFO) << "Now listening on snapuserd socket";
310
311 while (!IsTerminating()) {
312 int rv = TEMP_FAILURE_RETRY(poll(watched_fds_.data(), watched_fds_.size(), -1));
313 if (rv < 0) {
314 PLOG(ERROR) << "poll failed";
315 return false;
316 }
317 if (!rv) {
318 continue;
319 }
320
321 if (watched_fds_[0].revents) {
322 AcceptClient();
323 }
324
325 auto iter = watched_fds_.begin() + 1;
326 while (iter != watched_fds_.end()) {
327 if (iter->revents && !HandleClient(iter->fd, iter->revents)) {
328 close(iter->fd);
329 iter = watched_fds_.erase(iter);
330 } else {
331 iter++;
332 }
333 }
334 }
335
336 JoinAllThreads();
337 return true;
338 }
339
JoinAllThreads()340 void SnapuserdServer::JoinAllThreads() {
341 // Acquire the thread list within the lock.
342 std::vector<std::shared_ptr<DmUserHandler>> dm_users;
343 {
344 std::lock_guard<std::mutex> guard(lock_);
345 dm_users = std::move(dm_users_);
346 }
347
348 for (auto& client : dm_users) {
349 auto& th = client->thread();
350
351 if (th.joinable()) th.join();
352 }
353 }
354
AddWatchedFd(android::base::borrowed_fd fd,int events)355 void SnapuserdServer::AddWatchedFd(android::base::borrowed_fd fd, int events) {
356 struct pollfd p = {};
357 p.fd = fd.get();
358 p.events = events;
359 watched_fds_.emplace_back(std::move(p));
360 }
361
AcceptClient()362 void SnapuserdServer::AcceptClient() {
363 int fd = TEMP_FAILURE_RETRY(accept4(sockfd_.get(), nullptr, nullptr, SOCK_CLOEXEC));
364 if (fd < 0) {
365 PLOG(ERROR) << "accept4 failed";
366 return;
367 }
368
369 AddWatchedFd(fd, POLLIN);
370 }
371
HandleClient(android::base::borrowed_fd fd,int revents)372 bool SnapuserdServer::HandleClient(android::base::borrowed_fd fd, int revents) {
373 if (revents & POLLHUP) {
374 LOG(DEBUG) << "Snapuserd client disconnected";
375 return false;
376 }
377
378 std::string str;
379 if (!Recv(fd, &str)) {
380 return false;
381 }
382 if (!Receivemsg(fd, str)) {
383 LOG(ERROR) << "Encountered error handling client message, revents: " << revents;
384 return false;
385 }
386 return true;
387 }
388
Interrupt()389 void SnapuserdServer::Interrupt() {
390 // Force close the socket so poll() fails.
391 sockfd_ = {};
392 SetTerminating();
393 }
394
AddHandler(const std::string & misc_name,const std::string & cow_device_path,const std::string & backing_device)395 std::shared_ptr<DmUserHandler> SnapuserdServer::AddHandler(const std::string& misc_name,
396 const std::string& cow_device_path,
397 const std::string& backing_device) {
398 auto snapuserd = std::make_shared<Snapuserd>(misc_name, cow_device_path, backing_device);
399 if (!snapuserd->InitCowDevice()) {
400 LOG(ERROR) << "Failed to initialize Snapuserd";
401 return nullptr;
402 }
403
404 if (!snapuserd->InitializeWorkers()) {
405 LOG(ERROR) << "Failed to initialize workers";
406 return nullptr;
407 }
408
409 auto handler = std::make_shared<DmUserHandler>(snapuserd);
410 {
411 std::lock_guard<std::mutex> lock(lock_);
412 if (FindHandler(&lock, misc_name) != dm_users_.end()) {
413 LOG(ERROR) << "Handler already exists: " << misc_name;
414 return nullptr;
415 }
416 dm_users_.push_back(handler);
417 }
418 return handler;
419 }
420
StartHandler(const std::shared_ptr<DmUserHandler> & handler)421 bool SnapuserdServer::StartHandler(const std::shared_ptr<DmUserHandler>& handler) {
422 if (handler->snapuserd()->IsAttached()) {
423 LOG(ERROR) << "Handler already attached";
424 return false;
425 }
426
427 handler->snapuserd()->AttachControlDevice();
428
429 handler->thread() = std::thread(std::bind(&SnapuserdServer::RunThread, this, handler));
430 return true;
431 }
432
FindHandler(std::lock_guard<std::mutex> * proof_of_lock,const std::string & misc_name)433 auto SnapuserdServer::FindHandler(std::lock_guard<std::mutex>* proof_of_lock,
434 const std::string& misc_name) -> HandlerList::iterator {
435 CHECK(proof_of_lock);
436
437 for (auto iter = dm_users_.begin(); iter != dm_users_.end(); iter++) {
438 if ((*iter)->misc_name() == misc_name) {
439 return iter;
440 }
441 }
442 return dm_users_.end();
443 }
444
RemoveAndJoinHandler(const std::string & misc_name)445 bool SnapuserdServer::RemoveAndJoinHandler(const std::string& misc_name) {
446 std::shared_ptr<DmUserHandler> handler;
447 {
448 std::lock_guard<std::mutex> lock(lock_);
449
450 auto iter = FindHandler(&lock, misc_name);
451 if (iter == dm_users_.end()) {
452 // Client already deleted.
453 return true;
454 }
455 handler = std::move(*iter);
456 dm_users_.erase(iter);
457 }
458
459 auto& th = handler->thread();
460 if (th.joinable()) {
461 th.join();
462 }
463 return true;
464 }
465
WaitForSocket()466 bool SnapuserdServer::WaitForSocket() {
467 auto scope_guard = android::base::make_scope_guard([this]() -> void { JoinAllThreads(); });
468
469 auto socket_path = ANDROID_SOCKET_DIR "/"s + kSnapuserdSocketProxy;
470
471 if (!android::fs_mgr::WaitForFile(socket_path, std::chrono::milliseconds::max())) {
472 LOG(ERROR)
473 << "Failed to wait for proxy socket, second-stage snapuserd will fail to connect";
474 return false;
475 }
476
477 // We must re-initialize property service access, since we launched before
478 // second-stage init.
479 __system_properties_init();
480
481 if (!android::base::WaitForProperty("snapuserd.proxy_ready", "true")) {
482 LOG(ERROR)
483 << "Failed to wait for proxy property, second-stage snapuserd will fail to connect";
484 return false;
485 }
486
487 unique_fd fd(socket_local_client(kSnapuserdSocketProxy, ANDROID_SOCKET_NAMESPACE_RESERVED,
488 SOCK_SEQPACKET));
489 if (fd < 0) {
490 PLOG(ERROR) << "Failed to connect to socket proxy";
491 return false;
492 }
493
494 char code[1];
495 std::vector<unique_fd> fds;
496 ssize_t rv = android::base::ReceiveFileDescriptorVector(fd, code, sizeof(code), 1, &fds);
497 if (rv < 0) {
498 PLOG(ERROR) << "Failed to receive server socket over proxy";
499 return false;
500 }
501 if (fds.empty()) {
502 LOG(ERROR) << "Expected at least one file descriptor from proxy";
503 return false;
504 }
505
506 // We don't care if the ACK is received.
507 code[0] = 'a';
508 if (TEMP_FAILURE_RETRY(send(fd, code, sizeof(code), MSG_NOSIGNAL)) < 0) {
509 PLOG(ERROR) << "Failed to send ACK to proxy";
510 return false;
511 }
512
513 sockfd_ = std::move(fds[0]);
514 if (!StartWithSocket(true)) {
515 return false;
516 }
517 return Run();
518 }
519
RunForSocketHandoff()520 bool SnapuserdServer::RunForSocketHandoff() {
521 unique_fd proxy_fd(android_get_control_socket(kSnapuserdSocketProxy));
522 if (proxy_fd < 0) {
523 PLOG(FATAL) << "Proxy could not get android control socket " << kSnapuserdSocketProxy;
524 }
525 borrowed_fd server_fd(android_get_control_socket(kSnapuserdSocket));
526 if (server_fd < 0) {
527 PLOG(FATAL) << "Proxy could not get android control socket " << kSnapuserdSocket;
528 }
529
530 if (listen(proxy_fd.get(), 4) < 0) {
531 PLOG(FATAL) << "Proxy listen socket failed";
532 }
533
534 if (!android::base::SetProperty("snapuserd.proxy_ready", "true")) {
535 LOG(FATAL) << "Proxy failed to set ready property";
536 }
537
538 unique_fd client_fd(
539 TEMP_FAILURE_RETRY(accept4(proxy_fd.get(), nullptr, nullptr, SOCK_CLOEXEC)));
540 if (client_fd < 0) {
541 PLOG(FATAL) << "Proxy accept failed";
542 }
543
544 char code[1] = {'a'};
545 std::vector<int> fds = {server_fd.get()};
546 ssize_t rv = android::base::SendFileDescriptorVector(client_fd, code, sizeof(code), fds);
547 if (rv < 0) {
548 PLOG(FATAL) << "Proxy could not send file descriptor to snapuserd";
549 }
550 // Wait for an ACK - results don't matter, we just don't want to risk closing
551 // the proxy socket too early.
552 if (recv(client_fd, code, sizeof(code), 0) < 0) {
553 PLOG(FATAL) << "Proxy could not receive terminating code from snapuserd";
554 }
555 return true;
556 }
557
558 } // namespace snapshot
559 } // namespace android
560