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:
parent
00786076cd
commit
74f29f1df7
2 changed files with 116 additions and 57 deletions
163
cryptfs.c
163
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;
|
||||
}
|
||||
|
||||
|
|
10
cryptfs.h
10
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
|
||||
|
|
Loading…
Reference in a new issue