diff options
author | Ethan Yonker <dees_troy@teamw.in> | 2014-11-25 22:00:52 +0100 |
---|---|---|
committer | Dees Troy <dees_troy@teamw.in> | 2014-12-04 17:30:16 +0100 |
commit | 253368a0726120efa57664cdd1d088af099a3d81 (patch) | |
tree | 56cf3b08cdf70d016a2411fba977f7cd143bc265 /crypto/lollipop | |
parent | bootable recovery: we upgraded to 5.0.1 (diff) | |
download | android_bootable_recovery-253368a0726120efa57664cdd1d088af099a3d81.tar android_bootable_recovery-253368a0726120efa57664cdd1d088af099a3d81.tar.gz android_bootable_recovery-253368a0726120efa57664cdd1d088af099a3d81.tar.bz2 android_bootable_recovery-253368a0726120efa57664cdd1d088af099a3d81.tar.lz android_bootable_recovery-253368a0726120efa57664cdd1d088af099a3d81.tar.xz android_bootable_recovery-253368a0726120efa57664cdd1d088af099a3d81.tar.zst android_bootable_recovery-253368a0726120efa57664cdd1d088af099a3d81.zip |
Diffstat (limited to 'crypto/lollipop')
-rw-r--r-- | crypto/lollipop/Android.mk | 26 | ||||
-rw-r--r-- | crypto/lollipop/cryptfs.c | 2215 | ||||
-rw-r--r-- | crypto/lollipop/cryptfs.h | 17 |
3 files changed, 45 insertions, 2213 deletions
diff --git a/crypto/lollipop/Android.mk b/crypto/lollipop/Android.mk index 40b4d5f95..da25eac30 100644 --- a/crypto/lollipop/Android.mk +++ b/crypto/lollipop/Android.mk @@ -21,16 +21,17 @@ common_shared_libraries := \ libcutils \ liblog \ libdiskconfig \ - libhardware_legacy \ liblogwrap \ libext4_utils \ libf2fs_sparseblock \ libcrypto \ libselinux \ libutils \ - libhardware \ + libminhardware \ libsoftkeymaster +common_shared_libraries := libcrypto libselinux libhardware libsoftkeymaster libcutils + LOCAL_MODULE := libcryptfslollipop LOCAL_MODULE_TAGS := eng optional LOCAL_CFLAGS := @@ -44,9 +45,26 @@ LOCAL_SRC_FILES = cryptfs.c # hardware/libhardware/include/hardware \ # system/security/softkeymaster/include/keymaster #LOCAL_SHARED_LIBRARIES += libc liblog libcutils libcrypto libext4_utils -LOCAL_SHARED_LIBRARIES := $(common_shared_libraries) libmincrypttwrp liblogwrap +LOCAL_SHARED_LIBRARIES := $(common_shared_libraries) libmincrypttwrp LOCAL_C_INCLUDES := external/openssl/include $(common_c_includes) -LOCAL_WHOLE_STATIC_LIBRARIES += libfs_mgr libscrypt_static +LOCAL_WHOLE_STATIC_LIBRARIES += libscrypttwrp_static + +include $(BUILD_SHARED_LIBRARY) + +include $(CLEAR_VARS) + +LOCAL_SHARED_LIBRARIES := libcutils liblog + +LOCAL_INCLUDES += $(LOCAL_PATH) $(LOCAL_PATH)\libminhardware + +LOCAL_CFLAGS += -DQEMU_HARDWARE +QEMU_HARDWARE := true + +LOCAL_SHARED_LIBRARIES += libdl + +LOCAL_SRC_FILES += libminhardware/hardware.c + +LOCAL_MODULE:= libminhardware include $(BUILD_SHARED_LIBRARY) endif diff --git a/crypto/lollipop/cryptfs.c b/crypto/lollipop/cryptfs.c index 0277c78ef..90f1523d3 100644 --- a/crypto/lollipop/cryptfs.c +++ b/crypto/lollipop/cryptfs.c @@ -37,27 +37,17 @@ #include <sys/mount.h> #include <openssl/evp.h> #include <errno.h> -#include <ext4.h> #include <linux/kdev_t.h> -#include <fs_mgr.h> #include <time.h> #include "cryptfs.h" -#define LOG_TAG "Cryptfs" -#include "cutils/log.h" #include "cutils/properties.h" -#include "cutils/android_reboot.h" -#include "hardware_legacy/power.h" -#include <logwrap/logwrap.h> -//#include "VolumeManager.h" -//#include "VoldUtil.h" #include "crypto_scrypt.h" -#include "ext4_utils.h" -#include "f2fs_sparseblock.h" -//#include "CheckBattery.h" -//#include "Process.h" - #include <hardware/keymaster.h> +#ifndef min /* already defined by windows.h */ +#define min(a, b) ((a) < (b) ? (a) : (b)) +#endif + #define UNUSED __attribute__((unused)) #define UNUSED __attribute__((unused)) @@ -91,6 +81,16 @@ static unsigned char saved_master_key[KEY_LEN_BYTES]; static char *saved_mount_point; static int master_key_saved = 0; static struct crypt_persist_data *persist_data = NULL; +static char key_fname[PROPERTY_VALUE_MAX] = ""; +static char real_blkdev[PROPERTY_VALUE_MAX] = ""; +static char file_system[PROPERTY_VALUE_MAX] = ""; + +void set_partition_data(const char* block_device, const char* key_location, const char* fs) +{ + strcpy(key_fname, key_location); + strcpy(real_blkdev, block_device); + strcpy(file_system, fs); +} static int keymaster_init(keymaster_device_t **keymaster_dev) { @@ -291,31 +291,6 @@ static char* password = 0; static int password_expiry_time = 0; static const int password_max_age_seconds = 60; -struct fstab *fstab; - -enum RebootType {reboot, recovery, shutdown}; -static void cryptfs_reboot(enum RebootType rt) -{ - switch(rt) { - case reboot: - property_set(ANDROID_RB_PROPERTY, "reboot"); - break; - - case recovery: - property_set(ANDROID_RB_PROPERTY, "reboot,recovery"); - break; - - case shutdown: - property_set(ANDROID_RB_PROPERTY, "shutdown"); - break; - } - - sleep(20); - - /* Shouldn't get here, reboot should happen before sleep times out */ - return; -} - static void ioctl_init(struct dm_ioctl *io, size_t dataSize, const char *name, unsigned flags) { memset(io, 0, dataSize); @@ -380,41 +355,6 @@ static void get_device_scrypt_params(struct crypt_mnt_ftr *ftr) { ftr->p_factor = params[2]; } -static unsigned int get_fs_size(char *dev) -{ - int fd, block_size; - struct ext4_super_block sb; - off64_t len; - - if ((fd = open(dev, O_RDONLY)) < 0) { - printf("Cannot open device to get filesystem size "); - return 0; - } - - if (lseek64(fd, 1024, SEEK_SET) < 0) { - printf("Cannot seek to superblock"); - return 0; - } - - if (read(fd, &sb, sizeof(sb)) != sizeof(sb)) { - printf("Cannot read superblock"); - return 0; - } - - close(fd); - - if (le32_to_cpu(sb.s_magic) != EXT4_SUPER_MAGIC) { - printf("Not a valid ext4 superblock"); - return 0; - } - block_size = 1024 << sb.s_log_block_size; - /* compute length in bytes */ - len = ( ((off64_t)sb.s_blocks_count_hi << 32) + sb.s_blocks_count_lo) * block_size; - - /* return length in sectors */ - return (unsigned int) (len / 512); -} - static unsigned int get_blkdev_size(int fd) { unsigned int nr_sec; @@ -432,15 +372,12 @@ static int get_crypt_ftr_info(char **metadata_fname, off64_t *off) static off64_t cached_off = 0; static char cached_metadata_fname[PROPERTY_VALUE_MAX] = ""; int fd; - char key_loc[PROPERTY_VALUE_MAX]; - char real_blkdev[PROPERTY_VALUE_MAX]; unsigned int nr_sec; int rc = -1; if (!cached_data) { - fs_mgr_get_crypt_info(fstab, key_loc, real_blkdev, sizeof(key_loc)); - printf("get_crypt_ftr_info crypto key location: '%s'\n", key_loc); - if (!strcmp(key_loc, KEY_IN_FOOTER)) { + printf("get_crypt_ftr_info crypto key location: '%s'\n", key_fname); + if (!strcmp(key_fname, KEY_IN_FOOTER)) { if ( (fd = open(real_blkdev, O_RDWR)) < 0) { printf("Cannot open real block device %s\n", real_blkdev); return -1; @@ -459,7 +396,7 @@ static int get_crypt_ftr_info(char **metadata_fname, off64_t *off) } close(fd); } else { - strlcpy(cached_metadata_fname, key_loc, sizeof(cached_metadata_fname)); + strlcpy(cached_metadata_fname, key_fname, sizeof(cached_metadata_fname)); cached_off = 0; cached_data = 1; } @@ -478,65 +415,6 @@ static int get_crypt_ftr_info(char **metadata_fname, off64_t *off) return rc; } -/* key or salt can be NULL, in which case just skip writing that value. Useful to - * update the failed mount count but not change the key. - */ -static int put_crypt_ftr_and_key(struct crypt_mnt_ftr *crypt_ftr) -{ - printf("TWRP NOT putting crypt footer and key\n"); - return 0; - int fd; - unsigned int nr_sec, cnt; - /* starting_off is set to the SEEK_SET offset - * where the crypto structure starts - */ - off64_t starting_off; - int rc = -1; - char *fname = NULL; - struct stat statbuf; - - if (get_crypt_ftr_info(&fname, &starting_off)) { - printf("Unable to get crypt_ftr_info\n"); - return -1; - } - if (fname[0] != '/') { - printf("Unexpected value for crypto key location\n"); - return -1; - } - if ( (fd = open(fname, O_RDWR | O_CREAT, 0600)) < 0) { - printf("Cannot open footer file %s for put\n", fname); - return -1; - } - - /* Seek to the start of the crypt footer */ - if (lseek64(fd, starting_off, SEEK_SET) == -1) { - printf("Cannot seek to real block device footer\n"); - goto errout; - } - - if ((cnt = write(fd, crypt_ftr, sizeof(struct crypt_mnt_ftr))) != sizeof(struct crypt_mnt_ftr)) { - printf("Cannot write real block device footer\n"); - goto errout; - } - - fstat(fd, &statbuf); - /* If the keys are kept on a raw block device, do not try to truncate it. */ - if (S_ISREG(statbuf.st_mode)) { - if (ftruncate(fd, 0x4000)) { - printf("Cannot set footer file size\n"); - goto errout; - } - } - - /* Success! */ - rc = 0; - -errout: - close(fd); - return rc; - -} - static inline int unix_read(int fd, void* buff, int len) { return TEMP_FAILURE_RETRY(read(fd, buff, len)); @@ -554,75 +432,6 @@ static void init_empty_persist_data(struct crypt_persist_data *pdata, int len) pdata->persist_valid_entries = 0; } -/* A routine to update the passed in crypt_ftr to the lastest version. - * fd is open read/write on the device that holds the crypto footer and persistent - * data, crypt_ftr is a pointer to the struct to be updated, and offset is the - * absolute offset to the start of the crypt_mnt_ftr on the passed in fd. - */ -static void upgrade_crypt_ftr(int fd, struct crypt_mnt_ftr *crypt_ftr, off64_t offset) -{ - int orig_major = crypt_ftr->major_version; - int orig_minor = crypt_ftr->minor_version; -printf("TWRP NOT upgrading crypto footer\n"); -return; // do not upgrade in recovery - if ((crypt_ftr->major_version == 1) && (crypt_ftr->minor_version == 0)) { - struct crypt_persist_data *pdata; - off64_t pdata_offset = offset + CRYPT_FOOTER_TO_PERSIST_OFFSET; - - printf("upgrading crypto footer to 1.1"); - - pdata = malloc(CRYPT_PERSIST_DATA_SIZE); - if (pdata == NULL) { - printf("Cannot allocate persisent data\n"); - return; - } - memset(pdata, 0, CRYPT_PERSIST_DATA_SIZE); - - /* Need to initialize the persistent data area */ - if (lseek64(fd, pdata_offset, SEEK_SET) == -1) { - printf("Cannot seek to persisent data offset\n"); - return; - } - /* Write all zeros to the first copy, making it invalid */ - unix_write(fd, pdata, CRYPT_PERSIST_DATA_SIZE); - - /* Write a valid but empty structure to the second copy */ - init_empty_persist_data(pdata, CRYPT_PERSIST_DATA_SIZE); - unix_write(fd, pdata, CRYPT_PERSIST_DATA_SIZE); - - /* Update the footer */ - crypt_ftr->persist_data_size = CRYPT_PERSIST_DATA_SIZE; - crypt_ftr->persist_data_offset[0] = pdata_offset; - crypt_ftr->persist_data_offset[1] = pdata_offset + CRYPT_PERSIST_DATA_SIZE; - crypt_ftr->minor_version = 1; - } - - if ((crypt_ftr->major_version == 1) && (crypt_ftr->minor_version == 1)) { - printf("upgrading crypto footer to 1.2"); - /* But keep the old kdf_type. - * It will get updated later to KDF_SCRYPT after the password has been verified. - */ - crypt_ftr->kdf_type = KDF_PBKDF2; - get_device_scrypt_params(crypt_ftr); - crypt_ftr->minor_version = 2; - } - - if ((crypt_ftr->major_version == 1) && (crypt_ftr->minor_version == 2)) { - printf("upgrading crypto footer to 1.3"); - crypt_ftr->crypt_type = CRYPT_TYPE_PASSWORD; - crypt_ftr->minor_version = 3; - } - - if ((orig_major != crypt_ftr->major_version) || (orig_minor != crypt_ftr->minor_version)) { - if (lseek64(fd, offset, SEEK_SET) == -1) { - printf("Cannot seek to crypt footer\n"); - return; - } - unix_write(fd, crypt_ftr, sizeof(struct crypt_mnt_ftr)); - } -} - - static int get_crypt_ftr_and_key(struct crypt_mnt_ftr *crypt_ftr) { int fd; @@ -682,9 +491,9 @@ static int get_crypt_ftr_and_key(struct crypt_mnt_ftr *crypt_ftr) /* If this is a verion 1.0 crypt_ftr, make it a 1.1 crypt footer, and update the * copy on disk before returning. */ - if (crypt_ftr->minor_version < CURRENT_MINOR_VERSION) { + /*if (crypt_ftr->minor_version < CURRENT_MINOR_VERSION) { upgrade_crypt_ftr(fd, crypt_ftr, starting_off); - } + }*/ /* Success! */ rc = 0; @@ -694,229 +503,6 @@ errout: return rc; } -static int validate_persistent_data_storage(struct crypt_mnt_ftr *crypt_ftr) -{ - if (crypt_ftr->persist_data_offset[0] + crypt_ftr->persist_data_size > - crypt_ftr->persist_data_offset[1]) { - printf("Crypt_ftr persist data regions overlap"); - return -1; - } - - if (crypt_ftr->persist_data_offset[0] >= crypt_ftr->persist_data_offset[1]) { - printf("Crypt_ftr persist data region 0 starts after region 1"); - return -1; - } - - if (((crypt_ftr->persist_data_offset[1] + crypt_ftr->persist_data_size) - - (crypt_ftr->persist_data_offset[0] - CRYPT_FOOTER_TO_PERSIST_OFFSET)) > - CRYPT_FOOTER_OFFSET) { - printf("Persistent data extends past crypto footer"); - return -1; - } - - return 0; -} - -static int load_persistent_data(void) -{ - struct crypt_mnt_ftr crypt_ftr; - struct crypt_persist_data *pdata = NULL; - char encrypted_state[PROPERTY_VALUE_MAX]; - char *fname; - int found = 0; - int fd; - int ret; - int i; - - if (persist_data) { - /* Nothing to do, we've already loaded or initialized it */ - return 0; - } - - - /* If not encrypted, just allocate an empty table and initialize it */ - property_get("ro.crypto.state", encrypted_state, ""); - if (strcmp(encrypted_state, "encrypted") ) { - pdata = malloc(CRYPT_PERSIST_DATA_SIZE); - if (pdata) { - init_empty_persist_data(pdata, CRYPT_PERSIST_DATA_SIZE); - persist_data = pdata; - return 0; - } - return -1; - } - - if(get_crypt_ftr_and_key(&crypt_ftr)) { - return -1; - } - - if ((crypt_ftr.major_version < 1) - || (crypt_ftr.major_version == 1 && crypt_ftr.minor_version < 1)) { - printf("Crypt_ftr version doesn't support persistent data"); - return -1; - } - - if (get_crypt_ftr_info(&fname, NULL)) { - return -1; - } - - ret = validate_persistent_data_storage(&crypt_ftr); - if (ret) { - return -1; - } - - fd = open(fname, O_RDONLY); - if (fd < 0) { - printf("Cannot open %s metadata file", fname); - return -1; - } - - if (persist_data == NULL) { - pdata = malloc(crypt_ftr.persist_data_size); - if (pdata == NULL) { - printf("Cannot allocate memory for persistent data"); - goto err; - } - } - - for (i = 0; i < 2; i++) { - if (lseek64(fd, crypt_ftr.persist_data_offset[i], SEEK_SET) < 0) { - printf("Cannot seek to read persistent data on %s", fname); - goto err2; - } - if (unix_read(fd, pdata, crypt_ftr.persist_data_size) < 0){ - printf("Error reading persistent data on iteration %d", i); - goto err2; - } - if (pdata->persist_magic == PERSIST_DATA_MAGIC) { - found = 1; - break; - } - } - - if (!found) { - printf("Could not find valid persistent data, creating"); - init_empty_persist_data(pdata, crypt_ftr.persist_data_size); - } - - /* Success */ - persist_data = pdata; - close(fd); - return 0; - -err2: - free(pdata); - -err: - close(fd); - return -1; -} - -static int save_persistent_data(void) -{ - struct crypt_mnt_ftr crypt_ftr; - struct crypt_persist_data *pdata; - char *fname; - off64_t write_offset; - off64_t erase_offset; - int found = 0; - int fd; - int ret; - - if (persist_data == NULL) { - printf("No persistent data to save"); - return -1; - } - - if(get_crypt_ftr_and_key(&crypt_ftr)) { - return -1; - } - - if ((crypt_ftr.major_version < 1) - || (crypt_ftr.major_version == 1 && crypt_ftr.minor_version < 1)) { - printf("Crypt_ftr version doesn't support persistent data"); - return -1; - } - - ret = validate_persistent_data_storage(&crypt_ftr); - if (ret) { - return -1; - } - - if (get_crypt_ftr_info(&fname, NULL)) { - return -1; - } - - fd = open(fname, O_RDWR); - if (fd < 0) { - printf("Cannot open %s metadata file", fname); - return -1; - } - - pdata = malloc(crypt_ftr.persist_data_size); - if (pdata == NULL) { - printf("Cannot allocate persistant data"); - goto err; - } - - if (lseek64(fd, crypt_ftr.persist_data_offset[0], SEEK_SET) < 0) { - printf("Cannot seek to read persistent data on %s", fname); - goto err2; - } - - if (unix_read(fd, pdata, crypt_ftr.persist_data_size) < 0) { - printf("Error reading persistent data before save"); - goto err2; - } - - if (pdata->persist_magic == PERSIST_DATA_MAGIC) { - /* The first copy is the curent valid copy, so write to - * the second copy and erase this one */ - write_offset = crypt_ftr.persist_data_offset[1]; - erase_offset = crypt_ftr.persist_data_offset[0]; - } else { - /* The second copy must be the valid copy, so write to - * the first copy, and erase the second */ - write_offset = crypt_ftr.persist_data_offset[0]; - erase_offset = crypt_ftr.persist_data_offset[1]; - } - - /* Write the new copy first, if successful, then erase the old copy */ - if (lseek(fd, write_offset, SEEK_SET) < 0) { - printf("Cannot seek to write persistent data"); - goto err2; - } - if (unix_write(fd, persist_data, crypt_ftr.persist_data_size) == - (int) crypt_ftr.persist_data_size) { - if (lseek(fd, erase_offset, SEEK_SET) < 0) { - printf("Cannot seek to erase previous persistent data"); - goto err2; - } - fsync(fd); - memset(pdata, 0, crypt_ftr.persist_data_size); - if (unix_write(fd, pdata, crypt_ftr.persist_data_size) != - (int) crypt_ftr.persist_data_size) { - printf("Cannot write to erase previous persistent data"); - goto err2; - } - fsync(fd); - } else { - printf("Cannot write to save persistent data"); - goto err2; - } - - /* Success */ - free(pdata); - close(fd); - return 0; - -err2: - free(pdata); -err: - close(fd); - return -1; -} - static int hexdigit (char c) { if (c >= '0' && c <= '9') return c - '0'; @@ -1424,321 +1010,12 @@ static int decrypt_master_key(char *passwd, unsigned char *decrypted_master_key, return ret; } -static int create_encrypted_random_key(char *passwd, unsigned char *master_key, unsigned char *salt, - struct crypt_mnt_ftr *crypt_ftr) { - int fd; - unsigned char key_buf[KEY_LEN_BYTES]; - EVP_CIPHER_CTX e_ctx; - int encrypted_len, final_len; - - /* Get some random bits for a key */ - fd = open("/dev/urandom", O_RDONLY); - read(fd, key_buf, sizeof(key_buf)); - read(fd, salt, SALT_LEN); - close(fd); - - /* Now encrypt it with the password */ - return encrypt_master_key(passwd, salt, key_buf, master_key, crypt_ftr); -} - -static int wait_and_unmount(char *mountpoint, bool kill) -{ - int i, err, rc; -#define WAIT_UNMOUNT_COUNT 20 - - /* Now umount the tmpfs filesystem */ - for (i=0; i<WAIT_UNMOUNT_COUNT; i++) { - if (umount(mountpoint) == 0) { - break; - } - - if (errno == EINVAL) { - /* EINVAL is returned if the directory is not a mountpoint, - * i.e. there is no filesystem mounted there. So just get out. - */ - break; - } - - err = errno; - - /* If allowed, be increasingly aggressive before the last two retries */ - if (kill) { - if (i == (WAIT_UNMOUNT_COUNT - 3)) { - printf("sending SIGHUP to processes with open files\n"); - //vold_killProcessesWithOpenFiles(mountpoint, 1); - } else if (i == (WAIT_UNMOUNT_COUNT - 2)) { - printf("sending SIGKILL to processes with open files\n"); - //vold_killProcessesWithOpenFiles(mountpoint, 2); - } - } - - sleep(1); - } - - if (i < WAIT_UNMOUNT_COUNT) { - printf("unmounting %s succeeded\n", mountpoint); - rc = 0; - } else { - //vold_killProcessesWithOpenFiles(mountpoint, 0); - printf("unmounting %s failed: %s\n", mountpoint, strerror(err)); - rc = -1; - } - - return rc; -} - -#define DATA_PREP_TIMEOUT 200 -static int prep_data_fs(void) -{ - int i; - - /* Do the prep of the /data filesystem */ - property_set("vold.post_fs_data_done", "0"); - property_set("vold.decrypt", "trigger_post_fs_data"); - printf("Just triggered post_fs_data\n"); - - /* Wait a max of 50 seconds, hopefully it takes much less */ - for (i=0; i<DATA_PREP_TIMEOUT; i++) { - char p[PROPERTY_VALUE_MAX]; - - property_get("vold.post_fs_data_done", p, "0"); - if (*p == '1') { - break; - } else { - usleep(250000); - } - } - if (i == DATA_PREP_TIMEOUT) { - /* Ugh, we failed to prep /data in time. Bail. */ - printf("post_fs_data timed out!\n"); - return -1; - } else { - printf("post_fs_data done\n"); - return 0; - } -} - -static void cryptfs_set_corrupt() -{ - // Mark the footer as bad - struct crypt_mnt_ftr crypt_ftr; - if (get_crypt_ftr_and_key(&crypt_ftr)) { - printf("Failed to get crypto footer - panic"); - return; - } - - crypt_ftr.flags |= CRYPT_DATA_CORRUPT; - if (put_crypt_ftr_and_key(&crypt_ftr)) { - printf("Failed to set crypto footer - panic"); - return; - } -} - -static void cryptfs_trigger_restart_min_framework() -{ - if (fs_mgr_do_tmpfs_mount(DATA_MNT_POINT)) { - printf("Failed to mount tmpfs on data - panic"); - return; - } - - if (property_set("vold.decrypt", "trigger_post_fs_data")) { - printf("Failed to trigger post fs data - panic"); - return; - } - - if (property_set("vold.decrypt", "trigger_restart_min_framework")) { - printf("Failed to trigger restart min framework - panic"); - return; - } -} - -/* returns < 0 on failure */ -static int cryptfs_restart_internal(int restart_main) -{ - char fs_type[32]; - char real_blkdev[MAXPATHLEN]; - char crypto_blkdev[MAXPATHLEN]; - char fs_options[256]; - unsigned long mnt_flags; - struct stat statbuf; - int rc = -1, i; - static int restart_successful = 0; - - /* Validate that it's OK to call this routine */ - if (! master_key_saved) { - printf("Encrypted filesystem not validated, aborting"); - return -1; - } - - if (restart_successful) { - printf("System already restarted with encrypted disk, aborting"); - return -1; - } - - if (restart_main) { - /* Here is where we shut down the framework. The init scripts - * start all services in one of three classes: core, main or late_start. - * On boot, we start core and main. Now, we stop main, but not core, - * as core includes vold and a few other really important things that - * we need to keep running. Once main has stopped, we should be able - * to umount the tmpfs /data, then mount the encrypted /data. - * We then restart the class main, and also the class late_start. - * At the moment, I've only put a few things in late_start that I know - * are not needed to bring up the framework, and that also cause problems - * with unmounting the tmpfs /data, but I hope to add add more services - * to the late_start class as we optimize this to decrease the delay - * till the user is asked for the password to the filesystem. - */ - - /* The init files are setup to stop the class main when vold.decrypt is - * set to trigger_reset_main. - */ - property_set("vold.decrypt", "trigger_reset_main"); - printf("Just asked init to shut down class main\n"); - - /* Ugh, shutting down the framework is not synchronous, so until it - * can be fixed, this horrible hack will wait a moment for it all to - * shut down before proceeding. Without it, some devices cannot - * restart the graphics services. - */ - sleep(2); - } - - /* Now that the framework is shutdown, we should be able to umount() - * the tmpfs filesystem, and mount the real one. - */ - - property_get("ro.crypto.fs_crypto_blkdev", crypto_blkdev, ""); - if (strlen(crypto_blkdev) == 0) { - printf("fs_crypto_blkdev not set\n"); - return -1; - } - - if (! (rc = wait_and_unmount(DATA_MNT_POINT, true)) ) { - /* If ro.crypto.readonly is set to 1, mount the decrypted - * filesystem readonly. This is used when /data is mounted by - * recovery mode. - */ - char ro_prop[PROPERTY_VALUE_MAX]; - property_get("ro.crypto.readonly", ro_prop, ""); - if (strlen(ro_prop) > 0 && atoi(ro_prop)) { - struct fstab_rec* rec = fs_mgr_get_entry_for_mount_point(fstab, DATA_MNT_POINT); - rec->flags |= MS_RDONLY; - } - - /* If that succeeded, then mount the decrypted filesystem */ - int retries = RETRY_MOUNT_ATTEMPTS; - int mount_rc; - while ((mount_rc = fs_mgr_do_mount(fstab, DATA_MNT_POINT, - crypto_blkdev, 0)) - != 0) { - if (mount_rc == FS_MGR_DOMNT_BUSY) { - /* TODO: invoke something similar to - Process::killProcessWithOpenFiles(DATA_MNT_POINT, - retries > RETRY_MOUNT_ATTEMPT/2 ? 1 : 2 ) */ - printf("Failed to mount %s because it is busy - waiting", - crypto_blkdev); - if (--retries) { - sleep(RETRY_MOUNT_DELAY_SECONDS); - } else { - /* Let's hope that a reboot clears away whatever is keeping - the mount busy */ - cryptfs_reboot(reboot); - } - } else { - printf("Failed to mount decrypted data"); - cryptfs_set_corrupt(); - cryptfs_trigger_restart_min_framework(); - printf("Started framework to offer wipe"); - return -1; - } - } - - property_set("vold.decrypt", "trigger_load_persist_props"); - /* Create necessary paths on /data */ - if (prep_data_fs()) { - return -1; - } - - /* startup service classes main and late_start */ - property_set("vold.decrypt", "trigger_restart_framework"); - printf("Just triggered restart_framework\n"); - - /* Give it a few moments to get started */ - sleep(1); - } - - if (rc == 0) { - restart_successful = 1; - } - - return rc; -} - -int cryptfs_restart(void) -{ - /* Call internal implementation forcing a restart of main service group */ - return cryptfs_restart_internal(1); -} - -static int do_crypto_complete(char *mount_point UNUSED) -{ - struct crypt_mnt_ftr crypt_ftr; - char encrypted_state[PROPERTY_VALUE_MAX]; - char key_loc[PROPERTY_VALUE_MAX]; - - property_get("ro.crypto.state", encrypted_state, ""); - if (strcmp(encrypted_state, "encrypted") ) { - printf("not running with encryption, aborting"); - return CRYPTO_COMPLETE_NOT_ENCRYPTED; - } - - if (get_crypt_ftr_and_key(&crypt_ftr)) { - fs_mgr_get_crypt_info(fstab, key_loc, 0, sizeof(key_loc)); - - /* - * Only report this error if key_loc is a file and it exists. - * If the device was never encrypted, and /data is not mountable for - * some reason, returning 1 should prevent the UI from presenting the - * a "enter password" screen, or worse, a "press button to wipe the - * device" screen. - */ - if ((key_loc[0] == '/') && (access("key_loc", F_OK) == -1)) { - printf("master key file does not exist, aborting"); - return CRYPTO_COMPLETE_NOT_ENCRYPTED; - } else { - printf("Error getting crypt footer and key\n"); - return CRYPTO_COMPLETE_BAD_METADATA; - } - } - - // Test for possible error flags - if (crypt_ftr.flags & CRYPT_ENCRYPTION_IN_PROGRESS){ - printf("Encryption process is partway completed\n"); - return CRYPTO_COMPLETE_PARTIAL; - } - - if (crypt_ftr.flags & CRYPT_INCONSISTENT_STATE){ - printf("Encryption process was interrupted but cannot continue\n"); - return CRYPTO_COMPLETE_INCONSISTENT; - } - - if (crypt_ftr.flags & CRYPT_DATA_CORRUPT){ - printf("Encryption is successful but data is corrupt\n"); - return CRYPTO_COMPLETE_CORRUPT; - } - - /* We passed the test! We shall diminish, and return to the west */ - return CRYPTO_COMPLETE_ENCRYPTED; -} - static int test_mount_encrypted_fs(struct crypt_mnt_ftr* crypt_ftr, char *passwd, char *mount_point, char *label) { /* Allocate enough space for a 256 bit key, but we may use less */ unsigned char decrypted_master_key[32]; char crypto_blkdev[MAXPATHLEN]; - char real_blkdev[MAXPATHLEN]; char tmp_mount_point[64]; unsigned int orig_failed_decrypt_count; int rc; @@ -1761,8 +1038,6 @@ static int test_mount_encrypted_fs(struct crypt_mnt_ftr* crypt_ftr, } } - fs_mgr_get_crypt_info(fstab, 0, real_blkdev, sizeof(real_blkdev)); - // Create crypto block device - all (non fatal) code paths // need it if (create_crypto_blk_dev(crypt_ftr, decrypted_master_key, @@ -1795,7 +1070,7 @@ static int test_mount_encrypted_fs(struct crypt_mnt_ftr* crypt_ftr, * the footer, not the key. */ sprintf(tmp_mount_point, "%s/tmp_mnt", mount_point); mkdir(tmp_mount_point, 0755); - if (fs_mgr_do_mount(fstab, DATA_MNT_POINT, crypto_blkdev, tmp_mount_point)) { + if (mount(crypto_blkdev, tmp_mount_point, file_system, NULL, NULL) != 0) { printf("Error temp mounting decrypted block device '%s'\n", crypto_blkdev); delete_crypto_blk_dev(label); @@ -1877,52 +1152,6 @@ int cryptfs_revert_volume(const char *label) return delete_crypto_blk_dev((char *)label); } -/* - * Called by vold when it's asked to mount an encrypted, nonremovable volume. - * Setup a dm-crypt mapping, use the saved master key from - * setting up the /data mapping, and return the new device path. - */ -int cryptfs_setup_volume(const char *label, int major, int minor, - char *crypto_sys_path, unsigned int max_path, - int *new_major, int *new_minor) -{ - char real_blkdev[MAXPATHLEN], crypto_blkdev[MAXPATHLEN]; - struct crypt_mnt_ftr sd_crypt_ftr; - struct stat statbuf; - int nr_sec, fd; - - sprintf(real_blkdev, "/dev/block/vold/%d:%d", major, minor); - - get_crypt_ftr_and_key(&sd_crypt_ftr); - - /* Update the fs_size field to be the size of the volume */ - fd = open(real_blkdev, O_RDONLY); - nr_sec = get_blkdev_size(fd); - close(fd); - if (nr_sec == 0) { - printf("Cannot get size of volume %s\n", real_blkdev); - return -1; - } - - sd_crypt_ftr.fs_size = nr_sec; - create_crypto_blk_dev(&sd_crypt_ftr, saved_master_key, real_blkdev, - crypto_blkdev, label); - - stat(crypto_blkdev, &statbuf); - *new_major = MAJOR(statbuf.st_rdev); - *new_minor = MINOR(statbuf.st_rdev); - - /* Create path to sys entry for this block device */ - snprintf(crypto_sys_path, max_path, "/devices/virtual/block/%s", strrchr(crypto_blkdev, '/')+1); - - return 0; -} - -int cryptfs_crypto_complete(void) -{ - return do_crypto_complete("/data"); -} - int check_unmounted_and_get_ftr(struct crypt_mnt_ftr* crypt_ftr) { char encrypted_state[PROPERTY_VALUE_MAX]; @@ -2034,24 +1263,11 @@ char* hexadj_passwd(const char* passwd) return hex; } -#define FSTAB_PREFIX "/fstab." - -int cryptfs_check_footer(void) +int cryptfs_check_footer() { int rc = -1; - char fstab_filename[PROPERTY_VALUE_MAX + sizeof(FSTAB_PREFIX)]; - char propbuf[PROPERTY_VALUE_MAX]; struct crypt_mnt_ftr crypt_ftr; - property_get("ro.hardware", propbuf, ""); - snprintf(fstab_filename, sizeof(fstab_filename), FSTAB_PREFIX"%s", propbuf); - - fstab = fs_mgr_read_fstab(fstab_filename); - if (!fstab) { - printf("failed to open %s\n", fstab_filename); - return -1; - } - rc = get_crypt_ftr_and_key(&crypt_ftr); return rc; @@ -2061,17 +1277,6 @@ int cryptfs_check_passwd(char *passwd) { struct crypt_mnt_ftr crypt_ftr; int rc; - char fstab_filename[PROPERTY_VALUE_MAX + sizeof(FSTAB_PREFIX)]; - char propbuf[PROPERTY_VALUE_MAX]; - - property_get("ro.hardware", propbuf, ""); - snprintf(fstab_filename, sizeof(fstab_filename), FSTAB_PREFIX"%s", propbuf); - - fstab = fs_mgr_read_fstab(fstab_filename); - if (!fstab) { - printf("failed to open %s\n", fstab_filename); - return -1; - } rc = check_unmounted_and_get_ftr(&crypt_ftr); if (rc) @@ -2223,1366 +1428,11 @@ static int cryptfs_init_crypt_mnt_ftr(struct crypt_mnt_ftr *ftr) return 0; } -static int cryptfs_enable_wipe(char *crypto_blkdev, off64_t size, int type) -{ - const char *args[10]; - char size_str[32]; /* Must be large enough to hold a %lld and null byte */ - int num_args; - int status; - int tmp; - int rc = -1; - - if (type == EXT4_FS) { - args[0] = "/system/bin/make_ext4fs"; - args[1] = "-a"; - args[2] = "/data"; - args[3] = "-l"; - snprintf(size_str, sizeof(size_str), "%" PRId64, size * 512); - args[4] = size_str; - args[5] = crypto_blkdev; - num_args = 6; - printf("Making empty filesystem with command %s %s %s %s %s %s\n", - args[0], args[1], args[2], args[3], args[4], args[5]); - } else if (type == F2FS_FS) { - args[0] = "/system/bin/mkfs.f2fs"; - args[1] = "-t"; - args[2] = "-d1"; - args[3] = crypto_blkdev; - snprintf(size_str, sizeof(size_str), "%" PRId64, size); - args[4] = size_str; - num_args = 5; - printf("Making empty filesystem with command %s %s %s %s %s\n", - args[0], args[1], args[2], args[3], args[4]); - } else { - printf("cryptfs_enable_wipe(): unknown filesystem type %d\n", type); - return -1; - } - - tmp = android_fork_execvp(num_args, (char **)args, &status, false, true); - - if (tmp != 0) { - printf("Error creating empty filesystem on %s due to logwrap error\n", crypto_blkdev); - } else { - if (WIFEXITED(status)) { - if (WEXITSTATUS(status)) { - printf("Error creating filesystem on %s, exit status %d ", - crypto_blkdev, WEXITSTATUS(status)); - } else { - printf("Successfully created filesystem on %s\n", crypto_blkdev); - rc = 0; - } - } else { - printf("Error creating filesystem on %s, did not exit normally\n", crypto_blkdev); - } - } - - return rc; -} - -#define CRYPT_INPLACE_BUFSIZE 4096 -#define CRYPT_SECTORS_PER_BUFSIZE (CRYPT_INPLACE_BUFSIZE / CRYPT_SECTOR_SIZE) -#define CRYPT_SECTOR_SIZE 512 - -/* aligned 32K writes tends to make flash happy. - * SD card association recommends it. - */ -#define BLOCKS_AT_A_TIME 8 - -struct encryptGroupsData -{ - int realfd; - int cryptofd; - off64_t numblocks; - off64_t one_pct, cur_pct, new_pct; - off64_t blocks_already_done, tot_numblocks; - off64_t used_blocks_already_done, tot_used_blocks; - char* real_blkdev, * crypto_blkdev; - int count; - off64_t offset; - char* buffer; - off64_t last_written_sector; - int completed; - time_t time_started; - int remaining_time; -}; - -static void update_progress(struct encryptGroupsData* data, int is_used) -{ - data->blocks_already_done++; - - if (is_used) { - data->used_blocks_already_done++; - } - if (data->tot_used_blocks) { - data->new_pct = data->used_blocks_already_done / data->one_pct; - } else { - data->new_pct = data->blocks_already_done / data->one_pct; - } - - if (data->new_pct > data->cur_pct) { - char buf[8]; - data->cur_pct = data->new_pct; - snprintf(buf, sizeof(buf), "%" PRId64, data->cur_pct); - property_set("vold.encrypt_progress", buf); - } - - if (data->cur_pct >= 5) { - struct timespec time_now; - if (clock_gettime(CLOCK_MONOTONIC, &time_now)) { - printf("Error getting time"); - } else { - double elapsed_time = difftime(time_now.tv_sec, data->time_started); - off64_t remaining_blocks = data->tot_used_blocks - - data->used_blocks_already_done; - int remaining_time = (int)(elapsed_time * remaining_blocks - / data->used_blocks_already_done); - - // Change time only if not yet set, lower, or a lot higher for - // best user experience - if (data->remaining_time == -1 - || remaining_time < data->remaining_time - || remaining_time > data->remaining_time + 60) { - char buf[8]; - snprintf(buf, sizeof(buf), "%d", remaining_time); - property_set("vold.encrypt_time_remaining", buf); - data->remaining_time = remaining_time; - } - } - } -} - -static void log_progress(struct encryptGroupsData const* data, bool completed) -{ - // Precondition - if completed data = 0 else data != 0 - - // Track progress so we can skip logging blocks - static off64_t offset = -1; - - // Need to close existing 'Encrypting from' log? - if (completed || (offset != -1 && data->offset != offset)) { - printf("Encrypted to sector %" PRId64, - offset / info.block_size * CRYPT_SECTOR_SIZE); - offset = -1; - } - - // Need to start new 'Encrypting from' log? - if (!completed && offset != data->offset) { - printf("Encrypting from sector %" PRId64, - data->offset / info.block_size * CRYPT_SECTOR_SIZE); - } - - // Update offset - if (!completed) { - offset = data->offset + (off64_t)data->count * info.block_size; - } -} - -static int flush_outstanding_data(struct encryptGroupsData* data) -{ - if (data->count == 0) { - return 0; - } - - printf("Copying %d blocks at offset %" PRIx64, data->count, data->offset); - - if (pread64(data->realfd, data->buffer, - info.block_size * data->count, data->offset) - <= 0) { - printf("Error reading real_blkdev %s for inplace encrypt", - data->real_blkdev); - return -1; - } - - if (pwrite64(data->cryptofd, data->buffer, - info.block_size * data->count, data->offset) - <= 0) { - printf("Error writing crypto_blkdev %s for inplace encrypt", - data->crypto_blkdev); - return -1; - } else { - log_progress(data, false); - } - - data->count = 0; - data->last_written_sector = (data->offset + data->count) - / info.block_size * CRYPT_SECTOR_SIZE - 1; - return 0; -} - -static int encrypt_groups(struct encryptGroupsData* data) -{ - unsigned int i; - u8 *block_bitmap = 0; - unsigned int block; - off64_t ret; - int rc = -1; - - data->buffer = malloc(info.block_size * BLOCKS_AT_A_TIME); - if (!data->buffer) { - printf("Failed to allocate crypto buffer"); - goto errout; - } - - block_bitmap = malloc(info.block_size); - if (!block_bitmap) { - printf("failed to allocate block bitmap"); - goto errout; - } - - for (i = 0; i < aux_info.groups; ++i) { - printf("Encrypting group %d", i); - - u32 first_block = aux_info.first_data_block + i * info.blocks_per_group; - u32 block_count = min(info.blocks_per_group, - aux_info.len_blocks - first_block); - - off64_t offset = (u64)info.block_size - * aux_info.bg_desc[i].bg_block_bitmap; - - ret = pread64(data->realfd, block_bitmap, info.block_size, offset); - if (ret != (int)info.block_size) { - printf("failed to read all of block group bitmap %d", i); - goto errout; - } - - offset = (u64)info.block_size * first_block; - - data->count = 0; - - for (block = 0; block < block_count; block++) { - int used = bitmap_get_bit(block_bitmap, block); - update_progress(data, used); - if (used) { - if (data->count == 0) { - data->offset = offset; - } - data->count++; - } else { - if (flush_outstanding_data(data)) { - goto errout; - } - } - - offset += info.block_size; - - /* Write data if we are aligned or buffer size reached */ - if (offset % (info.block_size * BLOCKS_AT_A_TIME) == 0 - || data->count == BLOCKS_AT_A_TIME) { - if (flush_outstanding_data(data)) { - goto errout; - } - } - - if (1) { - printf("Stopping encryption due to low battery"); - rc = 0; - goto errout; - } - - } - if (flush_outstanding_data(data)) { - goto errout; - } - } - - data->completed = 1; - rc = 0; - -errout: - log_progress(0, true); - free(data->buffer); - free(block_bitmap); - return rc; -} - -static int cryptfs_enable_inplace_ext4(char *crypto_blkdev, - char *real_blkdev, - off64_t size, - off64_t *size_already_done, - off64_t tot_size, - off64_t previously_encrypted_upto) -{ - u32 i; - struct encryptGroupsData data; - int rc; // Can't initialize without causing warning -Wclobbered - - if (previously_encrypted_upto > *size_already_done) { - printf("Not fast encrypting since resuming part way through"); - return -1; - } - - memset(&data, 0, sizeof(data)); - data.real_blkdev = real_blkdev; - data.crypto_blkdev = crypto_blkdev; - - if ( (data.realfd = open(real_blkdev, O_RDWR)) < 0) { - printf("Error opening real_blkdev %s for inplace encrypt. err=%d(%s)\n", - real_blkdev, errno, strerror(errno)); - rc = -1; - goto errout; - } - - if ( (data.cryptofd = open(crypto_blkdev, O_WRONLY)) < 0) { - printf("Error opening crypto_blkdev %s for ext4 inplace encrypt. err=%d(%s)\n", - crypto_blkdev, errno, strerror(errno)); - rc = ENABLE_INPLACE_ERR_DEV; - goto errout; - } - - if (setjmp(setjmp_env)) { - printf("Reading ext4 extent caused an exception\n"); - rc = -1; - goto errout; - } - - if (read_ext(data.realfd, 0) != 0) { - printf("Failed to read ext4 extent\n"); - rc = -1; - goto errout; - } - - data.numblocks = size / CRYPT_SECTORS_PER_BUFSIZE; - data.tot_numblocks = tot_size / CRYPT_SECTORS_PER_BUFSIZE; - data.blocks_already_done = *size_already_done / CRYPT_SECTORS_PER_BUFSIZE; - - printf("Encrypting ext4 filesystem in place..."); - - data.tot_used_blocks = data.numblocks; - for (i = 0; i < aux_info.groups; ++i) { - data.tot_used_blocks -= aux_info.bg_desc[i].bg_free_blocks_count; - } - - data.one_pct = data.tot_used_blocks / 100; - data.cur_pct = 0; - - struct timespec time_started = {0}; - if (clock_gettime(CLOCK_MONOTONIC, &time_started)) { - printf("Error getting time at start"); - // Note - continue anyway - we'll run with 0 - } - data.time_started = time_started.tv_sec; - data.remaining_time = -1; - - rc = encrypt_groups(&data); - if (rc) { - printf("Error encrypting groups"); - goto errout; - } - - *size_already_done += data.completed ? size : data.last_written_sector; - rc = 0; - -errout: - close(data.realfd); - close(data.cryptofd); - - return rc; -} - -static void log_progress_f2fs(u64 block, bool completed) -{ - // Precondition - if completed data = 0 else data != 0 - - // Track progress so we can skip logging blocks - static u64 last_block = (u64)-1; - - // Need to close existing 'Encrypting from' log? - if (completed || (last_block != (u64)-1 && block != last_block + 1)) { - printf("Encrypted to block %" PRId64, last_block); - last_block = -1; - } - - // Need to start new 'Encrypting from' log? - if (!completed && (last_block == (u64)-1 || block != last_block + 1)) { - printf("Encrypting from block %" PRId64, block); - } - - // Update offset - if (!completed) { - last_block = block; - } -} - -static int encrypt_one_block_f2fs(u64 pos, void *data) -{ - struct encryptGroupsData *priv_dat = (struct encryptGroupsData *)data; - - priv_dat->blocks_already_done = pos - 1; - update_progress(priv_dat, 1); - - off64_t offset = pos * CRYPT_INPLACE_BUFSIZE; - - if (pread64(priv_dat->realfd, priv_dat->buffer, CRYPT_INPLACE_BUFSIZE, offset) <= 0) { - printf("Error reading real_blkdev %s for f2fs inplace encrypt", priv_dat->crypto_blkdev); - return -1; - } - - if (pwrite64(priv_dat->cryptofd, priv_dat->buffer, CRYPT_INPLACE_BUFSIZE, offset) <= 0) { - printf("Error writing crypto_blkdev %s for f2fs inplace encrypt", priv_dat->crypto_blkdev); - return -1; - } else { - log_progress_f2fs(pos, false); - } - - return 0; -} - -static int cryptfs_enable_inplace_f2fs(char *crypto_blkdev, - char *real_blkdev, - off64_t size, - off64_t *size_already_done, - off64_t tot_size, - off64_t previously_encrypted_upto) -{ - u32 i; - struct encryptGroupsData data; - struct f2fs_info *f2fs_info = NULL; - int rc = ENABLE_INPLACE_ERR_OTHER; - if (previously_encrypted_upto > *size_already_done) { - printf("Not fast encrypting since resuming part way through"); - return ENABLE_INPLACE_ERR_OTHER; - } - memset(&data, 0, sizeof(data)); - data.real_blkdev = real_blkdev; - data.crypto_blkdev = crypto_blkdev; - data.realfd = -1; - data.cryptofd = -1; - if ( (data.realfd = open64(real_blkdev, O_RDWR)) < 0) { - printf("Error opening real_blkdev %s for f2fs inplace encrypt\n", - real_blkdev); - goto errout; - } - if ( (data.cryptofd = open64(crypto_blkdev, O_WRONLY)) < 0) { - printf("Error opening crypto_blkdev %s for f2fs inplace encrypt. err=%d(%s)\n", - crypto_blkdev, errno, strerror(errno)); - rc = ENABLE_INPLACE_ERR_DEV; - goto errout; - } - - f2fs_info = generate_f2fs_info(data.realfd); - if (!f2fs_info) - goto errout; - - data.numblocks = size / CRYPT_SECTORS_PER_BUFSIZE; - data.tot_numblocks = tot_size / CRYPT_SECTORS_PER_BUFSIZE; - data.blocks_already_done = *size_already_done / CRYPT_SECTORS_PER_BUFSIZE; - - data.tot_used_blocks = get_num_blocks_used(f2fs_info); - - data.one_pct = data.tot_used_blocks / 100; - data.cur_pct = 0; - data.time_started = time(NULL); - data.remaining_time = -1; - - data.buffer = malloc(f2fs_info->block_size); - if (!data.buffer) { - printf("Failed to allocate crypto buffer"); - goto errout; - } - - data.count = 0; - - /* Currently, this either runs to completion, or hits a nonrecoverable error */ - rc = run_on_used_blocks(data.blocks_already_done, f2fs_info, &encrypt_one_block_f2fs, &data); - - if (rc) { - printf("Error in running over f2fs blocks"); - rc = ENABLE_INPLACE_ERR_OTHER; - goto errout; - } - - *size_already_done += size; - rc = 0; - -errout: - if (rc) - printf("Failed to encrypt f2fs filesystem on %s", real_blkdev); - - log_progress_f2fs(0, true); - free(f2fs_info); - free(data.buffer); - close(data.realfd); - close(data.cryptofd); - - return rc; -} - -static int cryptfs_enable_inplace_full(char *crypto_blkdev, char *real_blkdev, - off64_t size, off64_t *size_already_done, - off64_t tot_size, - off64_t previously_encrypted_upto) -{ - int realfd, cryptofd; - char *buf[CRYPT_INPLACE_BUFSIZE]; - int rc = ENABLE_INPLACE_ERR_OTHER; - off64_t numblocks, i, remainder; - off64_t one_pct, cur_pct, new_pct; - off64_t blocks_already_done, tot_numblocks; - - if ( (realfd = open(real_blkdev, O_RDONLY)) < 0) { - printf("Error opening real_blkdev %s for inplace encrypt\n", real_blkdev); - return ENABLE_INPLACE_ERR_OTHER; - } - - if ( (cryptofd = open(crypto_blkdev, O_WRONLY)) < 0) { - printf("Error opening crypto_blkdev %s for inplace encrypt. err=%d(%s)\n", - crypto_blkdev, errno, strerror(errno)); - close(realfd); - return ENABLE_INPLACE_ERR_DEV; - } - - /* This is pretty much a simple loop of reading 4K, and writing 4K. - * The size passed in is the number of 512 byte sectors in the filesystem. - * So compute the number of whole 4K blocks we should read/write, - * and the remainder. - */ - numblocks = size / CRYPT_SECTORS_PER_BUFSIZE; - remainder = size % CRYPT_SECTORS_PER_BUFSIZE; - tot_numblocks = tot_size / CRYPT_SECTORS_PER_BUFSIZE; - blocks_already_done = *size_already_done / CRYPT_SECTORS_PER_BUFSIZE; - - printf("Encrypting filesystem in place..."); - - i = previously_encrypted_upto + 1 - *size_already_done; - - if (lseek64(realfd, i * CRYPT_SECTOR_SIZE, SEEK_SET) < 0) { - printf("Cannot seek to previously encrypted point on %s", real_blkdev); - goto errout; - } - - if (lseek64(cryptofd, i * CRYPT_SECTOR_SIZE, SEEK_SET) < 0) { - printf("Cannot seek to previously encrypted point on %s", crypto_blkdev); - goto errout; - } - - for (;i < size && i % CRYPT_SECTORS_PER_BUFSIZE != 0; ++i) { - if (unix_read(realfd, buf, CRYPT_SECTOR_SIZE) <= 0) { - printf("Error reading initial sectors from real_blkdev %s for " - "inplace encrypt\n", crypto_blkdev); - goto errout; - } - if (unix_write(cryptofd, buf, CRYPT_SECTOR_SIZE) <= 0) { - printf("Error writing initial sectors to crypto_blkdev %s for " - "inplace encrypt\n", crypto_blkdev); - goto errout; - } else { - printf("Encrypted 1 block at %" PRId64, i); - } - } - - one_pct = tot_numblocks / 100; - cur_pct = 0; - /* process the majority of the filesystem in blocks */ - for (i/=CRYPT_SECTORS_PER_BUFSIZE; i<numblocks; i++) { - new_pct = (i + blocks_already_done) / one_pct; - if (new_pct > cur_pct) { - char buf[8]; - - cur_pct = new_pct; - snprintf(buf, sizeof(buf), "%" PRId64, cur_pct); - property_set("vold.encrypt_progress", buf); - } - if (unix_read(realfd, buf, CRYPT_INPLACE_BUFSIZE) <= 0) { - printf("Error reading real_blkdev %s for inplace encrypt", crypto_blkdev); - goto errout; - } - if (unix_write(cryptofd, buf, CRYPT_INPLACE_BUFSIZE) <= 0) { - printf("Error writing crypto_blkdev %s for inplace encrypt", crypto_blkdev); - goto errout; - } else { - printf("Encrypted %d block at %" PRId64, - CRYPT_SECTORS_PER_BUFSIZE, - i * CRYPT_SECTORS_PER_BUFSIZE); - } - - if (1) { - printf("Stopping encryption due to low battery"); - *size_already_done += (i + 1) * CRYPT_SECTORS_PER_BUFSIZE - 1; - rc = 0; - goto errout; - } - } - - /* Do any remaining sectors */ - for (i=0; i<remainder; i++) { - if (unix_read(realfd, buf, CRYPT_SECTOR_SIZE) <= 0) { - printf("Error reading final sectors from real_blkdev %s for inplace encrypt", crypto_blkdev); - goto errout; - } - if (unix_write(cryptofd, buf, CRYPT_SECTOR_SIZE) <= 0) { - printf("Error writing final sectors to crypto_blkdev %s for inplace encrypt", crypto_blkdev); - goto errout; - } else { - printf("Encrypted 1 block at next location"); - } - } - - *size_already_done += size; - rc = 0; - -errout: - close(realfd); - close(cryptofd); - - return rc; -} - -/* returns on of the ENABLE_INPLACE_* return codes */ -static int cryptfs_enable_inplace(char *crypto_blkdev, char *real_blkdev, - off64_t size, off64_t *size_already_done, - off64_t tot_size, - off64_t previously_encrypted_upto) -{ - int rc_ext4, rc_f2fs, rc_full; - if (previously_encrypted_upto) { - printf("Continuing encryption from %" PRId64, previously_encrypted_upto); - } - - if (*size_already_done + size < previously_encrypted_upto) { - *size_already_done += size; - return 0; - } - - /* TODO: identify filesystem type. - * As is, cryptfs_enable_inplace_ext4 will fail on an f2fs partition, and - * then we will drop down to cryptfs_enable_inplace_f2fs. - * */ - if ((rc_ext4 = cryptfs_enable_inplace_ext4(crypto_blkdev, real_blkdev, - size, size_already_done, - tot_size, previously_encrypted_upto)) == 0) { - return 0; - } - printf("cryptfs_enable_inplace_ext4()=%d\n", rc_ext4); - - if ((rc_f2fs = cryptfs_enable_inplace_f2fs(crypto_blkdev, real_blkdev, - size, size_already_done, - tot_size, previously_encrypted_upto)) == 0) { - return 0; - } - printf("cryptfs_enable_inplace_f2fs()=%d\n", rc_f2fs); - - rc_full = cryptfs_enable_inplace_full(crypto_blkdev, real_blkdev, - size, size_already_done, tot_size, - previously_encrypted_upto); - printf("cryptfs_enable_inplace_full()=%d\n", rc_full); - - /* Hack for b/17898962, the following is the symptom... */ - if (rc_ext4 == ENABLE_INPLACE_ERR_DEV - && rc_f2fs == ENABLE_INPLACE_ERR_DEV - && rc_full == ENABLE_INPLACE_ERR_DEV) { - return ENABLE_INPLACE_ERR_DEV; - } - return rc_full; -} - -#define CRYPTO_ENABLE_WIPE 1 -#define CRYPTO_ENABLE_INPLACE 2 - -#define FRAMEWORK_BOOT_WAIT 60 - -static inline int should_encrypt(struct volume_info *volume) -{ - return (volume->flags & (VOL_ENCRYPTABLE | VOL_NONREMOVABLE)) == - (VOL_ENCRYPTABLE | VOL_NONREMOVABLE); -} - -static int cryptfs_SHA256_fileblock(const char* filename, __le8* buf) -{ - int fd = open(filename, O_RDONLY); - if (fd == -1) { - printf("Error opening file %s", filename); - return -1; - } - - char block[CRYPT_INPLACE_BUFSIZE]; - memset(block, 0, sizeof(block)); - if (unix_read(fd, block, sizeof(block)) < 0) { - printf("Error reading file %s", filename); - close(fd); - return -1; - } - - close(fd); - - SHA256_CTX c; - SHA256_Init(&c); - SHA256_Update(&c, block, sizeof(block)); - SHA256_Final(buf, &c); - - return 0; -} - -static int get_fs_type(struct fstab_rec *rec) -{ - if (!strcmp(rec->fs_type, "ext4")) { - return EXT4_FS; - } else if (!strcmp(rec->fs_type, "f2fs")) { - return F2FS_FS; - } else { - return -1; - } -} - -static int cryptfs_enable_all_volumes(struct crypt_mnt_ftr *crypt_ftr, int how, - char *crypto_blkdev, char *real_blkdev, - int previously_encrypted_upto) -{ - off64_t cur_encryption_done=0, tot_encryption_size=0; - int i, rc = -1; - - if (1) { - printf("Not starting encryption due to low battery"); - return 0; - } - - /* The size of the userdata partition, and add in the vold volumes below */ - tot_encryption_size = crypt_ftr->fs_size; - - if (how == CRYPTO_ENABLE_WIPE) { - struct fstab_rec* rec = fs_mgr_get_entry_for_mount_point(fstab, DATA_MNT_POINT); - int fs_type = get_fs_type(rec); - if (fs_type < 0) { - printf("cryptfs_enable: unsupported fs type %s\n", rec->fs_type); - return -1; - } - rc = cryptfs_enable_wipe(crypto_blkdev, crypt_ftr->fs_size, fs_type); - } else if (how == CRYPTO_ENABLE_INPLACE) { - rc = cryptfs_enable_inplace(crypto_blkdev, real_blkdev, - crypt_ftr->fs_size, &cur_encryption_done, - tot_encryption_size, - previously_encrypted_upto); - - if (rc == ENABLE_INPLACE_ERR_DEV) { - /* Hack for b/17898962 */ - printf("cryptfs_enable: crypto block dev failure. Must reboot...\n"); - cryptfs_reboot(reboot); - } - - if (!rc) { - crypt_ftr->encrypted_upto = cur_encryption_done; - } - - if (!rc && crypt_ftr->encrypted_upto == crypt_ftr->fs_size) { - /* The inplace routine never actually sets the progress to 100% due - * to the round down nature of integer division, so set it here */ - property_set("vold.encrypt_progress", "100"); - } - } else { - /* Shouldn't happen */ - printf("cryptfs_enable: internal error, unknown option\n"); - rc = -1; - } - - return rc; -} - -int cryptfs_enable_internal(char *howarg, int crypt_type, char *passwd, - int allow_reboot) -{ - int how = 0; - char crypto_blkdev[MAXPATHLEN], real_blkdev[MAXPATHLEN]; - unsigned long nr_sec; - unsigned char decrypted_master_key[KEY_LEN_BYTES]; - int rc=-1, fd, i, ret; - struct crypt_mnt_ftr crypt_ftr; - struct crypt_persist_data *pdata; - char encrypted_state[PROPERTY_VALUE_MAX]; - char lockid[32] = { 0 }; - char key_loc[PROPERTY_VALUE_MAX]; - char fuse_sdcard[PROPERTY_VALUE_MAX]; - char *sd_mnt_point; - int num_vols; - struct volume_info *vol_list = 0; - off64_t previously_encrypted_upto = 0; -printf("cryptfs_enable_internal disabled by TWRP\n"); -return -1; - if (!strcmp(howarg, "wipe")) { - how = CRYPTO_ENABLE_WIPE; - } else if (! strcmp(howarg, "inplace")) { - how = CRYPTO_ENABLE_INPLACE; - } else { - /* Shouldn't happen, as CommandListener vets the args */ - goto error_unencrypted; - } - - /* See if an encryption was underway and interrupted */ - if (how == CRYPTO_ENABLE_INPLACE - && get_crypt_ftr_and_key(&crypt_ftr) == 0 - && (crypt_ftr.flags & CRYPT_ENCRYPTION_IN_PROGRESS)) { - previously_encrypted_upto = crypt_ftr.encrypted_upto; - crypt_ftr.encrypted_upto = 0; - crypt_ftr.flags &= ~CRYPT_ENCRYPTION_IN_PROGRESS; - - /* At this point, we are in an inconsistent state. Until we successfully - complete encryption, a reboot will leave us broken. So mark the - encryption failed in case that happens. - On successfully completing encryption, remove this flag */ - crypt_ftr.flags |= CRYPT_INCONSISTENT_STATE; - - put_crypt_ftr_and_key(&crypt_ftr); - } - - property_get("ro.crypto.state", encrypted_state, ""); - if (!strcmp(encrypted_state, "encrypted") && !previously_encrypted_upto) { - printf("Device is already running encrypted, aborting"); - goto error_unencrypted; - } - - // TODO refactor fs_mgr_get_crypt_info to get both in one call - fs_mgr_get_crypt_info(fstab, key_loc, 0, sizeof(key_loc)); - fs_mgr_get_crypt_info(fstab, 0, real_blkdev, sizeof(real_blkdev)); - - /* Get the size of the real block device */ - fd = open(real_blkdev, O_RDONLY); - if ( (nr_sec = get_blkdev_size(fd)) == 0) { - printf("Cannot get size of block device %s\n", real_blkdev); - goto error_unencrypted; - } - close(fd); - - /* If doing inplace encryption, make sure the orig fs doesn't include the crypto footer */ - if ((how == CRYPTO_ENABLE_INPLACE) && (!strcmp(key_loc, KEY_IN_FOOTER))) { - unsigned int fs_size_sec, max_fs_size_sec; - fs_size_sec = get_fs_size(real_blkdev); - if (fs_size_sec == 0) - fs_size_sec = get_f2fs_filesystem_size_sec(real_blkdev); - - max_fs_size_sec = nr_sec - (CRYPT_FOOTER_OFFSET / CRYPT_SECTOR_SIZE); - - if (fs_size_sec > max_fs_size_sec) { - printf("Orig filesystem overlaps crypto footer region. Cannot encrypt in place."); - goto error_unencrypted; - } - } - - /* Get a wakelock as this may take a while, and we don't want the - * device to sleep on us. We'll grab a partial wakelock, and if the UI - * wants to keep the screen on, it can grab a full wakelock. - */ - snprintf(lockid, sizeof(lockid), "enablecrypto%d", (int) getpid()); - acquire_wake_lock(PARTIAL_WAKE_LOCK, lockid); - - /* Get the sdcard mount point */ - sd_mnt_point = getenv("EMULATED_STORAGE_SOURCE"); - if (!sd_mnt_point) { - sd_mnt_point = getenv("EXTERNAL_STORAGE"); - } - if (!sd_mnt_point) { - sd_mnt_point = "/mnt/sdcard"; - } - - /* TODO - * Currently do not have test devices with multiple encryptable volumes. - * When we acquire some, re-add support. - */ - num_vols=0/*vold_getNumDirectVolumes()*/; - vol_list = malloc(sizeof(struct volume_info) * num_vols); - //vold_getDirectVolumeList(vol_list); - - for (i=0; i<num_vols; i++) { - if (should_encrypt(&vol_list[i])) { - printf("Cannot encrypt if there are multiple encryptable volumes" - "%s\n", vol_list[i].label); - goto error_unencrypted; - } - } - - /* The init files are setup to stop the class main and late start when - * vold sets trigger_shutdown_framework. - */ - property_set("vold.decrypt", "trigger_shutdown_framework"); - printf("Just asked init to shut down class main\n"); - - if (1 /*vold_unmountAllAsecs()*/) { - /* Just report the error. If any are left mounted, - * umounting /data below will fail and handle the error. - */ - printf("Error unmounting internal asecs"); - } - - property_get("ro.crypto.fuse_sdcard", fuse_sdcard, ""); - if (!strcmp(fuse_sdcard, "true")) { - /* This is a device using the fuse layer to emulate the sdcard semantics - * on top of the userdata partition. vold does not manage it, it is managed - * by the sdcard service. The sdcard service was killed by the property trigger - * above, so just unmount it now. We must do this _AFTER_ killing the framework, - * unlike the case for vold managed devices above. - */ - if (wait_and_unmount(sd_mnt_point, false)) { - goto error_shutting_down; - } - } - - /* Now unmount the /data partition. */ - if (wait_and_unmount(DATA_MNT_POINT, false)) { - if (allow_reboot) { - goto error_shutting_down; - } else { - goto error_unencrypted; - } - } - - /* Do extra work for a better UX when doing the long inplace encryption */ - if (how == CRYPTO_ENABLE_INPLACE) { - /* Now that /data is unmounted, we need to mount a tmpfs - * /data, set a property saying we're doing inplace encryption, - * and restart the framework. - */ - if (fs_mgr_do_tmpfs_mount(DATA_MNT_POINT)) { - goto error_shutting_down; - } - /* Tells the framework that inplace encryption is starting */ - property_set("vold.encrypt_progress", "0"); - - /* restart the framework. */ - /* Create necessary paths on /data */ - if (prep_data_fs()) { - goto error_shutting_down; - } - - /* Ugh, shutting down the framework is not synchronous, so until it - * can be fixed, this horrible hack will wait a moment for it all to - * shut down before proceeding. Without it, some devices cannot - * restart the graphics services. - */ - sleep(2); - - /* startup service classes main and late_start */ - property_set("vold.decrypt", "trigger_restart_min_framework"); - printf("Just triggered restart_min_framework\n"); - - /* OK, the framework is restarted and will soon be showing a - * progress bar. Time to setup an encrypted mapping, and - * either write a new filesystem, or encrypt in place updating - * the progress bar as we work. - */ - } - - /* Start the actual work of making an encrypted filesystem */ - /* Initialize a crypt_mnt_ftr for the partition */ - if (previously_encrypted_upto == 0) { - if (cryptfs_init_crypt_mnt_ftr(&crypt_ftr)) { - goto error_shutting_down; - } - - if (!strcmp(key_loc, KEY_IN_FOOTER)) { - crypt_ftr.fs_size = nr_sec - - (CRYPT_FOOTER_OFFSET / CRYPT_SECTOR_SIZE); - } else { - crypt_ftr.fs_size = nr_sec; - } - /* At this point, we are in an inconsistent state. Until we successfully - complete encryption, a reboot will leave us broken. So mark the - encryption failed in case that happens. - On successfully completing encryption, remove this flag */ - crypt_ftr.flags |= CRYPT_INCONSISTENT_STATE; - crypt_ftr.crypt_type = crypt_type; - strcpy((char *)crypt_ftr.crypto_type_name, "aes-cbc-essiv:sha256"); - - /* Make an encrypted master key */ - if (create_encrypted_random_key(passwd, crypt_ftr.master_key, crypt_ftr.salt, &crypt_ftr)) { - printf("Cannot create encrypted master key\n"); - goto error_shutting_down; - } - - /* Write the key to the end of the partition */ - put_crypt_ftr_and_key(&crypt_ftr); - - /* If any persistent data has been remembered, save it. - * If none, create a valid empty table and save that. - */ - if (!persist_data) { - pdata = malloc(CRYPT_PERSIST_DATA_SIZE); - if (pdata) { - init_empty_persist_data(pdata, CRYPT_PERSIST_DATA_SIZE); - persist_data = pdata; - } - } - if (persist_data) { - save_persistent_data(); - } - } - - decrypt_master_key(passwd, decrypted_master_key, &crypt_ftr, 0, 0); - create_crypto_blk_dev(&crypt_ftr, decrypted_master_key, real_blkdev, crypto_blkdev, - "userdata"); - - /* If we are continuing, check checksums match */ - rc = 0; - if (previously_encrypted_upto) { - __le8 hash_first_block[SHA256_DIGEST_LENGTH]; - rc = cryptfs_SHA256_fileblock(crypto_blkdev, hash_first_block); - - if (!rc && memcmp(hash_first_block, crypt_ftr.hash_first_block, - sizeof(hash_first_block)) != 0) { - printf("Checksums do not match - trigger wipe"); - rc = -1; - } - } - - if (!rc) { - rc = cryptfs_enable_all_volumes(&crypt_ftr, how, - crypto_blkdev, real_blkdev, - previously_encrypted_upto); - } - - /* Calculate checksum if we are not finished */ - if (!rc && crypt_ftr.encrypted_upto != crypt_ftr.fs_size) { - rc = cryptfs_SHA256_fileblock(crypto_blkdev, - crypt_ftr.hash_first_block); - if (rc) { - printf("Error calculating checksum for continuing encryption"); - rc = -1; - } - } - - /* Undo the dm-crypt mapping whether we succeed or not */ - delete_crypto_blk_dev("userdata"); - - free(vol_list); - - if (! rc) { - /* Success */ - crypt_ftr.flags &= ~CRYPT_INCONSISTENT_STATE; - - if (crypt_ftr.encrypted_upto != crypt_ftr.fs_size) { - printf("Encrypted up to sector %lld - will continue after reboot", - crypt_ftr.encrypted_upto); - crypt_ftr.flags |= CRYPT_ENCRYPTION_IN_PROGRESS; - } - - put_crypt_ftr_and_key(&crypt_ftr); - - if (crypt_ftr.encrypted_upto == crypt_ftr.fs_size) { - char value[PROPERTY_VALUE_MAX]; - property_get("ro.crypto.state", value, ""); - if (!strcmp(value, "")) { - /* default encryption - continue first boot sequence */ - property_set("ro.crypto.state", "encrypted"); - release_wake_lock(lockid); - cryptfs_check_passwd(DEFAULT_PASSWORD); - cryptfs_restart_internal(1); - return 0; - } else { - sleep(2); /* Give the UI a chance to show 100% progress */ - cryptfs_reboot(reboot); - } - } else { - sleep(2); /* Partially encrypted, ensure writes flushed to ssd */ - cryptfs_reboot(shutdown); - } - } else { - char value[PROPERTY_VALUE_MAX]; - - property_get("ro.vold.wipe_on_crypt_fail", value, "0"); - if (!strcmp(value, "1")) { - /* wipe data if encryption failed */ - printf("encryption failed - rebooting into recovery to wipe data\n"); - mkdir("/cache/recovery", 0700); - int fd = open("/cache/recovery/command", O_RDWR|O_CREAT|O_TRUNC, 0600); - if (fd >= 0) { - write(fd, "--wipe_data\n", strlen("--wipe_data\n") + 1); - write(fd, "--reason=cryptfs_enable_internal\n", strlen("--reason=cryptfs_enable_internal\n") + 1); - close(fd); - } else { - printf("could not open /cache/recovery/command\n"); - } - cryptfs_reboot(recovery); - } else { - /* set property to trigger dialog */ - property_set("vold.encrypt_progress", "error_partially_encrypted"); - release_wake_lock(lockid); - } - return -1; - } - - /* hrm, the encrypt step claims success, but the reboot failed. - * This should not happen. - * Set the property and return. Hope the framework can deal with it. - */ - property_set("vold.encrypt_progress", "error_reboot_failed"); - release_wake_lock(lockid); - return rc; - -error_unencrypted: - free(vol_list); - property_set("vold.encrypt_progress", "error_not_encrypted"); - if (lockid[0]) { - release_wake_lock(lockid); - } - return -1; - -error_shutting_down: - /* we failed, and have not encrypted anthing, so the users's data is still intact, - * but the framework is stopped and not restarted to show the error, so it's up to - * vold to restart the system. - */ - printf("Error enabling encryption after framework is shutdown, no data changed, restarting system"); - cryptfs_reboot(reboot); - - /* shouldn't get here */ - property_set("vold.encrypt_progress", "error_shutting_down"); - free(vol_list); - if (lockid[0]) { - release_wake_lock(lockid); - } - return -1; -} - -int cryptfs_enable(char *howarg, int type, char *passwd, int allow_reboot) -{ - char* adjusted_passwd = adjust_passwd(passwd); - if (adjusted_passwd) { - passwd = adjusted_passwd; - } - - int rc = cryptfs_enable_internal(howarg, type, passwd, allow_reboot); - - free(adjusted_passwd); - return rc; -} - -int cryptfs_enable_default(char *howarg, int allow_reboot) -{ - return cryptfs_enable_internal(howarg, CRYPT_TYPE_DEFAULT, - DEFAULT_PASSWORD, allow_reboot); -} - -int cryptfs_changepw(int crypt_type, const char *newpw) -{ - struct crypt_mnt_ftr crypt_ftr; - unsigned char decrypted_master_key[KEY_LEN_BYTES]; - - /* This is only allowed after we've successfully decrypted the master key */ - if (!master_key_saved) { - printf("Key not saved, aborting"); - return -1; - } - - if (crypt_type < 0 || crypt_type > CRYPT_TYPE_MAX_TYPE) { - printf("Invalid crypt_type %d", crypt_type); - return -1; - } - - /* get key */ - if (get_crypt_ftr_and_key(&crypt_ftr)) { - printf("Error getting crypt footer and key"); - return -1; - } - - crypt_ftr.crypt_type = crypt_type; - - char* adjusted_passwd = adjust_passwd(newpw); - if (adjusted_passwd) { - newpw = adjusted_passwd; - } - - encrypt_master_key(crypt_type == CRYPT_TYPE_DEFAULT ? DEFAULT_PASSWORD - : newpw, - crypt_ftr.salt, - saved_master_key, - crypt_ftr.master_key, - &crypt_ftr); - - /* save the key */ - put_crypt_ftr_and_key(&crypt_ftr); - - free(adjusted_passwd); - return 0; -} - -static int persist_get_key(char *fieldname, char *value) -{ - unsigned int i; - - if (persist_data == NULL) { - return -1; - } - for (i = 0; i < persist_data->persist_valid_entries; i++) { - if (!strncmp(persist_data->persist_entry[i].key, fieldname, PROPERTY_KEY_MAX)) { - /* We found it! */ - strlcpy(value, persist_data->persist_entry[i].val, PROPERTY_VALUE_MAX); - return 0; - } - } - - return -1; -} - -static int persist_set_key(char *fieldname, char *value, int encrypted) -{ - unsigned int i; - unsigned int num; - struct crypt_mnt_ftr crypt_ftr; - unsigned int max_persistent_entries; - unsigned int dsize; - - if (persist_data == NULL) { - return -1; - } - - /* If encrypted, use the values from the crypt_ftr, otherwise - * use the values for the current spec. - */ - if (encrypted) { - if(get_crypt_ftr_and_key(&crypt_ftr)) { - return -1; - } - dsize = crypt_ftr.persist_data_size; - } else { - dsize = CRYPT_PERSIST_DATA_SIZE; - } - max_persistent_entries = (dsize - sizeof(struct crypt_persist_data)) / - sizeof(struct crypt_persist_entry); - - num = persist_data->persist_valid_entries; - - for (i = 0; i < num; i++) { - if (!strncmp(persist_data->persist_entry[i].key, fieldname, PROPERTY_KEY_MAX)) { - /* We found an existing entry, update it! */ - memset(persist_data->persist_entry[i].val, 0, PROPERTY_VALUE_MAX); - strlcpy(persist_data->persist_entry[i].val, value, PROPERTY_VALUE_MAX); - return 0; - } - } - - /* We didn't find it, add it to the end, if there is room */ - if (persist_data->persist_valid_entries < max_persistent_entries) { - memset(&persist_data->persist_entry[num], 0, sizeof(struct crypt_persist_entry)); - strlcpy(persist_data->persist_entry[num].key, fieldname, PROPERTY_KEY_MAX); - strlcpy(persist_data->persist_entry[num].val, value, PROPERTY_VALUE_MAX); - persist_data->persist_valid_entries++; - return 0; - } - - return -1; -} - -/* Return the value of the specified field. */ -int cryptfs_getfield(char *fieldname, char *value, int len) -{ - char temp_value[PROPERTY_VALUE_MAX]; - char real_blkdev[MAXPATHLEN]; - /* 0 is success, 1 is not encrypted, - * -1 is value not set, -2 is any other error - */ - int rc = -2; - - if (persist_data == NULL) { - load_persistent_data(); - if (persist_data == NULL) { - printf("Getfield error, cannot load persistent data"); - goto out; - } - } - - if (!persist_get_key(fieldname, temp_value)) { - /* We found it, copy it to the caller's buffer and return */ - strlcpy(value, temp_value, len); - rc = 0; - } else { - /* Sadness, it's not there. Return the error */ - rc = -1; - } - -out: - return rc; -} - -/* Set the value of the specified field. */ -int cryptfs_setfield(char *fieldname, char *value) -{ - struct crypt_persist_data stored_pdata; - struct crypt_persist_data *pdata_p; - struct crypt_mnt_ftr crypt_ftr; - char encrypted_state[PROPERTY_VALUE_MAX]; - /* 0 is success, -1 is an error */ - int rc = -1; - int encrypted = 0; - - if (persist_data == NULL) { - load_persistent_data(); - if (persist_data == NULL) { - printf("Setfield error, cannot load persistent data"); - goto out; - } - } - - property_get("ro.crypto.state", encrypted_state, ""); - if (!strcmp(encrypted_state, "encrypted") ) { - encrypted = 1; - } - - if (persist_set_key(fieldname, value, encrypted)) { - goto out; - } - - /* If we are running encrypted, save the persistent data now */ - if (encrypted) { - if (save_persistent_data()) { - printf("Setfield error, cannot save persistent data"); - goto out; - } - } - - rc = 0; - -out: - return rc; -} - -/* Checks userdata. Attempt to mount the volume if default- - * encrypted. - * On success trigger next init phase and return 0. - * Currently do not handle failure - see TODO below. - */ -int cryptfs_mount_default_encrypted(void) -{ - char decrypt_state[PROPERTY_VALUE_MAX]; - property_get("vold.decrypt", decrypt_state, "0"); - if (!strcmp(decrypt_state, "0")) { - printf("Not encrypted - should not call here"); - } else { - int crypt_type = cryptfs_get_password_type(); - if (crypt_type < 0 || crypt_type > CRYPT_TYPE_MAX_TYPE) { - printf("Bad crypt type - error"); - } else if (crypt_type != CRYPT_TYPE_DEFAULT) { - printf("Password is not default - " - "starting min framework to prompt"); - property_set("vold.decrypt", "trigger_restart_min_framework"); - return 0; - } else if (cryptfs_check_passwd(DEFAULT_PASSWORD) == 0) { - printf("Password is default - restarting filesystem"); - cryptfs_restart_internal(0); - return 0; - } else { - printf("Encrypted, default crypt type but can't decrypt"); - } - } - - /** Corrupt. Allow us to boot into framework, which will detect bad - crypto when it calls do_crypto_complete, then do a factory reset - */ - property_set("vold.decrypt", "trigger_restart_min_framework"); - return 0; -} - /* Returns type of the password, default, pattern, pin or password. */ int cryptfs_get_password_type(void) { struct crypt_mnt_ftr crypt_ftr; - char fstab_filename[PROPERTY_VALUE_MAX + sizeof(FSTAB_PREFIX)]; - char propbuf[PROPERTY_VALUE_MAX]; - - property_get("ro.hardware", propbuf, ""); - snprintf(fstab_filename, sizeof(fstab_filename), FSTAB_PREFIX"%s", propbuf); - - fstab = fs_mgr_read_fstab(fstab_filename); - if (!fstab) { - printf("failed to open %s\n", fstab_filename); - return -1; - } if (get_crypt_ftr_and_key(&crypt_ftr)) { printf("Error getting crypt footer and key\n"); @@ -3595,26 +1445,3 @@ int cryptfs_get_password_type(void) return crypt_ftr.crypt_type; } - -char* cryptfs_get_password() -{ - struct timespec now; - clock_gettime(CLOCK_MONOTONIC, &now); - if (now.tv_sec < password_expiry_time) { - return password; - } else { - cryptfs_clear_password(); - return 0; - } -} - -void cryptfs_clear_password() -{ - if (password) { - size_t len = strlen(password); - memset(password, 0, len); - free(password); - password = 0; - password_expiry_time = 0; - } -} diff --git a/crypto/lollipop/cryptfs.h b/crypto/lollipop/cryptfs.h index b95a290cf..8cb8a7a32 100644 --- a/crypto/lollipop/cryptfs.h +++ b/crypto/lollipop/cryptfs.h @@ -208,24 +208,11 @@ extern "C" { typedef int (*kdf_func)(const char *passwd, const unsigned char *salt, unsigned char *ikey, void *params); - int cryptfs_crypto_complete(void); - int cryptfs_check_footer(void); + void set_partition_data(const char* block_device, const char* key_location, const char* fs); + int cryptfs_check_footer(); int cryptfs_check_passwd(char *pw); int cryptfs_verify_passwd(char *newpw); - int cryptfs_restart(void); - int cryptfs_enable(char *flag, int type, char *passwd, int allow_reboot); - int cryptfs_changepw(int type, const char *newpw); - int cryptfs_enable_default(char *flag, int allow_reboot); - int cryptfs_setup_volume(const char *label, int major, int minor, - char *crypto_dev_path, unsigned int max_pathlen, - int *new_major, int *new_minor); - int cryptfs_revert_volume(const char *label); - int cryptfs_getfield(char *fieldname, char *value, int len); - int cryptfs_setfield(char *fieldname, char *value); - int cryptfs_mount_default_encrypted(void); int cryptfs_get_password_type(void); - char* cryptfs_get_password(void); - void cryptfs_clear_password(void); #ifdef __cplusplus } #endif |