vold: Add encrypted ASEC support via devmapper
- Supports up to 4096 containers
- Keys are now implemented - specifying a key of 'none' means no encryption.
Otherwise, the key must be a string of 32 characters
Signed-off-by: San Mehat <san@google.com>
diff --git a/VolumeManager.cpp b/VolumeManager.cpp
index a462196..201ad98 100644
--- a/VolumeManager.cpp
+++ b/VolumeManager.cpp
@@ -36,6 +36,7 @@
#include "ResponseCode.h"
#include "Loop.h"
#include "Fat.h"
+#include "Devmapper.h"
extern "C" void KillProcessesWithOpenFiles(const char *, int, int, int);
@@ -204,10 +205,27 @@
return -1;
}
- /* XXX: Start devmapper */
+ char dmDevice[255];
+ bool cleanupDm = false;
- if (Fat::format(loopDevice)) {
+ if (strcmp(key, "none")) {
+ if (Devmapper::create(id, loopDevice, key, sizeMb, dmDevice,
+ sizeof(dmDevice))) {
+ LOGE("ASEC device mapping failed (%s)", strerror(errno));
+ Loop::destroyByDevice(loopDevice);
+ unlink(asecFileName);
+ return -1;
+ }
+ cleanupDm = true;
+ } else {
+ strcpy(dmDevice, loopDevice);
+ }
+
+ if (Fat::format(dmDevice)) {
LOGE("ASEC FAT format failed (%s)", strerror(errno));
+ if (cleanupDm) {
+ Devmapper::destroy(id);
+ }
Loop::destroyByDevice(loopDevice);
unlink(asecFileName);
return -1;
@@ -219,16 +237,22 @@
if (mkdir(mountPoint, 0777)) {
if (errno != EEXIST) {
LOGE("Mountpoint creation failed (%s)", strerror(errno));
+ if (cleanupDm) {
+ Devmapper::destroy(id);
+ }
Loop::destroyByDevice(loopDevice);
unlink(asecFileName);
return -1;
}
}
- if (Fat::doMount(loopDevice, mountPoint, false, false, ownerUid,
+ if (Fat::doMount(dmDevice, mountPoint, false, false, ownerUid,
0, 0000, false)) {
// 0, 0007, false)) {
LOGE("ASEC FAT mount failed (%s)", strerror(errno));
+ if (cleanupDm) {
+ Devmapper::destroy(id);
+ }
Loop::destroyByDevice(loopDevice);
unlink(asecFileName);
return -1;
@@ -261,7 +285,7 @@
return 0;
}
-int VolumeManager::destroyAsec(const char *id) {
+int VolumeManager::unmountAsec(const char *id) {
char asecFileName[255];
char mountPoint[255];
@@ -270,35 +294,57 @@
snprintf(mountPoint, sizeof(mountPoint), "/asec/%s", id);
if (isMountpointMounted(mountPoint)) {
- int i, rc;
- for (i = 0; i < 10; i++) {
- rc = umount(mountPoint);
- if (!rc) {
- break;
- }
- if (rc && (errno == EINVAL || errno == ENOENT)) {
- rc = 0;
- break;
- }
- LOGW("ASEC %s unmount attempt %d failed (%s)",
- id, i +1, strerror(errno));
+ LOGE("Unmount request for ASEC %s when not mounted", id);
+ errno = EINVAL;
+ return -1;
+ }
- if (i >= 5) {
- KillProcessesWithOpenFiles(mountPoint, (i < 7 ? 0 : 1),
- NULL, 0);
- }
- usleep(1000 * 250);
+ int i, rc;
+ for (i = 0; i < 10; i++) {
+ rc = umount(mountPoint);
+ if (!rc) {
+ break;
}
- if (rc) {
- LOGE("Failed to unmount ASEC %s for destroy", id);
- return -1;
+ if (rc && (errno == EINVAL || errno == ENOENT)) {
+ rc = 0;
+ break;
}
+ LOGW("ASEC %s unmount attempt %d failed (%s)",
+ id, i +1, strerror(errno));
+
+ if (i >= 5) {
+ KillProcessesWithOpenFiles(mountPoint, (i < 7 ? 0 : 1),
+ NULL, 0);
+ }
+ usleep(1000 * 250);
+ }
+
+ if (rc) {
+ LOGE("Failed to unmount ASEC %s", id);
+ return -1;
+ }
+
+ if (Devmapper::destroy(id) && errno != ENXIO) {
+ LOGE("Failed to destroy devmapper instance (%s)", strerror(errno));
}
char loopDevice[255];
if (!Loop::lookupActive(asecFileName, loopDevice, sizeof(loopDevice))) {
Loop::destroyByDevice(loopDevice);
}
+ return 0;
+}
+
+int VolumeManager::destroyAsec(const char *id) {
+ char asecFileName[255];
+ char mountPoint[255];
+
+ snprintf(asecFileName, sizeof(asecFileName),
+ "/sdcard/android_secure/%s.asec", id);
+ snprintf(mountPoint, sizeof(mountPoint), "/asec/%s", id);
+
+ if (unmountAsec(id))
+ return -1;
unlink(asecFileName);
@@ -326,17 +372,66 @@
LOGE("ASEC loop device creation failed (%s)", strerror(errno));
return -1;
}
+ LOGD("New loop device created at %s", loopDevice);
+ } else {
+ LOGD("Found active loopback for %s at %s", asecFileName, loopDevice);
+ }
+
+ char dmDevice[255];
+ bool cleanupDm = false;
+ if (strcmp(key, "none")) {
+ if (Devmapper::lookupActive(id, dmDevice, sizeof(dmDevice))) {
+ unsigned int nr_sec = 0;
+ int fd;
+
+ if ((fd = open(loopDevice, O_RDWR)) < 0) {
+ LOGE("Failed to open loopdevice (%s)", strerror(errno));
+ Loop::destroyByDevice(loopDevice);
+ return -1;
+ }
+
+ if (ioctl(fd, BLKGETSIZE, &nr_sec)) {
+ LOGE("Failed to get loop size (%s)", strerror(errno));
+ Loop::destroyByDevice(loopDevice);
+ close(fd);
+ return -1;
+ }
+ close(fd);
+ if (Devmapper::create(id, loopDevice, key,
+ (nr_sec * 512) / (1024 * 1024),
+ dmDevice, sizeof(dmDevice))) {
+ LOGE("ASEC device mapping failed (%s)", strerror(errno));
+ Loop::destroyByDevice(loopDevice);
+ return -1;
+ }
+ LOGD("New devmapper instance created at %s", dmDevice);
+ } else {
+ LOGD("Found active devmapper for %s at %s", asecFileName, dmDevice);
+ }
+ cleanupDm = true;
+ } else {
+ strcpy(dmDevice, loopDevice);
}
if (mkdir(mountPoint, 0777)) {
- LOGE("Mountpoint creation failed (%s)", strerror(errno));
- return -1;
+ if (errno != EEXIST) {
+ LOGE("Mountpoint creation failed (%s)", strerror(errno));
+ if (cleanupDm) {
+ Devmapper::destroy(id);
+ }
+ Loop::destroyByDevice(loopDevice);
+ return -1;
+ }
}
- if (Fat::doMount(loopDevice, mountPoint, true, false, ownerUid, 0,
+ if (Fat::doMount(dmDevice, mountPoint, true, false, ownerUid, 0,
0222, false)) {
// 0227, false)) {
LOGE("ASEC mount failed (%s)", strerror(errno));
+ if (cleanupDm) {
+ Devmapper::destroy(id);
+ }
+ Loop::destroyByDevice(loopDevice);
return -1;
}