Merge "Don't try to encrypt in place a filesystem that is too large and return proper errors" into honeycomb
This commit is contained in:
commit
3f476690ea
2 changed files with 87 additions and 16 deletions
|
@ -26,6 +26,7 @@ common_src_files := \
|
||||||
|
|
||||||
common_c_includes := \
|
common_c_includes := \
|
||||||
$(KERNEL_HEADERS) \
|
$(KERNEL_HEADERS) \
|
||||||
|
system/extras/ext4_utils \
|
||||||
external/openssl/include
|
external/openssl/include
|
||||||
|
|
||||||
common_shared_libraries := \
|
common_shared_libraries := \
|
||||||
|
|
102
cryptfs.c
102
cryptfs.c
|
@ -36,6 +36,7 @@
|
||||||
#include <openssl/sha.h>
|
#include <openssl/sha.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <sys/reboot.h>
|
#include <sys/reboot.h>
|
||||||
|
#include <ext4.h>
|
||||||
#include "cryptfs.h"
|
#include "cryptfs.h"
|
||||||
#define LOG_TAG "Cryptfs"
|
#define LOG_TAG "Cryptfs"
|
||||||
#include "cutils/log.h"
|
#include "cutils/log.h"
|
||||||
|
@ -67,6 +68,37 @@ static void ioctl_init(struct dm_ioctl *io, size_t dataSize, const char *name, u
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
SLOGE("Cannot open device to get filesystem size ");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lseek64(fd, 1024, SEEK_SET) < 0) {
|
||||||
|
SLOGE("Cannot seek to superblock");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (read(fd, &sb, sizeof(sb)) != sizeof(sb)) {
|
||||||
|
SLOGE("Cannot read superblock");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
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)
|
static unsigned int get_blkdev_size(int fd)
|
||||||
{
|
{
|
||||||
unsigned int nr_sec;
|
unsigned int nr_sec;
|
||||||
|
@ -869,7 +901,7 @@ int cryptfs_enable(char *howarg, char *passwd)
|
||||||
property_get("ro.crypto.state", encrypted_state, "");
|
property_get("ro.crypto.state", encrypted_state, "");
|
||||||
if (strcmp(encrypted_state, "unencrypted")) {
|
if (strcmp(encrypted_state, "unencrypted")) {
|
||||||
SLOGE("Device is already running encrypted, aborting");
|
SLOGE("Device is already running encrypted, aborting");
|
||||||
return -1;
|
goto error_unencrypted;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!strcmp(howarg, "wipe")) {
|
if (!strcmp(howarg, "wipe")) {
|
||||||
|
@ -878,11 +910,32 @@ int cryptfs_enable(char *howarg, char *passwd)
|
||||||
how = CRYPTO_ENABLE_INPLACE;
|
how = CRYPTO_ENABLE_INPLACE;
|
||||||
} else {
|
} else {
|
||||||
/* Shouldn't happen, as CommandListener vets the args */
|
/* Shouldn't happen, as CommandListener vets the args */
|
||||||
return -1;
|
goto error_unencrypted;
|
||||||
}
|
}
|
||||||
|
|
||||||
get_orig_mount_parms(mount_point, fs_type, real_blkdev, &mnt_flags, fs_options);
|
get_orig_mount_parms(mount_point, fs_type, real_blkdev, &mnt_flags, fs_options);
|
||||||
|
|
||||||
|
/* Get the size of the real block device */
|
||||||
|
fd = open(real_blkdev, O_RDONLY);
|
||||||
|
if ( (nr_sec = get_blkdev_size(fd)) == 0) {
|
||||||
|
SLOGE("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) {
|
||||||
|
unsigned int fs_size_sec, max_fs_size_sec;
|
||||||
|
|
||||||
|
fs_size_sec = get_fs_size(real_blkdev);
|
||||||
|
max_fs_size_sec = nr_sec - (CRYPT_FOOTER_OFFSET / 512);
|
||||||
|
|
||||||
|
if (fs_size_sec > max_fs_size_sec) {
|
||||||
|
SLOGE("Orig filesystem overlaps crypto footer region. Cannot encrypt in place.");
|
||||||
|
goto error_unencrypted;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* The init files are setup to stop the class main and late start when
|
/* The init files are setup to stop the class main and late start when
|
||||||
* vold sets trigger_shutdown_framework.
|
* vold sets trigger_shutdown_framework.
|
||||||
*/
|
*/
|
||||||
|
@ -890,12 +943,12 @@ int cryptfs_enable(char *howarg, char *passwd)
|
||||||
SLOGD("Just asked init to shut down class main\n");
|
SLOGD("Just asked init to shut down class main\n");
|
||||||
|
|
||||||
if (wait_and_unmount("/mnt/sdcard")) {
|
if (wait_and_unmount("/mnt/sdcard")) {
|
||||||
return -1;
|
goto error_shutting_down;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Now unmount the /data partition. */
|
/* Now unmount the /data partition. */
|
||||||
if (wait_and_unmount(DATA_MNT_POINT)) {
|
if (wait_and_unmount(DATA_MNT_POINT)) {
|
||||||
return -1;
|
goto error_shutting_down;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Do extra work for a better UX when doing the long inplace encryption */
|
/* Do extra work for a better UX when doing the long inplace encryption */
|
||||||
|
@ -907,7 +960,7 @@ int cryptfs_enable(char *howarg, char *passwd)
|
||||||
property_get("ro.crypto.tmpfs_options", tmpfs_options, "");
|
property_get("ro.crypto.tmpfs_options", tmpfs_options, "");
|
||||||
if (mount("tmpfs", DATA_MNT_POINT, "tmpfs", MS_NOATIME | MS_NOSUID | MS_NODEV,
|
if (mount("tmpfs", DATA_MNT_POINT, "tmpfs", MS_NOATIME | MS_NOSUID | MS_NODEV,
|
||||||
tmpfs_options) < 0) {
|
tmpfs_options) < 0) {
|
||||||
return -1;
|
goto error_shutting_down;
|
||||||
}
|
}
|
||||||
/* Tells the framework that inplace encryption is starting */
|
/* Tells the framework that inplace encryption is starting */
|
||||||
property_set("vold.encrypt_progress", "0");
|
property_set("vold.encrypt_progress", "0");
|
||||||
|
@ -915,7 +968,7 @@ int cryptfs_enable(char *howarg, char *passwd)
|
||||||
/* restart the framework. */
|
/* restart the framework. */
|
||||||
/* Create necessary paths on /data */
|
/* Create necessary paths on /data */
|
||||||
if (prep_data_fs()) {
|
if (prep_data_fs()) {
|
||||||
return -1;
|
goto error_shutting_down;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* startup service classes main and late_start */
|
/* startup service classes main and late_start */
|
||||||
|
@ -930,13 +983,6 @@ int cryptfs_enable(char *howarg, char *passwd)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Start the actual work of making an encrypted filesystem */
|
/* Start the actual work of making an encrypted filesystem */
|
||||||
fd = open(real_blkdev, O_RDONLY);
|
|
||||||
if ( (nr_sec = get_blkdev_size(fd)) == 0) {
|
|
||||||
SLOGE("Cannot get size of block device %s\n", real_blkdev);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
close(fd);
|
|
||||||
|
|
||||||
/* Initialize a crypt_mnt_ftr for the partition */
|
/* Initialize a crypt_mnt_ftr for the partition */
|
||||||
cryptfs_init_crypt_mnt_ftr(&crypt_ftr);
|
cryptfs_init_crypt_mnt_ftr(&crypt_ftr);
|
||||||
crypt_ftr.fs_size = nr_sec - (CRYPT_FOOTER_OFFSET / 512);
|
crypt_ftr.fs_size = nr_sec - (CRYPT_FOOTER_OFFSET / 512);
|
||||||
|
@ -945,7 +991,7 @@ int cryptfs_enable(char *howarg, char *passwd)
|
||||||
/* Make an encrypted master key */
|
/* Make an encrypted master key */
|
||||||
if (create_encrypted_random_key(passwd, master_key, salt)) {
|
if (create_encrypted_random_key(passwd, master_key, salt)) {
|
||||||
SLOGE("Cannot create encrypted master key\n");
|
SLOGE("Cannot create encrypted master key\n");
|
||||||
return -1;
|
goto error_unencrypted;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Write the key to the end of the partition */
|
/* Write the key to the end of the partition */
|
||||||
|
@ -961,7 +1007,7 @@ int cryptfs_enable(char *howarg, char *passwd)
|
||||||
} else {
|
} else {
|
||||||
/* Shouldn't happen */
|
/* Shouldn't happen */
|
||||||
SLOGE("cryptfs_enable: internal error, unknown option\n");
|
SLOGE("cryptfs_enable: internal error, unknown option\n");
|
||||||
return -1;
|
goto error_unencrypted;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Undo the dm-crypt mapping whether we succeed or not */
|
/* Undo the dm-crypt mapping whether we succeed or not */
|
||||||
|
@ -972,10 +1018,34 @@ int cryptfs_enable(char *howarg, char *passwd)
|
||||||
sleep(2); /* Give the UI a change to show 100% progress */
|
sleep(2); /* Give the UI a change to show 100% progress */
|
||||||
sync();
|
sync();
|
||||||
reboot(LINUX_REBOOT_CMD_RESTART);
|
reboot(LINUX_REBOOT_CMD_RESTART);
|
||||||
|
} else {
|
||||||
|
property_set("vold.encrypt_progress", "error_partially_encrypted");
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Only returns on error */
|
/* 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");
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
|
error_unencrypted:
|
||||||
|
property_set("vold.encrypt_progress", "error_not_encrypted");
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
SLOGE("Error enabling encryption after framework is shutdown, no data changed, restarting system");
|
||||||
|
sync();
|
||||||
|
reboot(LINUX_REBOOT_CMD_RESTART);
|
||||||
|
|
||||||
|
/* shouldn't get here */
|
||||||
|
property_set("vold.encrypt_progress", "error_shutting_down");
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cryptfs_changepw(char *newpw)
|
int cryptfs_changepw(char *newpw)
|
||||||
|
|
Loading…
Reference in a new issue