Support for private (adopted) volumes.

This adds support for private volumes which is just a filesystem
wrapped in a dm-crypt layer.  For now we're using the exact same
configuration as internal encryption (aes-cbc-essiv:sha256), but we
don't store any key material on the removable media.  Instead, we
store the key on internal storage, and use the GPT partition GUID
to identify which key should be used.

This means that private external storage is effectively as secure as
the internal storage of the device.  That is, if the internal storage
is encrypted, then our external storage key is also encrypted.

When partitioning disks, we now support a "private" mode which has
a PrivateVolume partition, and a currently unused 16MB metadata
partition reserved for future use.  It also supports a "mixed" mode
which creates both a PublicVolume and PrivateVolume on the same
disk.  Mixed mode is currently experimental.

For now, just add ext4 support to PrivateVolume; we'll look at f2fs
in a future change.  Add VolumeBase lifecycle for setting up crypto
mappings, and extract blkid logic into shared method.  Sprinkle some
more "static" around the cryptfs code to improve invariants.

Bug: 19993667
Change-Id: Ibd1df6250735b706959a1eb9d9f7219ea85912a0
diff --git a/Utils.cpp b/Utils.cpp
index b5d037a..7d32590 100644
--- a/Utils.cpp
+++ b/Utils.cpp
@@ -19,8 +19,10 @@
 #include "Process.h"
 
 #include <base/logging.h>
+#include <base/stringprintf.h>
 #include <cutils/fs.h>
 #include <private/android_filesystem_config.h>
+#include <logwrap/logwrap.h>
 
 #include <fcntl.h>
 #include <linux/fs.h>
@@ -34,9 +36,13 @@
 #define UMOUNT_NOFOLLOW    0x00000008  /* Don't follow symlink on umount */
 #endif
 
+using android::base::StringPrintf;
+
 namespace android {
 namespace vold {
 
+static const char* kBlkidPath = "/system/bin/blkid";
+
 status_t CreateDeviceNode(const std::string& path, dev_t dev) {
     const char* cpath = path.c_str();
     status_t res = 0;
@@ -81,14 +87,14 @@
     }
     PLOG(WARNING) << "Failed to unmount " << path << "; sending SIGTERM";
     Process::killProcessesWithOpenFiles(cpath, SIGTERM);
-    sleep(1);
+    sleep(5);
 
     if (!umount2(cpath, UMOUNT_NOFOLLOW) || errno == EINVAL || errno == ENOENT) {
         return OK;
     }
     PLOG(WARNING) << "Failed to unmount " << path << "; sending SIGKILL";
     Process::killProcessesWithOpenFiles(cpath, SIGKILL);
-    sleep(1);
+    sleep(5);
 
     if (!umount2(cpath, UMOUNT_NOFOLLOW) || errno == EINVAL || errno == ENOENT) {
         return OK;
@@ -105,5 +111,138 @@
     return OK;
 }
 
+status_t ReadMetadata(const std::string& path, std::string& fsType,
+        std::string& fsUuid, std::string& fsLabel) {
+    fsType.clear();
+    fsUuid.clear();
+    fsLabel.clear();
+
+    std::string cmd(StringPrintf("%s -c /dev/null %s", kBlkidPath, path.c_str()));
+    FILE* fp = popen(cmd.c_str(), "r");
+    if (!fp) {
+        PLOG(ERROR) << "Failed to run " << cmd;
+        return -errno;
+    }
+
+    status_t res = OK;
+    char line[1024];
+    char value[128];
+    if (fgets(line, sizeof(line), fp) != nullptr) {
+        LOG(DEBUG) << "blkid identified " << path << " as " << line;
+
+        // Extract values from blkid output, if defined
+        char* start = strstr(line, "TYPE=");
+        if (start != nullptr && sscanf(start + 5, "\"%127[^\"]\"", value) == 1) {
+            fsType = value;
+        }
+
+        start = strstr(line, "UUID=");
+        if (start != nullptr && sscanf(start + 5, "\"%127[^\"]\"", value) == 1) {
+            fsUuid = value;
+        }
+
+        start = strstr(line, "LABEL=");
+        if (start != nullptr && sscanf(start + 6, "\"%127[^\"]\"", value) == 1) {
+            fsLabel = value;
+        }
+    } else {
+        LOG(WARNING) << "blkid failed to identify " << path;
+        res = -ENODATA;
+    }
+
+    pclose(fp);
+    return res;
+}
+
+status_t ForkExecvp(const std::vector<std::string>& args, int* status,
+        bool ignore_int_quit, bool logwrap) {
+    int argc = args.size();
+    char** argv = (char**) calloc(argc, sizeof(char*));
+    for (int i = 0; i < argc; i++) {
+        argv[i] = (char*) args[i].c_str();
+        if (i == 0) {
+            LOG(VERBOSE) << args[i];
+        } else {
+            LOG(VERBOSE) << "    " << args[i];
+        }
+    }
+    int res = android_fork_execvp(argc, argv, status, ignore_int_quit, logwrap);
+    free(argv);
+    return res;
+}
+
+status_t ReadRandomBytes(size_t bytes, std::string& out) {
+    out.clear();
+
+    int fd = TEMP_FAILURE_RETRY(open("/dev/urandom", O_RDONLY | O_CLOEXEC | O_NOFOLLOW));
+    if (fd == -1) {
+        return -errno;
+    }
+
+    char buf[BUFSIZ];
+    size_t n;
+    while ((n = TEMP_FAILURE_RETRY(read(fd, &buf[0], std::min(sizeof(buf), bytes)))) > 0) {
+        out.append(buf, n);
+        bytes -= n;
+    }
+    TEMP_FAILURE_RETRY(close(fd));
+
+    if (bytes == 0) {
+        return OK;
+    } else {
+        return -EIO;
+    }
+}
+
+status_t HexToStr(const std::string& hex, std::string& str) {
+    str.clear();
+    bool even = true;
+    char cur = 0;
+    for (size_t i = 0; i < hex.size(); i++) {
+        int val = 0;
+        switch (hex[i]) {
+        case ' ': case '-': case ':': continue;
+        case 'f': case 'F': val = 15; break;
+        case 'e': case 'E': val = 14; break;
+        case 'd': case 'D': val = 13; break;
+        case 'c': case 'C': val = 12; break;
+        case 'b': case 'B': val = 11; break;
+        case 'a': case 'A': val = 10; break;
+        case '9': val = 9; break;
+        case '8': val = 8; break;
+        case '7': val = 7; break;
+        case '6': val = 6; break;
+        case '5': val = 5; break;
+        case '4': val = 4; break;
+        case '3': val = 3; break;
+        case '2': val = 2; break;
+        case '1': val = 1; break;
+        case '0': val = 0; break;
+        default: return -EINVAL;
+        }
+
+        if (even) {
+            cur = val << 4;
+        } else {
+            cur += val;
+            str.push_back(cur);
+            cur = 0;
+        }
+        even = !even;
+    }
+    return even ? OK : -EINVAL;
+}
+
+static const char* kLookup = "0123456789abcdef";
+
+status_t StrToHex(const std::string& str, std::string& hex) {
+    hex.clear();
+    for (size_t i = 0; i < str.size(); i++) {
+        hex.push_back(kLookup[str[i] >> 4]);
+        hex.push_back(kLookup[str[i] & 0x0F]);
+    }
+    return OK;
+}
+
 }  // namespace vold
 }  // namespace android