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)) ? "" : " ");