Merge "Fix Vold to properly handle full-disk file systems"
diff --git a/DirectVolume.cpp b/DirectVolume.cpp
index df06c83..b7c73ae 100644
--- a/DirectVolume.cpp
+++ b/DirectVolume.cpp
@@ -18,6 +18,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
+#include <fnmatch.h>
 
 #include <linux/kdev_t.h>
 
@@ -33,6 +34,42 @@
 
 // #define PARTITION_DEBUG
 
+PathInfo::PathInfo(const char *p)
+{
+    warned = false;
+    pattern = strdup(p);
+
+    if (!strchr(pattern, '*')) {
+        patternType = prefix;
+    } else {
+        patternType = wildcard;
+    }
+}
+
+PathInfo::~PathInfo()
+{
+    free(pattern);
+}
+
+bool PathInfo::match(const char *path)
+{
+    switch (patternType) {
+    case prefix:
+    {
+        bool ret = (strncmp(path, pattern, strlen(pattern)) == 0);
+        if (!warned && ret && (strlen(pattern) != strlen(path))) {
+            SLOGW("Deprecated implied prefix pattern detected, please use '%s*' instead", pattern);
+            warned = true;
+        }
+        return ret;
+    }
+    case wildcard:
+        return fnmatch(pattern, path, 0) == 0;
+    }
+    SLOGE("Bad matching type");
+    return false;
+}
+
 DirectVolume::DirectVolume(VolumeManager *vm, const fstab_rec* rec, int flags) :
         Volume(vm, rec, flags) {
     mPaths = new PathCollection();
@@ -62,12 +99,12 @@
     PathCollection::iterator it;
 
     for (it = mPaths->begin(); it != mPaths->end(); ++it)
-        free(*it);
+        delete *it;
     delete mPaths;
 }
 
 int DirectVolume::addPath(const char *path) {
-    mPaths->push_back(strdup(path));
+    mPaths->push_back(new PathInfo(path));
     return 0;
 }
 
