vold: allow to store key in a file on another partition
Add support for keeping the keys in a separate file on another partition,
for devices with no space reserved for a footer after the userdata filesystem.
Add support for encrypting the volumes managed by vold, if they meet certain
criteria, namely being marked as nonremovable and encryptable in vold.fstab.
A bit of trickiness is required to keep vold happy.
Change-Id: Idf0611f74b56c1026c45742ca82e0c26e58828fe
diff --git a/Volume.cpp b/Volume.cpp
index ce41455..40a3669 100644
--- a/Volume.cpp
+++ b/Volume.cpp
@@ -25,6 +25,7 @@
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/mount.h>
+#include <sys/param.h>
#include <linux/kdev_t.h>
#include <linux/fs.h>
@@ -44,6 +45,7 @@
#include "ResponseCode.h"
#include "Fat.h"
#include "Process.h"
+#include "cryptfs.h"
extern "C" void dos_partition_dec(void const *pp, struct dos_partition *d);
extern "C" void dos_partition_enc(void *pp, struct dos_partition *d);
@@ -284,8 +286,19 @@
char errmsg[255];
const char* externalStorage = getenv("EXTERNAL_STORAGE");
bool primaryStorage = externalStorage && !strcmp(getMountpoint(), externalStorage);
+ char decrypt_state[PROPERTY_VALUE_MAX];
+ char crypto_state[PROPERTY_VALUE_MAX];
+ char encrypt_progress[PROPERTY_VALUE_MAX];
+ int flags;
- if (getState() == Volume::State_NoMedia) {
+ property_get("vold.decrypt", decrypt_state, "");
+ property_get("vold.encrypt_progress", encrypt_progress, "");
+
+ /* Don't try to mount the volumes if we have not yet entered the disk password
+ * or are in the process of encrypting.
+ */
+ if ((getState() == Volume::State_NoMedia) ||
+ ((!strcmp(decrypt_state, "1") || encrypt_progress[0]) && primaryStorage)) {
snprintf(errmsg, sizeof(errmsg),
"Volume %s %s mount failed - no media",
getLabel(), getMountpoint());
@@ -312,6 +325,56 @@
return -1;
}
+ /* If we're running encrypted, and the volume is marked as encryptable and nonremovable,
+ * and vold is asking to mount the primaryStorage device, then we need to decrypt
+ * that partition, and update the volume object to point to it's new decrypted
+ * block device
+ */
+ property_get("ro.crypto.state", crypto_state, "");
+ flags = getFlags();
+ if (primaryStorage &&
+ ((flags & (VOL_NONREMOVABLE | VOL_ENCRYPTABLE))==(VOL_NONREMOVABLE | VOL_ENCRYPTABLE)) &&
+ !strcmp(crypto_state, "encrypted") && !isDecrypted()) {
+ char new_sys_path[MAXPATHLEN];
+ char nodepath[256];
+ int new_major, new_minor;
+
+ if (n != 1) {
+ /* We only expect one device node returned when mounting encryptable volumes */
+ SLOGE("Too many device nodes returned when mounting %d\n", getMountpoint());
+ return -1;
+ }
+
+ if (cryptfs_setup_volume(getLabel(), MAJOR(deviceNodes[0]), MINOR(deviceNodes[0]),
+ new_sys_path, sizeof(new_sys_path),
+ &new_major, &new_minor)) {
+ SLOGE("Cannot setup encryption mapping for %d\n", getMountpoint());
+ return -1;
+ }
+ /* We now have the new sysfs path for the decrypted block device, and the
+ * majore and minor numbers for it. So, create the device, update the
+ * path to the new sysfs path, and continue.
+ */
+ snprintf(nodepath,
+ sizeof(nodepath), "/dev/block/vold/%d:%d",
+ new_major, new_minor);
+ if (createDeviceNode(nodepath, new_major, new_minor)) {
+ SLOGE("Error making device node '%s' (%s)", nodepath,
+ strerror(errno));
+ }
+
+ // Todo: Either create sys filename from nodepath, or pass in bogus path so
+ // vold ignores state changes on this internal device.
+ updateDeviceInfo(nodepath, new_major, new_minor);
+
+ /* Get the device nodes again, because they just changed */
+ n = getDeviceNodes((dev_t *) &deviceNodes, 4);
+ if (!n) {
+ SLOGE("Failed to get device nodes (%s)\n", strerror(errno));
+ return -1;
+ }
+ }
+
for (i = 0; i < n; i++) {
char devicePath[255];