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