@@ -96,7 +133,7 @@
 
     PathCollection::iterator  it;
     for (it = mPaths->begin(); it != mPaths->end(); ++it) {
-        if (!strncmp(dp, *it, strlen(*it))) {
+        if ((*it)->match(dp)) {
             /* We can handle this disk */
             int action = evt->getAction();
             const char *devtype = evt->findParam("DEVTYPE");
@@ -417,7 +454,7 @@
     }
 
     it = mPaths->begin();
-    free(*it); /* Free the string storage */
+    delete *it; /* Free the string storage */
     mPaths->erase(it); /* Remove it from the list */
     addPath(new_path); /* Put the new path on the list */
 
diff --git a/DirectVolume.h b/DirectVolume.h
index 149ec56..e598598 100644
--- a/DirectVolume.h
+++ b/DirectVolume.h
@@ -21,7 +21,19 @@
 
 #include "Volume.h"
 
-typedef android::List<char *> PathCollection;
+class PathInfo {
+public:
+	PathInfo(const char *pattern);
+	~PathInfo();
+	bool match(const char *path);
+private:
+	bool warned;
+	char *pattern;
+	enum PatternType { prefix, wildcard };
+	PatternType patternType;
+};
+
+typedef android::List<PathInfo *> PathCollection;
 
 class DirectVolume : public Volume {
 public:
diff --git a/Volume.cpp b/Volume.cpp
index ca56d1c..0baf008 100644
--- a/Volume.cpp
+++ b/Volume.cpp
@@ -252,7 +252,7 @@
     dev_t diskNode = getDiskDevice();
     dev_t partNode =
         MKDEV(MAJOR(diskNode),
-              MINOR(diskNode) + (formatEntireDevice ? 1 : mPartIdx));
+              MINOR(diskNode) + (formatEntireDevice ? 0 : mPartIdx));
 
     setState(Volume::State_Formatting);
 
diff --git a/VolumeManager.cpp b/VolumeManager.cpp
index 757fae7..1ffa939 100644
--- a/VolumeManager.cpp
+++ b/VolumeManager.cpp
@@ -211,6 +211,12 @@
 int VolumeManager::getAsecMountPath(const char *id, char *buffer, int maxlen) {
     char asecFileName[255];
 
+    if (!isLegalAsecId(id)) {
+        SLOGE("getAsecMountPath: Invalid asec id \"%s\"", id);
+        errno = EINVAL;
+        return -1;
+    }
+
     if (findAsec(id, asecFileName, sizeof(asecFileName))) {
         SLOGE("Couldn't find ASEC %s", id);
         return -1;
@@ -235,6 +241,12 @@
 int VolumeManager::getAsecFilesystemPath(const char *id, char *buffer, int maxlen) {
     char asecFileName[255];
 
+    if (!isLegalAsecId(id)) {
+        SLOGE("getAsecFilesystemPath: Invalid asec id \"%s\"", id);
+        errno = EINVAL;
+        return -1;
+    }
+
     if (findAsec(id, asecFileName, sizeof(asecFileName))) {
         SLOGE("Couldn't find ASEC %s", id);
         return -1;
@@ -260,6 +272,12 @@
     struct asec_superblock sb;
     memset(&sb, 0, sizeof(sb));
 
+    if (!isLegalAsecId(id)) {
+        SLOGE("createAsec: Invalid asec id \"%s\"", id);
+        errno = EINVAL;
+        return -1;
+    }
+
     const bool wantFilesystem = strcmp(fstype, "none");
     bool usingExt4 = false;
     if (wantFilesystem) {
@@ -483,6 +501,12 @@
     char loopDevice[255];
     char mountPoint[255];
 
+    if (!isLegalAsecId(id)) {
+        SLOGE("finalizeAsec: Invalid asec id \"%s\"", id);
+        errno = EINVAL;
+        return -1;
+    }
+
     if (findAsec(id, asecFileName, sizeof(asecFileName))) {
         SLOGE("Couldn't find ASEC %s", id);
         return -1;
@@ -540,6 +564,12 @@
         return -1;
     }
 
+    if (!isLegalAsecId(id)) {
+        SLOGE("fixupAsecPermissions: Invalid asec id \"%s\"", id);
+        errno = EINVAL;
+        return -1;
+    }
+
     if (findAsec(id, asecFileName, sizeof(asecFileName))) {
         SLOGE("Couldn't find ASEC %s", id);
         return -1;
@@ -659,6 +689,18 @@
 
     const char *dir;
 
+    if (!isLegalAsecId(id1)) {
+        SLOGE("renameAsec: Invalid asec id1 \"%s\"", id1);
+        errno = EINVAL;
+        return -1;
+    }
+
+    if (!isLegalAsecId(id2)) {
+        SLOGE("renameAsec: Invalid asec id2 \"%s\"", id2);
+        errno = EINVAL;
+        return -1;
+    }
+
     if (findAsec(id1, asecFilename1, sizeof(asecFilename1), &dir)) {
         SLOGE("Couldn't find ASEC %s", id1);
         return -1;
@@ -715,6 +757,12 @@
     char asecFileName[255];
     char mountPoint[255];
 
+    if (!isLegalAsecId(id)) {
+        SLOGE("unmountAsec: Invalid asec id \"%s\"", id);
+        errno = EINVAL;
+        return -1;
+    }
+
     if (findAsec(id, asecFileName, sizeof(asecFileName))) {
         SLOGE("Couldn't find ASEC %s", id);
         return -1;
@@ -839,6 +887,12 @@
     char asecFileName[255];
     char mountPoint[255];
 
+    if (!isLegalAsecId(id)) {
+        SLOGE("destroyAsec: Invalid asec id \"%s\"", id);
+        errno = EINVAL;
+        return -1;
+    }
+
     if (findAsec(id, asecFileName, sizeof(asecFileName))) {
         SLOGE("Couldn't find ASEC %s", id);
         return -1;
@@ -871,6 +925,38 @@
     return 0;
 }
 
+/*
+ * Legal ASEC ids consist of alphanumeric characters, '-',
+ * '_', or '.'. ".." is not allowed. The first or last character
+ * of the ASEC id cannot be '.' (dot).
+ */
+bool VolumeManager::isLegalAsecId(const char *id) const {
+    size_t i;
+    size_t len = strlen(id);
+
+    if (len == 0) {
+        return false;
+    }
+    if ((id[0] == '.') || (id[len - 1] == '.')) {
+        return false;
+    }
+
+    for (i = 0; i < len; i++) {
+        if (id[i] == '.') {
+            // i=0 is guaranteed never to have a dot. See above.
+            if (id[i-1] == '.') return false;
+            continue;
+        }
+        if (id[i] == '_' || id[i] == '-') continue;
+        if (id[i] >= 'a' && id[i] <= 'z') continue;
+        if (id[i] >= 'A' && id[i] <= 'Z') continue;
+        if (id[i] >= '0' && id[i] <= '9') continue;
+        return false;
+    }
+
+    return true;
+}
+
 bool VolumeManager::isAsecInDirectory(const char *dir, const char *asecName) const {
     int dirfd = open(dir, O_DIRECTORY);
     if (dirfd < 0) {
@@ -895,6 +981,12 @@
     const int idLen = strlen(id);
     char *asecName;
 
+    if (!isLegalAsecId(id)) {
+        SLOGE("findAsec: Invalid asec id \"%s\"", id);
+        errno = EINVAL;
+        return -1;
+    }
+
     if (asprintf(&asecName, "%s.asec", id) < 0) {
         SLOGE("Couldn't allocate string to write ASEC name");
         return -1;
@@ -931,6 +1023,12 @@
     char asecFileName[255];
     char mountPoint[255];
 
+    if (!isLegalAsecId(id)) {
+        SLOGE("mountAsec: Invalid asec id \"%s\"", id);
+        errno = EINVAL;
+        return -1;
+    }
+
     if (findAsec(id, asecFileName, sizeof(asecFileName))) {
         SLOGE("Couldn't find ASEC %s", id);
         return -1;
diff --git a/VolumeManager.h b/VolumeManager.h
index 9d69d6a..cc8958d 100644
--- a/VolumeManager.h
+++ b/VolumeManager.h
@@ -154,6 +154,7 @@
     void readInitialState();
     bool isMountpointMounted(const char *mp);
     bool isAsecInDirectory(const char *dir, const char *asec) const;
+    bool isLegalAsecId(const char *id) const;
 };
 
 extern "C" {
diff --git a/cryptfs.c b/cryptfs.c
index e545919..99f6069 100644
--- a/cryptfs.c
+++ b/cryptfs.c
@@ -24,6 +24,7 @@
 #include <sys/wait.h>
 #include <sys/stat.h>
 #include <fcntl.h>
+#include <inttypes.h>
 #include <unistd.h>
 #include <stdio.h>
 #include <sys/ioctl.h>
@@ -1448,7 +1449,7 @@
         args[1] = "-a";
         args[2] = "/data";
         args[3] = "-l";
-        snprintf(size_str, sizeof(size_str), "%lld", size * 512);
+        snprintf(size_str, sizeof(size_str), "%" PRId64, size * 512);
         args[4] = size_str;
         args[5] = crypto_blkdev;
         num_args = 6;
@@ -1463,7 +1464,7 @@
         args[5] = "-c";
         args[6] = "8";
         args[7] = "-s";
-        snprintf(size_str, sizeof(size_str), "%lld", size);
+        snprintf(size_str, sizeof(size_str), "%" PRId64, size);
         args[8] = size_str;
         args[9] = crypto_blkdev;
         num_args = 10;
@@ -1540,7 +1541,7 @@
             char buf[8];
 
             cur_pct = new_pct;
-            snprintf(buf, sizeof(buf), "%lld", cur_pct);
+            snprintf(buf, sizeof(buf), "%" PRId64, cur_pct);
             property_set("vold.encrypt_progress", buf);
         }
         if (unix_read(realfd, buf, CRYPT_INPLACE_BUFSIZE) <= 0) {
diff --git a/vdc.c b/vdc.c
index 59f34d6..a810872 100644
--- a/vdc.c
+++ b/vdc.c
@@ -62,7 +62,7 @@
     for (i = 1; i < argc; i++) {
         char *cmp;
 
-        if (!index(argv[i], ' '))
+        if (!strchr(argv[i], ' '))
             asprintf(&cmp, "%s%s", argv[i], (i == (argc -1)) ? "" : " ");
         else
             asprintf(&cmp, "\"%s\"%s", argv[i], (i == (argc -1)) ? "" : " ");