Home | History | Annotate | Download | only in vold
      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 "sehandle.h"
     18 #include "Utils.h"
     19 #include "Process.h"
     20 
     21 #include <android-base/file.h>
     22 #include <android-base/logging.h>
     23 #include <android-base/stringprintf.h>
     24 #include <cutils/fs.h>
     25 #include <cutils/properties.h>
     26 #include <private/android_filesystem_config.h>
     27 #include <logwrap/logwrap.h>
     28 
     29 #include <mutex>
     30 #include <dirent.h>
     31 #include <fcntl.h>
     32 #include <linux/fs.h>
     33 #include <stdlib.h>
     34 #include <sys/mount.h>
     35 #include <sys/types.h>
     36 #include <sys/stat.h>
     37 #include <sys/wait.h>
     38 #include <sys/statvfs.h>
     39 
     40 #ifndef UMOUNT_NOFOLLOW
     41 #define UMOUNT_NOFOLLOW    0x00000008  /* Don't follow symlink on umount */
     42 #endif
     43 
     44 using android::base::ReadFileToString;
     45 using android::base::StringPrintf;
     46 
     47 namespace android {
     48 namespace vold {
     49 
     50 security_context_t sBlkidContext = nullptr;
     51 security_context_t sBlkidUntrustedContext = nullptr;
     52 security_context_t sFsckContext = nullptr;
     53 security_context_t sFsckUntrustedContext = nullptr;
     54 
     55 static const char* kBlkidPath = "/system/bin/blkid";
     56 static const char* kKeyPath = "/data/misc/vold";
     57 
     58 static const char* kProcFilesystems = "/proc/filesystems";
     59 
     60 status_t CreateDeviceNode(const std::string& path, dev_t dev) {
     61     const char* cpath = path.c_str();
     62     status_t res = 0;
     63 
     64     char* secontext = nullptr;
     65     if (sehandle) {
     66         if (!selabel_lookup(sehandle, &secontext, cpath, S_IFBLK)) {
     67             setfscreatecon(secontext);
     68         }
     69     }
     70 
     71     mode_t mode = 0660 | S_IFBLK;
     72     if (mknod(cpath, mode, dev) < 0) {
     73         if (errno != EEXIST) {
     74             PLOG(ERROR) << "Failed to create device node for " << major(dev)
     75                     << ":" << minor(dev) << " at " << path;
     76             res = -errno;
     77         }
     78     }
     79 
     80     if (secontext) {
     81         setfscreatecon(nullptr);
     82         freecon(secontext);
     83     }
     84 
     85     return res;
     86 }
     87 
     88 status_t DestroyDeviceNode(const std::string& path) {
     89     const char* cpath = path.c_str();
     90     if (TEMP_FAILURE_RETRY(unlink(cpath))) {
     91         return -errno;
     92     } else {
     93         return OK;
     94     }
     95 }
     96 
     97 status_t PrepareDir(const std::string& path, mode_t mode, uid_t uid, gid_t gid) {
     98     const char* cpath = path.c_str();
     99 
    100     char* secontext = nullptr;
    101     if (sehandle) {
    102         if (!selabel_lookup(sehandle, &secontext, cpath, S_IFDIR)) {
    103             setfscreatecon(secontext);
    104         }
    105     }
    106 
    107     int res = fs_prepare_dir(cpath, mode, uid, gid);
    108 
    109     if (secontext) {
    110         setfscreatecon(nullptr);
    111         freecon(secontext);
    112     }
    113 
    114     if (res == 0) {
    115         return OK;
    116     } else {
    117         return -errno;
    118     }
    119 }
    120 
    121 status_t ForceUnmount(const std::string& path) {
    122     const char* cpath = path.c_str();
    123     if (!umount2(cpath, UMOUNT_NOFOLLOW) || errno == EINVAL || errno == ENOENT) {
    124         return OK;
    125     }
    126     // Apps might still be handling eject request, so wait before
    127     // we start sending signals
    128     sleep(5);
    129 
    130     Process::killProcessesWithOpenFiles(cpath, SIGINT);
    131     sleep(5);
    132     if (!umount2(cpath, UMOUNT_NOFOLLOW) || errno == EINVAL || errno == ENOENT) {
    133         return OK;
    134     }
    135 
    136     Process::killProcessesWithOpenFiles(cpath, SIGTERM);
    137     sleep(5);
    138     if (!umount2(cpath, UMOUNT_NOFOLLOW) || errno == EINVAL || errno == ENOENT) {
    139         return OK;
    140     }
    141 
    142     Process::killProcessesWithOpenFiles(cpath, SIGKILL);
    143     sleep(5);
    144     if (!umount2(cpath, UMOUNT_NOFOLLOW) || errno == EINVAL || errno == ENOENT) {
    145         return OK;
    146     }
    147 
    148     return -errno;
    149 }
    150 
    151 status_t KillProcessesUsingPath(const std::string& path) {
    152     const char* cpath = path.c_str();
    153     if (Process::killProcessesWithOpenFiles(cpath, SIGINT) == 0) {
    154         return OK;
    155     }
    156     sleep(5);
    157 
    158     if (Process::killProcessesWithOpenFiles(cpath, SIGTERM) == 0) {
    159         return OK;
    160     }
    161     sleep(5);
    162 
    163     if (Process::killProcessesWithOpenFiles(cpath, SIGKILL) == 0) {
    164         return OK;
    165     }
    166     sleep(5);
    167 
    168     // Send SIGKILL a second time to determine if we've
    169     // actually killed everyone with open files
    170     if (Process::killProcessesWithOpenFiles(cpath, SIGKILL) == 0) {
    171         return OK;
    172     }
    173     PLOG(ERROR) << "Failed to kill processes using " << path;
    174     return -EBUSY;
    175 }
    176 
    177 status_t BindMount(const std::string& source, const std::string& target) {
    178     if (::mount(source.c_str(), target.c_str(), "", MS_BIND, NULL)) {
    179         PLOG(ERROR) << "Failed to bind mount " << source << " to " << target;
    180         return -errno;
    181     }
    182     return OK;
    183 }
    184 
    185 static status_t readMetadata(const std::string& path, std::string& fsType,
    186         std::string& fsUuid, std::string& fsLabel, bool untrusted) {
    187     fsType.clear();
    188     fsUuid.clear();
    189     fsLabel.clear();
    190 
    191     std::vector<std::string> cmd;
    192     cmd.push_back(kBlkidPath);
    193     cmd.push_back("-c");
    194     cmd.push_back("/dev/null");
    195     cmd.push_back("-s");
    196     cmd.push_back("TYPE");
    197     cmd.push_back("-s");
    198     cmd.push_back("UUID");
    199     cmd.push_back("-s");
    200     cmd.push_back("LABEL");
    201     cmd.push_back(path);
    202 
    203     std::vector<std::string> output;
    204     status_t res = ForkExecvp(cmd, output, untrusted ? sBlkidUntrustedContext : sBlkidContext);
    205     if (res != OK) {
    206         LOG(WARNING) << "blkid failed to identify " << path;
    207         return res;
    208     }
    209 
    210     char value[128];
    211     for (const auto& line : output) {
    212         // Extract values from blkid output, if defined
    213         const char* cline = line.c_str();
    214         const char* start = strstr(cline, "TYPE=");
    215         if (start != nullptr && sscanf(start + 5, "\"%127[^\"]\"", value) == 1) {
    216             fsType = value;
    217         }
    218 
    219         start = strstr(cline, "UUID=");
    220         if (start != nullptr && sscanf(start + 5, "\"%127[^\"]\"", value) == 1) {
    221             fsUuid = value;
    222         }
    223 
    224         start = strstr(cline, "LABEL=");
    225         if (start != nullptr && sscanf(start + 6, "\"%127[^\"]\"", value) == 1) {
    226             fsLabel = value;
    227         }
    228     }
    229 
    230     return OK;
    231 }
    232 
    233 status_t ReadMetadata(const std::string& path, std::string& fsType,
    234         std::string& fsUuid, std::string& fsLabel) {
    235     return readMetadata(path, fsType, fsUuid, fsLabel, false);
    236 }
    237 
    238 status_t ReadMetadataUntrusted(const std::string& path, std::string& fsType,
    239         std::string& fsUuid, std::string& fsLabel) {
    240     return readMetadata(path, fsType, fsUuid, fsLabel, true);
    241 }
    242 
    243 status_t ForkExecvp(const std::vector<std::string>& args) {
    244     return ForkExecvp(args, nullptr);
    245 }
    246 
    247 status_t ForkExecvp(const std::vector<std::string>& args, security_context_t context) {
    248     size_t argc = args.size();
    249     char** argv = (char**) calloc(argc, sizeof(char*));
    250     for (size_t i = 0; i < argc; i++) {
    251         argv[i] = (char*) args[i].c_str();
    252         if (i == 0) {
    253             LOG(VERBOSE) << args[i];
    254         } else {
    255             LOG(VERBOSE) << "    " << args[i];
    256         }
    257     }
    258 
    259     if (setexeccon(context)) {
    260         LOG(ERROR) << "Failed to setexeccon";
    261         abort();
    262     }
    263     status_t res = android_fork_execvp(argc, argv, NULL, false, true);
    264     if (setexeccon(nullptr)) {
    265         LOG(ERROR) << "Failed to setexeccon";
    266         abort();
    267     }
    268 
    269     free(argv);
    270     return res;
    271 }
    272 
    273 status_t ForkExecvp(const std::vector<std::string>& args,
    274         std::vector<std::string>& output) {
    275     return ForkExecvp(args, output, nullptr);
    276 }
    277 
    278 status_t ForkExecvp(const std::vector<std::string>& args,
    279         std::vector<std::string>& output, security_context_t context) {
    280     std::string cmd;
    281     for (size_t i = 0; i < args.size(); i++) {
    282         cmd += args[i] + " ";
    283         if (i == 0) {
    284             LOG(VERBOSE) << args[i];
    285         } else {
    286             LOG(VERBOSE) << "    " << args[i];
    287         }
    288     }
    289     output.clear();
    290 
    291     if (setexeccon(context)) {
    292         LOG(ERROR) << "Failed to setexeccon";
    293         abort();
    294     }
    295     FILE* fp = popen(cmd.c_str(), "r");
    296     if (setexeccon(nullptr)) {
    297         LOG(ERROR) << "Failed to setexeccon";
    298         abort();
    299     }
    300 
    301     if (!fp) {
    302         PLOG(ERROR) << "Failed to popen " << cmd;
    303         return -errno;
    304     }
    305     char line[1024];
    306     while (fgets(line, sizeof(line), fp) != nullptr) {
    307         LOG(VERBOSE) << line;
    308         output.push_back(std::string(line));
    309     }
    310     if (pclose(fp) != 0) {
    311         PLOG(ERROR) << "Failed to pclose " << cmd;
    312         return -errno;
    313     }
    314 
    315     return OK;
    316 }
    317 
    318 pid_t ForkExecvpAsync(const std::vector<std::string>& args) {
    319     size_t argc = args.size();
    320     char** argv = (char**) calloc(argc + 1, sizeof(char*));
    321     for (size_t i = 0; i < argc; i++) {
    322         argv[i] = (char*) args[i].c_str();
    323         if (i == 0) {
    324             LOG(VERBOSE) << args[i];
    325         } else {
    326             LOG(VERBOSE) << "    " << args[i];
    327         }
    328     }
    329 
    330     pid_t pid = fork();
    331     if (pid == 0) {
    332         close(STDIN_FILENO);
    333         close(STDOUT_FILENO);
    334         close(STDERR_FILENO);
    335 
    336         if (execvp(argv[0], argv)) {
    337             PLOG(ERROR) << "Failed to exec";
    338         }
    339 
    340         _exit(1);
    341     }
    342 
    343     if (pid == -1) {
    344         PLOG(ERROR) << "Failed to exec";
    345     }
    346 
    347     free(argv);
    348     return pid;
    349 }
    350 
    351 status_t ReadRandomBytes(size_t bytes, std::string& out) {
    352     out.clear();
    353 
    354     int fd = TEMP_FAILURE_RETRY(open("/dev/urandom", O_RDONLY | O_CLOEXEC | O_NOFOLLOW));
    355     if (fd == -1) {
    356         return -errno;
    357     }
    358 
    359     char buf[BUFSIZ];
    360     size_t n;
    361     while ((n = TEMP_FAILURE_RETRY(read(fd, &buf[0], std::min(sizeof(buf), bytes)))) > 0) {
    362         out.append(buf, n);
    363         bytes -= n;
    364     }
    365     close(fd);
    366 
    367     if (bytes == 0) {
    368         return OK;
    369     } else {
    370         return -EIO;
    371     }
    372 }
    373 
    374 status_t HexToStr(const std::string& hex, std::string& str) {
    375     str.clear();
    376     bool even = true;
    377     char cur = 0;
    378     for (size_t i = 0; i < hex.size(); i++) {
    379         int val = 0;
    380         switch (hex[i]) {
    381         case ' ': case '-': case ':': continue;
    382         case 'f': case 'F': val = 15; break;
    383         case 'e': case 'E': val = 14; break;
    384         case 'd': case 'D': val = 13; break;
    385         case 'c': case 'C': val = 12; break;
    386         case 'b': case 'B': val = 11; break;
    387         case 'a': case 'A': val = 10; break;
    388         case '9': val = 9; break;
    389         case '8': val = 8; break;
    390         case '7': val = 7; break;
    391         case '6': val = 6; break;
    392         case '5': val = 5; break;
    393         case '4': val = 4; break;
    394         case '3': val = 3; break;
    395         case '2': val = 2; break;
    396         case '1': val = 1; break;
    397         case '0': val = 0; break;
    398         default: return -EINVAL;
    399         }
    400 
    401         if (even) {
    402             cur = val << 4;
    403         } else {
    404             cur += val;
    405             str.push_back(cur);
    406             cur = 0;
    407         }
    408         even = !even;
    409     }
    410     return even ? OK : -EINVAL;
    411 }
    412 
    413 static const char* kLookup = "0123456789abcdef";
    414 
    415 status_t StrToHex(const std::string& str, std::string& hex) {
    416     hex.clear();
    417     for (size_t i = 0; i < str.size(); i++) {
    418         hex.push_back(kLookup[(str[i] & 0xF0) >> 4]);
    419         hex.push_back(kLookup[str[i] & 0x0F]);
    420     }
    421     return OK;
    422 }
    423 
    424 status_t NormalizeHex(const std::string& in, std::string& out) {
    425     std::string tmp;
    426     if (HexToStr(in, tmp)) {
    427         return -EINVAL;
    428     }
    429     return StrToHex(tmp, out);
    430 }
    431 
    432 uint64_t GetFreeBytes(const std::string& path) {
    433     struct statvfs sb;
    434     if (statvfs(path.c_str(), &sb) == 0) {
    435         return (uint64_t) sb.f_bavail * sb.f_frsize;
    436     } else {
    437         return -1;
    438     }
    439 }
    440 
    441 // TODO: borrowed from frameworks/native/libs/diskusage/ which should
    442 // eventually be migrated into system/
    443 static int64_t stat_size(struct stat *s) {
    444     int64_t blksize = s->st_blksize;
    445     // count actual blocks used instead of nominal file size
    446     int64_t size = s->st_blocks * 512;
    447 
    448     if (blksize) {
    449         /* round up to filesystem block size */
    450         size = (size + blksize - 1) & (~(blksize - 1));
    451     }
    452 
    453     return size;
    454 }
    455 
    456 // TODO: borrowed from frameworks/native/libs/diskusage/ which should
    457 // eventually be migrated into system/
    458 int64_t calculate_dir_size(int dfd) {
    459     int64_t size = 0;
    460     struct stat s;
    461     DIR *d;
    462     struct dirent *de;
    463 
    464     d = fdopendir(dfd);
    465     if (d == NULL) {
    466         close(dfd);
    467         return 0;
    468     }
    469 
    470     while ((de = readdir(d))) {
    471         const char *name = de->d_name;
    472         if (fstatat(dfd, name, &s, AT_SYMLINK_NOFOLLOW) == 0) {
    473             size += stat_size(&s);
    474         }
    475         if (de->d_type == DT_DIR) {
    476             int subfd;
    477 
    478             /* always skip "." and ".." */
    479             if (name[0] == '.') {
    480                 if (name[1] == 0)
    481                     continue;
    482                 if ((name[1] == '.') && (name[2] == 0))
    483                     continue;
    484             }
    485 
    486             subfd = openat(dfd, name, O_RDONLY | O_DIRECTORY | O_CLOEXEC);
    487             if (subfd >= 0) {
    488                 size += calculate_dir_size(subfd);
    489             }
    490         }
    491     }
    492     closedir(d);
    493     return size;
    494 }
    495 
    496 uint64_t GetTreeBytes(const std::string& path) {
    497     int dirfd = open(path.c_str(), O_RDONLY | O_DIRECTORY | O_CLOEXEC);
    498     if (dirfd < 0) {
    499         PLOG(WARNING) << "Failed to open " << path;
    500         return -1;
    501     } else {
    502         uint64_t res = calculate_dir_size(dirfd);
    503         close(dirfd);
    504         return res;
    505     }
    506 }
    507 
    508 bool IsFilesystemSupported(const std::string& fsType) {
    509     std::string supported;
    510     if (!ReadFileToString(kProcFilesystems, &supported)) {
    511         PLOG(ERROR) << "Failed to read supported filesystems";
    512         return false;
    513     }
    514     return supported.find(fsType + "\n") != std::string::npos;
    515 }
    516 
    517 status_t WipeBlockDevice(const std::string& path) {
    518     status_t res = -1;
    519     const char* c_path = path.c_str();
    520     unsigned long nr_sec = 0;
    521     unsigned long long range[2];
    522 
    523     int fd = TEMP_FAILURE_RETRY(open(c_path, O_RDWR | O_CLOEXEC));
    524     if (fd == -1) {
    525         PLOG(ERROR) << "Failed to open " << path;
    526         goto done;
    527     }
    528 
    529     if ((ioctl(fd, BLKGETSIZE, &nr_sec)) == -1) {
    530         PLOG(ERROR) << "Failed to determine size of " << path;
    531         goto done;
    532     }
    533 
    534     range[0] = 0;
    535     range[1] = (unsigned long long) nr_sec * 512;
    536 
    537     LOG(INFO) << "About to discard " << range[1] << " on " << path;
    538     if (ioctl(fd, BLKDISCARD, &range) == 0) {
    539         LOG(INFO) << "Discard success on " << path;
    540         res = 0;
    541     } else {
    542         PLOG(ERROR) << "Discard failure on " << path;
    543     }
    544 
    545 done:
    546     close(fd);
    547     return res;
    548 }
    549 
    550 static bool isValidFilename(const std::string& name) {
    551     if (name.empty() || (name == ".") || (name == "..")
    552             || (name.find('/') != std::string::npos)) {
    553         return false;
    554     } else {
    555         return true;
    556     }
    557 }
    558 
    559 std::string BuildKeyPath(const std::string& partGuid) {
    560     return StringPrintf("%s/expand_%s.key", kKeyPath, partGuid.c_str());
    561 }
    562 
    563 std::string BuildDataSystemLegacyPath(userid_t userId) {
    564     return StringPrintf("%s/system/users/%u", BuildDataPath(nullptr).c_str(), userId);
    565 }
    566 
    567 std::string BuildDataSystemCePath(userid_t userId) {
    568     return StringPrintf("%s/system_ce/%u", BuildDataPath(nullptr).c_str(), userId);
    569 }
    570 
    571 std::string BuildDataSystemDePath(userid_t userId) {
    572     return StringPrintf("%s/system_de/%u", BuildDataPath(nullptr).c_str(), userId);
    573 }
    574 
    575 std::string BuildDataMiscLegacyPath(userid_t userId) {
    576     return StringPrintf("%s/misc/user/%u", BuildDataPath(nullptr).c_str(), userId);
    577 }
    578 
    579 std::string BuildDataMiscCePath(userid_t userId) {
    580     return StringPrintf("%s/misc_ce/%u", BuildDataPath(nullptr).c_str(), userId);
    581 }
    582 
    583 std::string BuildDataMiscDePath(userid_t userId) {
    584     return StringPrintf("%s/misc_de/%u", BuildDataPath(nullptr).c_str(), userId);
    585 }
    586 
    587 // Keep in sync with installd (frameworks/native/cmds/installd/utils.h)
    588 std::string BuildDataProfilesDePath(userid_t userId) {
    589     return StringPrintf("%s/misc/profiles/cur/%u", BuildDataPath(nullptr).c_str(), userId);
    590 }
    591 
    592 std::string BuildDataPath(const char* volumeUuid) {
    593     // TODO: unify with installd path generation logic
    594     if (volumeUuid == nullptr) {
    595         return "/data";
    596     } else {
    597         CHECK(isValidFilename(volumeUuid));
    598         return StringPrintf("/mnt/expand/%s", volumeUuid);
    599     }
    600 }
    601 
    602 std::string BuildDataMediaCePath(const char* volumeUuid, userid_t userId) {
    603     // TODO: unify with installd path generation logic
    604     std::string data(BuildDataPath(volumeUuid));
    605     return StringPrintf("%s/media/%u", data.c_str(), userId);
    606 }
    607 
    608 std::string BuildDataUserCePath(const char* volumeUuid, userid_t userId) {
    609     // TODO: unify with installd path generation logic
    610     std::string data(BuildDataPath(volumeUuid));
    611     if (volumeUuid == nullptr) {
    612         if (userId == 0) {
    613             return StringPrintf("%s/data", data.c_str());
    614         } else {
    615             return StringPrintf("%s/user/%u", data.c_str(), userId);
    616         }
    617     } else {
    618         return StringPrintf("%s/user/%u", data.c_str(), userId);
    619     }
    620 }
    621 
    622 std::string BuildDataUserDePath(const char* volumeUuid, userid_t userId) {
    623     // TODO: unify with installd path generation logic
    624     std::string data(BuildDataPath(volumeUuid));
    625     return StringPrintf("%s/user_de/%u", data.c_str(), userId);
    626 }
    627 
    628 dev_t GetDevice(const std::string& path) {
    629     struct stat sb;
    630     if (stat(path.c_str(), &sb)) {
    631         PLOG(WARNING) << "Failed to stat " << path;
    632         return 0;
    633     } else {
    634         return sb.st_dev;
    635     }
    636 }
    637 
    638 status_t RestoreconRecursive(const std::string& path) {
    639     LOG(VERBOSE) << "Starting restorecon of " << path;
    640 
    641     // TODO: find a cleaner way of waiting for restorecon to finish
    642     const char* cpath = path.c_str();
    643     property_set("selinux.restorecon_recursive", "");
    644     property_set("selinux.restorecon_recursive", cpath);
    645 
    646     char value[PROPERTY_VALUE_MAX];
    647     while (true) {
    648         property_get("selinux.restorecon_recursive", value, "");
    649         if (strcmp(cpath, value) == 0) {
    650             break;
    651         }
    652         usleep(100000); // 100ms
    653     }
    654 
    655     LOG(VERBOSE) << "Finished restorecon of " << path;
    656     return OK;
    657 }
    658 
    659 status_t SaneReadLinkAt(int dirfd, const char* path, char* buf, size_t bufsiz) {
    660     ssize_t len = readlinkat(dirfd, path, buf, bufsiz);
    661     if (len < 0) {
    662         return -1;
    663     } else if (len == (ssize_t) bufsiz) {
    664         return -1;
    665     } else {
    666         buf[len] = '\0';
    667         return 0;
    668     }
    669 }
    670 
    671 bool IsRunningInEmulator() {
    672     return property_get_bool("ro.kernel.qemu", 0);
    673 }
    674 
    675 }  // namespace vold
    676 }  // namespace android
    677