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
This commit is contained in:
Paul Lawrence 2014-08-28 15:54:10 -07:00
parent 00786076cd
commit 74f29f1df7
2 changed files with 116 additions and 57 deletions

163
cryptfs.c
View file

@ -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;
}

View file

@ -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