1 /*
2  * Copyright (C) 2015 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 "Utils.h"
18 
19 #include "Process.h"
20 #include "sehandle.h"
21 
22 #include <android-base/chrono_utils.h>
23 #include <android-base/file.h>
24 #include <android-base/logging.h>
25 #include <android-base/properties.h>
26 #include <android-base/stringprintf.h>
27 #include <android-base/strings.h>
28 #include <android-base/unique_fd.h>
29 #include <cutils/fs.h>
30 #include <logwrap/logwrap.h>
31 #include <private/android_filesystem_config.h>
32 
33 #include <dirent.h>
34 #include <fcntl.h>
35 #include <linux/fs.h>
36 #include <mntent.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <unistd.h>
40 #include <sys/mount.h>
41 #include <sys/stat.h>
42 #include <sys/statvfs.h>
43 #include <sys/sysmacros.h>
44 #include <sys/types.h>
45 #include <sys/wait.h>
46 #include <unistd.h>
47 
48 #include <list>
49 #include <mutex>
50 #include <thread>
51 
52 #ifndef UMOUNT_NOFOLLOW
53 #define UMOUNT_NOFOLLOW 0x00000008 /* Don't follow symlink on umount */
54 #endif
55 
56 using namespace std::chrono_literals;
57 using android::base::ReadFileToString;
58 using android::base::StringPrintf;
59 
60 namespace android {
61 namespace vold {
62 
63 security_context_t sBlkidContext = nullptr;
64 security_context_t sBlkidUntrustedContext = nullptr;
65 security_context_t sFsckContext = nullptr;
66 security_context_t sFsckUntrustedContext = nullptr;
67 
68 bool sSleepOnUnmount = true;
69 
70 static const char* kBlkidPath = "/system/bin/blkid";
71 static const char* kKeyPath = "/data/misc/vold";
72 
73 static const char* kProcDevices = "/proc/devices";
74 static const char* kProcFilesystems = "/proc/filesystems";
75 
76 // Lock used to protect process-level SELinux changes from racing with each
77 // other between multiple threads.
78 static std::mutex kSecurityLock;
79 
CreateDeviceNode(const std::string & path,dev_t dev)80 status_t CreateDeviceNode(const std::string& path, dev_t dev) {
81     std::lock_guard<std::mutex> lock(kSecurityLock);
82     const char* cpath = path.c_str();
83     status_t res = 0;
84 
85     char* secontext = nullptr;
86     if (sehandle) {
87         if (!selabel_lookup(sehandle, &secontext, cpath, S_IFBLK)) {
88             setfscreatecon(secontext);
89         }
90     }
91 
92     mode_t mode = 0660 | S_IFBLK;
93     if (mknod(cpath, mode, dev) < 0) {
94         if (errno != EEXIST) {
95             PLOG(ERROR) << "Failed to create device node for " << major(dev) << ":" << minor(dev)
96                         << " at " << path;
97             res = -errno;
98         }
99     }
100 
101     if (secontext) {
102         setfscreatecon(nullptr);
103         freecon(secontext);
104     }
105 
106     return res;
107 }
108 
DestroyDeviceNode(const std::string & path)109 status_t DestroyDeviceNode(const std::string& path) {
110     const char* cpath = path.c_str();
111     if (TEMP_FAILURE_RETRY(unlink(cpath))) {
112         return -errno;
113     } else {
114         return OK;
115     }
116 }
117 
PrepareDir(const std::string & path,mode_t mode,uid_t uid,gid_t gid)118 status_t PrepareDir(const std::string& path, mode_t mode, uid_t uid, gid_t gid) {
119     std::lock_guard<std::mutex> lock(kSecurityLock);
120     const char* cpath = path.c_str();
121 
122     char* secontext = nullptr;
123     if (sehandle) {
124         if (!selabel_lookup(sehandle, &secontext, cpath, S_IFDIR)) {
125             setfscreatecon(secontext);
126         }
127     }
128 
129     int res = fs_prepare_dir(cpath, mode, uid, gid);
130 
131     if (secontext) {
132         setfscreatecon(nullptr);
133         freecon(secontext);
134     }
135 
136     if (res == 0) {
137         return OK;
138     } else {
139         return -errno;
140     }
141 }
142 
ForceUnmount(const std::string & path)143 status_t ForceUnmount(const std::string& path) {
144     const char* cpath = path.c_str();
145     if (!umount2(cpath, UMOUNT_NOFOLLOW) || errno == EINVAL || errno == ENOENT) {
146         return OK;
147     }
148     // Apps might still be handling eject request, so wait before
149     // we start sending signals
150     if (sSleepOnUnmount) sleep(5);
151 
152     KillProcessesWithOpenFiles(path, SIGINT);
153     if (sSleepOnUnmount) sleep(5);
154     if (!umount2(cpath, UMOUNT_NOFOLLOW) || errno == EINVAL || errno == ENOENT) {
155         return OK;
156     }
157 
158     KillProcessesWithOpenFiles(path, SIGTERM);
159     if (sSleepOnUnmount) sleep(5);
160     if (!umount2(cpath, UMOUNT_NOFOLLOW) || errno == EINVAL || errno == ENOENT) {
161         return OK;
162     }
163 
164     KillProcessesWithOpenFiles(path, SIGKILL);
165     if (sSleepOnUnmount) sleep(5);
166     if (!umount2(cpath, UMOUNT_NOFOLLOW) || errno == EINVAL || errno == ENOENT) {
167         return OK;
168     }
169 
170     return -errno;
171 }
172 
KillProcessesUsingPath(const std::string & path)173 status_t KillProcessesUsingPath(const std::string& path) {
174     if (KillProcessesWithOpenFiles(path, SIGINT) == 0) {
175         return OK;
176     }
177     if (sSleepOnUnmount) sleep(5);
178 
179     if (KillProcessesWithOpenFiles(path, SIGTERM) == 0) {
180         return OK;
181     }
182     if (sSleepOnUnmount) sleep(5);
183 
184     if (KillProcessesWithOpenFiles(path, SIGKILL) == 0) {
185         return OK;
186     }
187     if (sSleepOnUnmount) sleep(5);
188 
189     // Send SIGKILL a second time to determine if we've
190     // actually killed everyone with open files
191     if (KillProcessesWithOpenFiles(path, SIGKILL) == 0) {
192         return OK;
193     }
194     PLOG(ERROR) << "Failed to kill processes using " << path;
195     return -EBUSY;
196 }
197 
BindMount(const std::string & source,const std::string & target)198 status_t BindMount(const std::string& source, const std::string& target) {
199     if (UnmountTree(target) < 0) {
200         return -errno;
201     }
202     if (TEMP_FAILURE_RETRY(mount(source.c_str(), target.c_str(), nullptr, MS_BIND, nullptr)) < 0) {
203         PLOG(ERROR) << "Failed to bind mount " << source << " to " << target;
204         return -errno;
205     }
206     return OK;
207 }
208 
Symlink(const std::string & target,const std::string & linkpath)209 status_t Symlink(const std::string& target, const std::string& linkpath) {
210     if (Unlink(linkpath) < 0) {
211         return -errno;
212     }
213     if (TEMP_FAILURE_RETRY(symlink(target.c_str(), linkpath.c_str())) < 0) {
214         PLOG(ERROR) << "Failed to create symlink " << linkpath << " to " << target;
215         return -errno;
216     }
217     return OK;
218 }
219 
Unlink(const std::string & linkpath)220 status_t Unlink(const std::string& linkpath) {
221     if (TEMP_FAILURE_RETRY(unlink(linkpath.c_str())) < 0 && errno != EINVAL && errno != ENOENT) {
222         PLOG(ERROR) << "Failed to unlink " << linkpath;
223         return -errno;
224     }
225     return OK;
226 }
227 
CreateDir(const std::string & dir,mode_t mode)228 status_t CreateDir(const std::string& dir, mode_t mode) {
229     struct stat sb;
230     if (TEMP_FAILURE_RETRY(stat(dir.c_str(), &sb)) == 0) {
231         if (S_ISDIR(sb.st_mode)) {
232             return OK;
233         } else if (TEMP_FAILURE_RETRY(unlink(dir.c_str())) == -1) {
234             PLOG(ERROR) << "Failed to unlink " << dir;
235             return -errno;
236         }
237     } else if (errno != ENOENT) {
238         PLOG(ERROR) << "Failed to stat " << dir;
239         return -errno;
240     }
241     if (TEMP_FAILURE_RETRY(mkdir(dir.c_str(), mode)) == -1 && errno != EEXIST) {
242         PLOG(ERROR) << "Failed to mkdir " << dir;
243         return -errno;
244     }
245     return OK;
246 }
247 
FindValue(const std::string & raw,const std::string & key,std::string * value)248 bool FindValue(const std::string& raw, const std::string& key, std::string* value) {
249     auto qual = key + "=\"";
250     size_t start = 0;
251     while (true) {
252         start = raw.find(qual, start);
253         if (start == std::string::npos) return false;
254         if (start == 0 || raw[start - 1] == ' ') {
255             break;
256         }
257         start += 1;
258     }
259     start += qual.length();
260 
261     auto end = raw.find("\"", start);
262     if (end == std::string::npos) return false;
263 
264     *value = raw.substr(start, end - start);
265     return true;
266 }
267 
readMetadata(const std::string & path,std::string * fsType,std::string * fsUuid,std::string * fsLabel,bool untrusted)268 static status_t readMetadata(const std::string& path, std::string* fsType, std::string* fsUuid,
269                              std::string* fsLabel, bool untrusted) {
270     fsType->clear();
271     fsUuid->clear();
272     fsLabel->clear();
273 
274     std::vector<std::string> cmd;
275     cmd.push_back(kBlkidPath);
276     cmd.push_back("-c");
277     cmd.push_back("/dev/null");
278     cmd.push_back("-s");
279     cmd.push_back("TYPE");
280     cmd.push_back("-s");
281     cmd.push_back("UUID");
282     cmd.push_back("-s");
283     cmd.push_back("LABEL");
284     cmd.push_back(path);
285 
286     std::vector<std::string> output;
287     status_t res = ForkExecvp(cmd, &output, untrusted ? sBlkidUntrustedContext : sBlkidContext);
288     if (res != OK) {
289         LOG(WARNING) << "blkid failed to identify " << path;
290         return res;
291     }
292 
293     for (const auto& line : output) {
294         // Extract values from blkid output, if defined
295         FindValue(line, "TYPE", fsType);
296         FindValue(line, "UUID", fsUuid);
297         FindValue(line, "LABEL", fsLabel);
298     }
299 
300     return OK;
301 }
302 
ReadMetadata(const std::string & path,std::string * fsType,std::string * fsUuid,std::string * fsLabel)303 status_t ReadMetadata(const std::string& path, std::string* fsType, std::string* fsUuid,
304                       std::string* fsLabel) {
305     return readMetadata(path, fsType, fsUuid, fsLabel, false);
306 }
307 
ReadMetadataUntrusted(const std::string & path,std::string * fsType,std::string * fsUuid,std::string * fsLabel)308 status_t ReadMetadataUntrusted(const std::string& path, std::string* fsType, std::string* fsUuid,
309                                std::string* fsLabel) {
310     return readMetadata(path, fsType, fsUuid, fsLabel, true);
311 }
312 
ConvertToArgv(const std::vector<std::string> & args)313 static std::vector<const char*> ConvertToArgv(const std::vector<std::string>& args) {
314     std::vector<const char*> argv;
315     argv.reserve(args.size() + 1);
316     for (const auto& arg : args) {
317         if (argv.empty()) {
318             LOG(DEBUG) << arg;
319         } else {
320             LOG(DEBUG) << "    " << arg;
321         }
322         argv.emplace_back(arg.data());
323     }
324     argv.emplace_back(nullptr);
325     return argv;
326 }
327 
ReadLinesFromFdAndLog(std::vector<std::string> * output,android::base::unique_fd ufd)328 static status_t ReadLinesFromFdAndLog(std::vector<std::string>* output,
329                                       android::base::unique_fd ufd) {
330     std::unique_ptr<FILE, int (*)(FILE*)> fp(android::base::Fdopen(std::move(ufd), "r"), fclose);
331     if (!fp) {
332         PLOG(ERROR) << "fdopen in ReadLinesFromFdAndLog";
333         return -errno;
334     }
335     if (output) output->clear();
336     char line[1024];
337     while (fgets(line, sizeof(line), fp.get()) != nullptr) {
338         LOG(DEBUG) << line;
339         if (output) output->emplace_back(line);
340     }
341     return OK;
342 }
343 
ForkExecvp(const std::vector<std::string> & args,std::vector<std::string> * output,security_context_t context)344 status_t ForkExecvp(const std::vector<std::string>& args, std::vector<std::string>* output,
345                     security_context_t context) {
346     auto argv = ConvertToArgv(args);
347 
348     android::base::unique_fd pipe_read, pipe_write;
349     if (!android::base::Pipe(&pipe_read, &pipe_write)) {
350         PLOG(ERROR) << "Pipe in ForkExecvp";
351         return -errno;
352     }
353 
354     pid_t pid = fork();
355     if (pid == 0) {
356         if (context) {
357             if (setexeccon(context)) {
358                 LOG(ERROR) << "Failed to setexeccon in ForkExecvp";
359                 abort();
360             }
361         }
362         pipe_read.reset();
363         if (dup2(pipe_write.get(), STDOUT_FILENO) == -1) {
364             PLOG(ERROR) << "dup2 in ForkExecvp";
365             _exit(EXIT_FAILURE);
366         }
367         pipe_write.reset();
368         execvp(argv[0], const_cast<char**>(argv.data()));
369         PLOG(ERROR) << "exec in ForkExecvp";
370         _exit(EXIT_FAILURE);
371     }
372     if (pid == -1) {
373         PLOG(ERROR) << "fork in ForkExecvp";
374         return -errno;
375     }
376 
377     pipe_write.reset();
378     auto st = ReadLinesFromFdAndLog(output, std::move(pipe_read));
379     if (st != 0) return st;
380 
381     int status;
382     if (waitpid(pid, &status, 0) == -1) {
383         PLOG(ERROR) << "waitpid in ForkExecvp";
384         return -errno;
385     }
386     if (!WIFEXITED(status)) {
387         LOG(ERROR) << "Process did not exit normally, status: " << status;
388         return -ECHILD;
389     }
390     if (WEXITSTATUS(status)) {
391         LOG(ERROR) << "Process exited with code: " << WEXITSTATUS(status);
392         return WEXITSTATUS(status);
393     }
394     return OK;
395 }
396 
ForkExecvpAsync(const std::vector<std::string> & args)397 pid_t ForkExecvpAsync(const std::vector<std::string>& args) {
398     auto argv = ConvertToArgv(args);
399 
400     pid_t pid = fork();
401     if (pid == 0) {
402         close(STDIN_FILENO);
403         close(STDOUT_FILENO);
404         close(STDERR_FILENO);
405 
406         execvp(argv[0], const_cast<char**>(argv.data()));
407         PLOG(ERROR) << "exec in ForkExecvpAsync";
408         _exit(EXIT_FAILURE);
409     }
410     if (pid == -1) {
411         PLOG(ERROR) << "fork in ForkExecvpAsync";
412         return -1;
413     }
414     return pid;
415 }
416 
ReadRandomBytes(size_t bytes,std::string & out)417 status_t ReadRandomBytes(size_t bytes, std::string& out) {
418     out.resize(bytes);
419     return ReadRandomBytes(bytes, &out[0]);
420 }
421 
ReadRandomBytes(size_t bytes,char * buf)422 status_t ReadRandomBytes(size_t bytes, char* buf) {
423     int fd = TEMP_FAILURE_RETRY(open("/dev/urandom", O_RDONLY | O_CLOEXEC | O_NOFOLLOW));
424     if (fd == -1) {
425         return -errno;
426     }
427 
428     ssize_t n;
429     while ((n = TEMP_FAILURE_RETRY(read(fd, &buf[0], bytes))) > 0) {
430         bytes -= n;
431         buf += n;
432     }
433     close(fd);
434 
435     if (bytes == 0) {
436         return OK;
437     } else {
438         return -EIO;
439     }
440 }
441 
GenerateRandomUuid(std::string & out)442 status_t GenerateRandomUuid(std::string& out) {
443     status_t res = ReadRandomBytes(16, out);
444     if (res == OK) {
445         out[6] &= 0x0f; /* clear version        */
446         out[6] |= 0x40; /* set to version 4     */
447         out[8] &= 0x3f; /* clear variant        */
448         out[8] |= 0x80; /* set to IETF variant  */
449     }
450     return res;
451 }
452 
HexToStr(const std::string & hex,std::string & str)453 status_t HexToStr(const std::string& hex, std::string& str) {
454     str.clear();
455     bool even = true;
456     char cur = 0;
457     for (size_t i = 0; i < hex.size(); i++) {
458         int val = 0;
459         switch (hex[i]) {
460             // clang-format off
461             case ' ': case '-': case ':': continue;
462             case 'f': case 'F': val = 15; break;
463             case 'e': case 'E': val = 14; break;
464             case 'd': case 'D': val = 13; break;
465             case 'c': case 'C': val = 12; break;
466             case 'b': case 'B': val = 11; break;
467             case 'a': case 'A': val = 10; break;
468             case '9': val = 9; break;
469             case '8': val = 8; break;
470             case '7': val = 7; break;
471             case '6': val = 6; break;
472             case '5': val = 5; break;
473             case '4': val = 4; break;
474             case '3': val = 3; break;
475             case '2': val = 2; break;
476             case '1': val = 1; break;
477             case '0': val = 0; break;
478             default: return -EINVAL;
479                 // clang-format on
480         }
481 
482         if (even) {
483             cur = val << 4;
484         } else {
485             cur += val;
486             str.push_back(cur);
487             cur = 0;
488         }
489         even = !even;
490     }
491     return even ? OK : -EINVAL;
492 }
493 
494 static const char* kLookup = "0123456789abcdef";
495 
StrToHex(const std::string & str,std::string & hex)496 status_t StrToHex(const std::string& str, std::string& hex) {
497     hex.clear();
498     for (size_t i = 0; i < str.size(); i++) {
499         hex.push_back(kLookup[(str[i] & 0xF0) >> 4]);
500         hex.push_back(kLookup[str[i] & 0x0F]);
501     }
502     return OK;
503 }
504 
StrToHex(const KeyBuffer & str,KeyBuffer & hex)505 status_t StrToHex(const KeyBuffer& str, KeyBuffer& hex) {
506     hex.clear();
507     for (size_t i = 0; i < str.size(); i++) {
508         hex.push_back(kLookup[(str.data()[i] & 0xF0) >> 4]);
509         hex.push_back(kLookup[str.data()[i] & 0x0F]);
510     }
511     return OK;
512 }
513 
NormalizeHex(const std::string & in,std::string & out)514 status_t NormalizeHex(const std::string& in, std::string& out) {
515     std::string tmp;
516     if (HexToStr(in, tmp)) {
517         return -EINVAL;
518     }
519     return StrToHex(tmp, out);
520 }
521 
GetBlockDevSize(int fd,uint64_t * size)522 status_t GetBlockDevSize(int fd, uint64_t* size) {
523     if (ioctl(fd, BLKGETSIZE64, size)) {
524         return -errno;
525     }
526 
527     return OK;
528 }
529 
GetBlockDevSize(const std::string & path,uint64_t * size)530 status_t GetBlockDevSize(const std::string& path, uint64_t* size) {
531     int fd = open(path.c_str(), O_RDONLY | O_CLOEXEC);
532     status_t res = OK;
533 
534     if (fd < 0) {
535         return -errno;
536     }
537 
538     res = GetBlockDevSize(fd, size);
539 
540     close(fd);
541 
542     return res;
543 }
544 
GetBlockDev512Sectors(const std::string & path,uint64_t * nr_sec)545 status_t GetBlockDev512Sectors(const std::string& path, uint64_t* nr_sec) {
546     uint64_t size;
547     status_t res = GetBlockDevSize(path, &size);
548 
549     if (res != OK) {
550         return res;
551     }
552 
553     *nr_sec = size / 512;
554 
555     return OK;
556 }
557 
GetFreeBytes(const std::string & path)558 uint64_t GetFreeBytes(const std::string& path) {
559     struct statvfs sb;
560     if (statvfs(path.c_str(), &sb) == 0) {
561         return (uint64_t)sb.f_bavail * sb.f_frsize;
562     } else {
563         return -1;
564     }
565 }
566 
567 // TODO: borrowed from frameworks/native/libs/diskusage/ which should
568 // eventually be migrated into system/
stat_size(struct stat * s)569 static int64_t stat_size(struct stat* s) {
570     int64_t blksize = s->st_blksize;
571     // count actual blocks used instead of nominal file size
572     int64_t size = s->st_blocks * 512;
573 
574     if (blksize) {
575         /* round up to filesystem block size */
576         size = (size + blksize - 1) & (~(blksize - 1));
577     }
578 
579     return size;
580 }
581 
582 // TODO: borrowed from frameworks/native/libs/diskusage/ which should
583 // eventually be migrated into system/
calculate_dir_size(int dfd)584 int64_t calculate_dir_size(int dfd) {
585     int64_t size = 0;
586     struct stat s;
587     DIR* d;
588     struct dirent* de;
589 
590     d = fdopendir(dfd);
591     if (d == NULL) {
592         close(dfd);
593         return 0;
594     }
595 
596     while ((de = readdir(d))) {
597         const char* name = de->d_name;
598         if (fstatat(dfd, name, &s, AT_SYMLINK_NOFOLLOW) == 0) {
599             size += stat_size(&s);
600         }
601         if (de->d_type == DT_DIR) {
602             int subfd;
603 
604             /* always skip "." and ".." */
605             if (name[0] == '.') {
606                 if (name[1] == 0) continue;
607                 if ((name[1] == '.') && (name[2] == 0)) continue;
608             }
609 
610             subfd = openat(dfd, name, O_RDONLY | O_DIRECTORY | O_CLOEXEC);
611             if (subfd >= 0) {
612                 size += calculate_dir_size(subfd);
613             }
614         }
615     }
616     closedir(d);
617     return size;
618 }
619 
GetTreeBytes(const std::string & path)620 uint64_t GetTreeBytes(const std::string& path) {
621     int dirfd = open(path.c_str(), O_RDONLY | O_DIRECTORY | O_CLOEXEC);
622     if (dirfd < 0) {
623         PLOG(WARNING) << "Failed to open " << path;
624         return -1;
625     } else {
626         return calculate_dir_size(dirfd);
627     }
628 }
629 
IsFilesystemSupported(const std::string & fsType)630 bool IsFilesystemSupported(const std::string& fsType) {
631     std::string supported;
632     if (!ReadFileToString(kProcFilesystems, &supported)) {
633         PLOG(ERROR) << "Failed to read supported filesystems";
634         return false;
635     }
636     return supported.find(fsType + "\n") != std::string::npos;
637 }
638 
WipeBlockDevice(const std::string & path)639 status_t WipeBlockDevice(const std::string& path) {
640     status_t res = -1;
641     const char* c_path = path.c_str();
642     uint64_t range[2] = {0, 0};
643 
644     int fd = TEMP_FAILURE_RETRY(open(c_path, O_RDWR | O_CLOEXEC));
645     if (fd == -1) {
646         PLOG(ERROR) << "Failed to open " << path;
647         goto done;
648     }
649 
650     if (GetBlockDevSize(fd, &range[1]) != OK) {
651         PLOG(ERROR) << "Failed to determine size of " << path;
652         goto done;
653     }
654 
655     LOG(INFO) << "About to discard " << range[1] << " on " << path;
656     if (ioctl(fd, BLKDISCARD, &range) == 0) {
657         LOG(INFO) << "Discard success on " << path;
658         res = 0;
659     } else {
660         PLOG(ERROR) << "Discard failure on " << path;
661     }
662 
663 done:
664     close(fd);
665     return res;
666 }
667 
isValidFilename(const std::string & name)668 static bool isValidFilename(const std::string& name) {
669     if (name.empty() || (name == ".") || (name == "..") || (name.find('/') != std::string::npos)) {
670         return false;
671     } else {
672         return true;
673     }
674 }
675 
BuildKeyPath(const std::string & partGuid)676 std::string BuildKeyPath(const std::string& partGuid) {
677     return StringPrintf("%s/expand_%s.key", kKeyPath, partGuid.c_str());
678 }
679 
BuildDataSystemLegacyPath(userid_t userId)680 std::string BuildDataSystemLegacyPath(userid_t userId) {
681     return StringPrintf("%s/system/users/%u", BuildDataPath("").c_str(), userId);
682 }
683 
BuildDataSystemCePath(userid_t userId)684 std::string BuildDataSystemCePath(userid_t userId) {
685     return StringPrintf("%s/system_ce/%u", BuildDataPath("").c_str(), userId);
686 }
687 
BuildDataSystemDePath(userid_t userId)688 std::string BuildDataSystemDePath(userid_t userId) {
689     return StringPrintf("%s/system_de/%u", BuildDataPath("").c_str(), userId);
690 }
691 
BuildDataMiscLegacyPath(userid_t userId)692 std::string BuildDataMiscLegacyPath(userid_t userId) {
693     return StringPrintf("%s/misc/user/%u", BuildDataPath("").c_str(), userId);
694 }
695 
BuildDataMiscCePath(userid_t userId)696 std::string BuildDataMiscCePath(userid_t userId) {
697     return StringPrintf("%s/misc_ce/%u", BuildDataPath("").c_str(), userId);
698 }
699 
BuildDataMiscDePath(userid_t userId)700 std::string BuildDataMiscDePath(userid_t userId) {
701     return StringPrintf("%s/misc_de/%u", BuildDataPath("").c_str(), userId);
702 }
703 
704 // Keep in sync with installd (frameworks/native/cmds/installd/utils.h)
BuildDataProfilesDePath(userid_t userId)705 std::string BuildDataProfilesDePath(userid_t userId) {
706     return StringPrintf("%s/misc/profiles/cur/%u", BuildDataPath("").c_str(), userId);
707 }
708 
BuildDataVendorCePath(userid_t userId)709 std::string BuildDataVendorCePath(userid_t userId) {
710     return StringPrintf("%s/vendor_ce/%u", BuildDataPath("").c_str(), userId);
711 }
712 
BuildDataVendorDePath(userid_t userId)713 std::string BuildDataVendorDePath(userid_t userId) {
714     return StringPrintf("%s/vendor_de/%u", BuildDataPath("").c_str(), userId);
715 }
716 
BuildDataPath(const std::string & volumeUuid)717 std::string BuildDataPath(const std::string& volumeUuid) {
718     // TODO: unify with installd path generation logic
719     if (volumeUuid.empty()) {
720         return "/data";
721     } else {
722         CHECK(isValidFilename(volumeUuid));
723         return StringPrintf("/mnt/expand/%s", volumeUuid.c_str());
724     }
725 }
726 
BuildDataMediaCePath(const std::string & volumeUuid,userid_t userId)727 std::string BuildDataMediaCePath(const std::string& volumeUuid, userid_t userId) {
728     // TODO: unify with installd path generation logic
729     std::string data(BuildDataPath(volumeUuid));
730     return StringPrintf("%s/media/%u", data.c_str(), userId);
731 }
732 
BuildDataUserCePath(const std::string & volumeUuid,userid_t userId)733 std::string BuildDataUserCePath(const std::string& volumeUuid, userid_t userId) {
734     // TODO: unify with installd path generation logic
735     std::string data(BuildDataPath(volumeUuid));
736     if (volumeUuid.empty() && userId == 0) {
737         std::string legacy = StringPrintf("%s/data", data.c_str());
738         struct stat sb;
739         if (lstat(legacy.c_str(), &sb) == 0 && S_ISDIR(sb.st_mode)) {
740             /* /data/data is dir, return /data/data for legacy system */
741             return legacy;
742         }
743     }
744     return StringPrintf("%s/user/%u", data.c_str(), userId);
745 }
746 
BuildDataUserDePath(const std::string & volumeUuid,userid_t userId)747 std::string BuildDataUserDePath(const std::string& volumeUuid, userid_t userId) {
748     // TODO: unify with installd path generation logic
749     std::string data(BuildDataPath(volumeUuid));
750     return StringPrintf("%s/user_de/%u", data.c_str(), userId);
751 }
752 
GetDevice(const std::string & path)753 dev_t GetDevice(const std::string& path) {
754     struct stat sb;
755     if (stat(path.c_str(), &sb)) {
756         PLOG(WARNING) << "Failed to stat " << path;
757         return 0;
758     } else {
759         return sb.st_dev;
760     }
761 }
762 
RestoreconRecursive(const std::string & path)763 status_t RestoreconRecursive(const std::string& path) {
764     LOG(DEBUG) << "Starting restorecon of " << path;
765 
766     static constexpr const char* kRestoreconString = "selinux.restorecon_recursive";
767 
768     android::base::SetProperty(kRestoreconString, "");
769     android::base::SetProperty(kRestoreconString, path);
770 
771     android::base::WaitForProperty(kRestoreconString, path);
772 
773     LOG(DEBUG) << "Finished restorecon of " << path;
774     return OK;
775 }
776 
Readlinkat(int dirfd,const std::string & path,std::string * result)777 bool Readlinkat(int dirfd, const std::string& path, std::string* result) {
778     // Shamelessly borrowed from android::base::Readlink()
779     result->clear();
780 
781     // Most Linux file systems (ext2 and ext4, say) limit symbolic links to
782     // 4095 bytes. Since we'll copy out into the string anyway, it doesn't
783     // waste memory to just start there. We add 1 so that we can recognize
784     // whether it actually fit (rather than being truncated to 4095).
785     std::vector<char> buf(4095 + 1);
786     while (true) {
787         ssize_t size = readlinkat(dirfd, path.c_str(), &buf[0], buf.size());
788         // Unrecoverable error?
789         if (size == -1) return false;
790         // It fit! (If size == buf.size(), it may have been truncated.)
791         if (static_cast<size_t>(size) < buf.size()) {
792             result->assign(&buf[0], size);
793             return true;
794         }
795         // Double our buffer and try again.
796         buf.resize(buf.size() * 2);
797     }
798 }
799 
GetMajorBlockVirtioBlk()800 static unsigned int GetMajorBlockVirtioBlk() {
801     std::string devices;
802     if (!ReadFileToString(kProcDevices, &devices)) {
803         PLOG(ERROR) << "Unable to open /proc/devices";
804         return 0;
805     }
806 
807     bool blockSection = false;
808     for (auto line : android::base::Split(devices, "\n")) {
809         if (line == "Block devices:") {
810             blockSection = true;
811         } else if (line == "Character devices:") {
812             blockSection = false;
813         } else if (blockSection) {
814             auto tokens = android::base::Split(line, " ");
815             if (tokens.size() == 2 && tokens[1] == "virtblk") {
816                 return std::stoul(tokens[0]);
817             }
818         }
819     }
820 
821     return 0;
822 }
823 
IsVirtioBlkDevice(unsigned int major)824 bool IsVirtioBlkDevice(unsigned int major) {
825     // Most virtualized platforms expose block devices with the virtio-blk
826     // block device driver. Unfortunately, this driver does not use a fixed
827     // major number, but relies on the kernel to assign one from a specific
828     // range of block majors, which are allocated for "LOCAL/EXPERIMENAL USE"
829     // per Documentation/devices.txt. This is true even for the latest Linux
830     // kernel (4.4; see init() in drivers/block/virtio_blk.c).
831     static unsigned int kMajorBlockVirtioBlk = GetMajorBlockVirtioBlk();
832     return kMajorBlockVirtioBlk && major == kMajorBlockVirtioBlk;
833 }
834 
findMountPointsWithPrefix(const std::string & prefix,std::list<std::string> & mountPoints)835 static status_t findMountPointsWithPrefix(const std::string& prefix,
836                                           std::list<std::string>& mountPoints) {
837     // Add a trailing slash if the client didn't provide one so that we don't match /foo/barbaz
838     // when the prefix is /foo/bar
839     std::string prefixWithSlash(prefix);
840     if (prefix.back() != '/') {
841         android::base::StringAppendF(&prefixWithSlash, "/");
842     }
843 
844     std::unique_ptr<FILE, int (*)(FILE*)> mnts(setmntent("/proc/mounts", "re"), endmntent);
845     if (!mnts) {
846         PLOG(ERROR) << "Unable to open /proc/mounts";
847         return -errno;
848     }
849 
850     // Some volumes can be stacked on each other, so force unmount in
851     // reverse order to give us the best chance of success.
852     struct mntent* mnt;  // getmntent returns a thread local, so it's safe.
853     while ((mnt = getmntent(mnts.get())) != nullptr) {
854         auto mountPoint = std::string(mnt->mnt_dir) + "/";
855         if (android::base::StartsWith(mountPoint, prefixWithSlash)) {
856             mountPoints.push_front(mountPoint);
857         }
858     }
859     return OK;
860 }
861 
862 // Unmount all mountpoints that start with prefix. prefix itself doesn't need to be a mountpoint.
UnmountTreeWithPrefix(const std::string & prefix)863 status_t UnmountTreeWithPrefix(const std::string& prefix) {
864     std::list<std::string> toUnmount;
865     status_t result = findMountPointsWithPrefix(prefix, toUnmount);
866     if (result < 0) {
867         return result;
868     }
869     for (const auto& path : toUnmount) {
870         if (umount2(path.c_str(), MNT_DETACH)) {
871             PLOG(ERROR) << "Failed to unmount " << path;
872             result = -errno;
873         }
874     }
875     return result;
876 }
877 
UnmountTree(const std::string & mountPoint)878 status_t UnmountTree(const std::string& mountPoint) {
879     if (TEMP_FAILURE_RETRY(umount2(mountPoint.c_str(), MNT_DETACH)) < 0 && errno != EINVAL &&
880         errno != ENOENT) {
881         PLOG(ERROR) << "Failed to unmount " << mountPoint;
882         return -errno;
883     }
884     return OK;
885 }
886 
delete_dir_contents(DIR * dir)887 static status_t delete_dir_contents(DIR* dir) {
888     // Shamelessly borrowed from android::installd
889     int dfd = dirfd(dir);
890     if (dfd < 0) {
891         return -errno;
892     }
893 
894     status_t result = OK;
895     struct dirent* de;
896     while ((de = readdir(dir))) {
897         const char* name = de->d_name;
898         if (de->d_type == DT_DIR) {
899             /* always skip "." and ".." */
900             if (name[0] == '.') {
901                 if (name[1] == 0) continue;
902                 if ((name[1] == '.') && (name[2] == 0)) continue;
903             }
904 
905             android::base::unique_fd subfd(
906                 openat(dfd, name, O_RDONLY | O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC));
907             if (subfd.get() == -1) {
908                 PLOG(ERROR) << "Couldn't openat " << name;
909                 result = -errno;
910                 continue;
911             }
912             std::unique_ptr<DIR, decltype(&closedir)> subdirp(
913                 android::base::Fdopendir(std::move(subfd)), closedir);
914             if (!subdirp) {
915                 PLOG(ERROR) << "Couldn't fdopendir " << name;
916                 result = -errno;
917                 continue;
918             }
919             result = delete_dir_contents(subdirp.get());
920             if (unlinkat(dfd, name, AT_REMOVEDIR) < 0) {
921                 PLOG(ERROR) << "Couldn't unlinkat " << name;
922                 result = -errno;
923             }
924         } else {
925             if (unlinkat(dfd, name, 0) < 0) {
926                 PLOG(ERROR) << "Couldn't unlinkat " << name;
927                 result = -errno;
928             }
929         }
930     }
931     return result;
932 }
933 
DeleteDirContentsAndDir(const std::string & pathname)934 status_t DeleteDirContentsAndDir(const std::string& pathname) {
935     status_t res = DeleteDirContents(pathname);
936     if (res < 0) {
937         return res;
938     }
939     if (TEMP_FAILURE_RETRY(rmdir(pathname.c_str())) < 0 && errno != ENOENT) {
940         PLOG(ERROR) << "rmdir failed on " << pathname;
941         return -errno;
942     }
943     LOG(VERBOSE) << "Success: rmdir on " << pathname;
944     return OK;
945 }
946 
DeleteDirContents(const std::string & pathname)947 status_t DeleteDirContents(const std::string& pathname) {
948     // Shamelessly borrowed from android::installd
949     std::unique_ptr<DIR, decltype(&closedir)> dirp(opendir(pathname.c_str()), closedir);
950     if (!dirp) {
951         if (errno == ENOENT) {
952             return OK;
953         }
954         PLOG(ERROR) << "Failed to opendir " << pathname;
955         return -errno;
956     }
957     return delete_dir_contents(dirp.get());
958 }
959 
960 // TODO(118708649): fix duplication with init/util.h
WaitForFile(const char * filename,std::chrono::nanoseconds timeout)961 status_t WaitForFile(const char* filename, std::chrono::nanoseconds timeout) {
962     android::base::Timer t;
963     while (t.duration() < timeout) {
964         struct stat sb;
965         if (stat(filename, &sb) != -1) {
966             LOG(INFO) << "wait for '" << filename << "' took " << t;
967             return 0;
968         }
969         std::this_thread::sleep_for(10ms);
970     }
971     LOG(WARNING) << "wait for '" << filename << "' timed out and took " << t;
972     return -1;
973 }
974 
FsyncDirectory(const std::string & dirname)975 bool FsyncDirectory(const std::string& dirname) {
976     android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(dirname.c_str(), O_RDONLY | O_CLOEXEC)));
977     if (fd == -1) {
978         PLOG(ERROR) << "Failed to open " << dirname;
979         return false;
980     }
981     if (fsync(fd) == -1) {
982         if (errno == EROFS || errno == EINVAL) {
983             PLOG(WARNING) << "Skip fsync " << dirname
984                           << " on a file system does not support synchronization";
985         } else {
986             PLOG(ERROR) << "Failed to fsync " << dirname;
987             return false;
988         }
989     }
990     return true;
991 }
992 
writeStringToFile(const std::string & payload,const std::string & filename)993 bool writeStringToFile(const std::string& payload, const std::string& filename) {
994     android::base::unique_fd fd(TEMP_FAILURE_RETRY(
995         open(filename.c_str(), O_WRONLY | O_CREAT | O_NOFOLLOW | O_TRUNC | O_CLOEXEC, 0666)));
996     if (fd == -1) {
997         PLOG(ERROR) << "Failed to open " << filename;
998         return false;
999     }
1000     if (!android::base::WriteStringToFd(payload, fd)) {
1001         PLOG(ERROR) << "Failed to write to " << filename;
1002         unlink(filename.c_str());
1003         return false;
1004     }
1005     // fsync as close won't guarantee flush data
1006     // see close(2), fsync(2) and b/68901441
1007     if (fsync(fd) == -1) {
1008         if (errno == EROFS || errno == EINVAL) {
1009             PLOG(WARNING) << "Skip fsync " << filename
1010                           << " on a file system does not support synchronization";
1011         } else {
1012             PLOG(ERROR) << "Failed to fsync " << filename;
1013             unlink(filename.c_str());
1014             return false;
1015         }
1016     }
1017     return true;
1018 }
1019 
1020 }  // namespace vold
1021 }  // namespace android
1022