From 74f29f1df7d12c0cc06e9d6685adf15e757d8eda Mon Sep 17 00:00:00 2001 From: Paul Lawrence Date: Thu, 28 Aug 2014 15:54:10 -0700 Subject: [PATCH] Don't test mount when we can use the crypto footer to test the password Note that this also changes the boot sequence, and moves the test for corrupted data to cryptfs_restart_internal. Bug: 17213613 Change-Id: I0f86e8fe3d482e2d1373bd0f4d0d861e63ad8904 --- cryptfs.c | 163 +++++++++++++++++++++++++++++++++++------------------- cryptfs.h | 10 ++++ 2 files changed, 116 insertions(+), 57 deletions(-) diff --git a/cryptfs.c b/cryptfs.c index ac250e5..8bed8cb 100644 --- a/cryptfs.c +++ b/cryptfs.c @@ -1429,6 +1429,40 @@ static int prep_data_fs(void) } } +static void cryptfs_set_corrupt() +{ + // Mark the footer as bad + struct crypt_mnt_ftr crypt_ftr; + if (get_crypt_ftr_and_key(&crypt_ftr)) { + SLOGE("Failed to get crypto footer - panic"); + return; + } + + crypt_ftr.flags |= CRYPT_DATA_CORRUPT; + if (put_crypt_ftr_and_key(&crypt_ftr)) { + SLOGE("Failed to set crypto footer - panic"); + return; + } +} + +static void cryptfs_trigger_restart_min_framework() +{ + if (fs_mgr_do_tmpfs_mount(DATA_MNT_POINT)) { + SLOGE("Failed to mount tmpfs on data - panic"); + return; + } + + if (property_set("vold.decrypt", "trigger_post_fs_data")) { + SLOGE("Failed to trigger post fs data - panic"); + return; + } + + if (property_set("vold.decrypt", "trigger_restart_min_framework")) { + SLOGE("Failed to trigger restart min framework - panic"); + return; + } +} + static int cryptfs_restart_internal(int restart_main) { char fs_type[32]; @@ -1503,7 +1537,13 @@ static int cryptfs_restart_internal(int restart_main) } /* If that succeeded, then mount the decrypted filesystem */ - fs_mgr_do_mount(fstab, DATA_MNT_POINT, crypto_blkdev, 0); + if (fs_mgr_do_mount(fstab, DATA_MNT_POINT, crypto_blkdev, 0)) { + SLOGE("Failed to mount decrypted data"); + cryptfs_set_corrupt(); + cryptfs_trigger_restart_min_framework(); + SLOGI("Started framework to offer wipe"); + return -1; + } property_set("vold.decrypt", "trigger_load_persist_props"); /* Create necessary paths on /data */ @@ -1541,7 +1581,7 @@ static int do_crypto_complete(char *mount_point UNUSED) property_get("ro.crypto.state", encrypted_state, ""); if (strcmp(encrypted_state, "encrypted") ) { SLOGE("not running with encryption, aborting"); - return 1; + return CRYPTO_COMPLETE_NOT_ENCRYPTED; } if (get_crypt_ftr_and_key(&crypt_ftr)) { @@ -1556,22 +1596,31 @@ static int do_crypto_complete(char *mount_point UNUSED) */ if ((key_loc[0] == '/') && (access("key_loc", F_OK) == -1)) { SLOGE("master key file does not exist, aborting"); - return 1; + return CRYPTO_COMPLETE_NOT_ENCRYPTED; } else { SLOGE("Error getting crypt footer and key\n"); - return -1; + return CRYPTO_COMPLETE_BAD_METADATA; } } - if (crypt_ftr.flags - & (CRYPT_ENCRYPTION_IN_PROGRESS | CRYPT_INCONSISTENT_STATE)) { - SLOGE("Encryption process didn't finish successfully\n"); - return -2; /* -2 is the clue to the UI that there is no usable data on the disk, - * and give the user an option to wipe the disk */ + // Test for possible error flags + if (crypt_ftr.flags & CRYPT_ENCRYPTION_IN_PROGRESS){ + SLOGE("Encryption process is partway completed\n"); + return CRYPTO_COMPLETE_PARTIAL; + } + + if (crypt_ftr.flags & CRYPT_INCONSISTENT_STATE){ + SLOGE("Encryption process was interrupted but cannot continue\n"); + return CRYPTO_COMPLETE_INCONSISTENT; + } + + if (crypt_ftr.flags & CRYPT_DATA_CORRUPT){ + SLOGE("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 0; + return CRYPTO_COMPLETE_ENCRYPTED; } static int test_mount_encrypted_fs(struct crypt_mnt_ftr* crypt_ftr, @@ -1605,72 +1654,68 @@ 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, real_blkdev, crypto_blkdev, label)) { - SLOGE("Error creating decrypted block device\n"); - rc = -1; - goto errout; + SLOGE("Error creating decrypted block device\n"); + rc = -1; + goto errout; } - /* If init detects an encrypted filesystem, it writes a file for each such - * encrypted fs into the tmpfs /data filesystem, and then the framework finds those - * files and passes that data to me */ - /* Create a tmp mount point to try mounting the decryptd fs - * Since we're here, the mount_point should be a tmpfs filesystem, so make - * a directory in it to test mount the decrypted filesystem. - */ - 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)) { - SLOGE("Error temp mounting decrypted block device\n"); - delete_crypto_blk_dev(label); + /* Work out if the problem is the password or the data */ + unsigned char scrypted_intermediate_key[sizeof(crypt_ftr-> + scrypted_intermediate_key)]; + int N = 1 << crypt_ftr->N_factor; + int r = 1 << crypt_ftr->r_factor; + int p = 1 << crypt_ftr->p_factor; - /* Work out if the problem is the password or the data */ - unsigned char scrypted_intermediate_key[sizeof(crypt_ftr-> - scrypted_intermediate_key)]; - int N = 1 << crypt_ftr->N_factor; - int r = 1 << crypt_ftr->r_factor; - int p = 1 << crypt_ftr->p_factor; + rc = crypto_scrypt(intermediate_key, intermediate_key_size, + crypt_ftr->salt, sizeof(crypt_ftr->salt), + N, r, p, scrypted_intermediate_key, + sizeof(scrypted_intermediate_key)); + + // Does the key match the crypto footer? + if (rc == 0 && memcmp(scrypted_intermediate_key, + crypt_ftr->scrypted_intermediate_key, + sizeof(scrypted_intermediate_key)) == 0) { + SLOGI("Password matches"); + rc = 0; + } else { + /* Try mounting the file system anyway, just in case the problem's with + * 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)) { + SLOGE("Error temp mounting decrypted block device\n"); + delete_crypto_blk_dev(label); - rc = crypto_scrypt(intermediate_key, intermediate_key_size, - crypt_ftr->salt, sizeof(crypt_ftr->salt), - N, r, p, scrypted_intermediate_key, - sizeof(scrypted_intermediate_key)); - if (rc == 0 && memcmp(scrypted_intermediate_key, - crypt_ftr->scrypted_intermediate_key, - sizeof(scrypted_intermediate_key)) == 0) { - SLOGE("Right password, so wipe"); - rc = -1; - } else { - SLOGE(rc ? "scrypt failure, so allow retry" : - "Wrong password, so allow retry"); rc = ++crypt_ftr->failed_decrypt_count; put_crypt_ftr_and_key(crypt_ftr); + } else { + /* Success! */ + SLOGI("Password did not match but decrypted drive mounted - continue"); + umount(tmp_mount_point); + rc = 0; } - } else { - /* Success! - * umount and we'll mount it properly when we restart the framework. - */ - umount(tmp_mount_point); - crypt_ftr->failed_decrypt_count = 0; + } + + if (rc == 0) { + crypt_ftr->failed_decrypt_count = 0; /* Save the name of the crypto block device - * so we can mount it when restarting the framework. - */ + * so we can mount it when restarting the framework. */ property_set("ro.crypto.fs_crypto_blkdev", crypto_blkdev); /* Also save a the master key so we can reencrypted the key - * the key when we want to change the password on it. - */ + * the key when we want to change the password on it. */ memcpy(saved_master_key, decrypted_master_key, KEY_LEN_BYTES); saved_mount_point = strdup(mount_point); master_key_saved = 1; SLOGD("%s(): Master key saved\n", __FUNCTION__); rc = 0; - /* - * Upgrade if we're not using the latest KDF. - */ + // Upgrade if we're not using the latest KDF. use_keymaster = keymaster_check_compatibility(); if (crypt_ftr->kdf_type == KDF_SCRYPT_KEYMASTER) { // Don't allow downgrade to KDF_SCRYPT @@ -2139,7 +2184,7 @@ static int cryptfs_enable_inplace_ext4(char *crypto_blkdev, { u32 i; struct encryptGroupsData data; - int rc = -1; + int rc; // Can't initialize without causing warning -Wclobbered if (previously_encrypted_upto > *size_already_done) { SLOGD("Not fast encrypting since resuming part way through"); @@ -2153,22 +2198,26 @@ static int cryptfs_enable_inplace_ext4(char *crypto_blkdev, if ( (data.realfd = open(real_blkdev, O_RDWR)) < 0) { SLOGE("Error opening real_blkdev %s for inplace encrypt\n", real_blkdev); + rc = -1; goto errout; } if ( (data.cryptofd = open(crypto_blkdev, O_WRONLY)) < 0) { SLOGE("Error opening crypto_blkdev %s for inplace encrypt\n", crypto_blkdev); + rc = -1; goto errout; } if (setjmp(setjmp_env)) { SLOGE("Reading extent caused an exception"); + rc = -1; goto errout; } if (read_ext(data.realfd, 0) != 0) { SLOGE("Failed to read extent"); + rc = -1; goto errout; } diff --git a/cryptfs.h b/cryptfs.h index 0b4cda6..1cce21e 100644 --- a/cryptfs.h +++ b/cryptfs.h @@ -50,6 +50,8 @@ #define CRYPT_INCONSISTENT_STATE 0x4 /* Set when starting encryption, clear when exit cleanly, either through success or correctly marked partial encryption */ +#define CRYPT_DATA_CORRUPT 0x8 /* Set when encryption is fine, but the + underlying volume is corrupt */ /* Allowed values for type in the structure below */ #define CRYPT_TYPE_PASSWORD 0 /* master_key is encrypted with a password @@ -182,6 +184,14 @@ struct volume_info { #define DATA_MNT_POINT "/data" +/* Return values for cryptfs_crypto_complete */ +#define CRYPTO_COMPLETE_NOT_ENCRYPTED 1 +#define CRYPTO_COMPLETE_ENCRYPTED 0 +#define CRYPTO_COMPLETE_BAD_METADATA -1 +#define CRYPTO_COMPLETE_PARTIAL -2 +#define CRYPTO_COMPLETE_INCONSISTENT -3 +#define CRYPTO_COMPLETE_CORRUPT -4 + #ifdef __cplusplus extern "C" { #endif