Don't corrupt ssd when encrypting and power fails

Stop encryption when battery is low, mark position, and continue on reboot.

Note - support for multiple encrypted volumes removed as no devices seem
to exist with an fstab that uses this feature. If you want support for such
a device, contact me and we will re-add it with appropriate testing.

Bug: 13284213
Change-Id: I1f7178e4f7dd8ea816cbc03ab5c4f6543e98acaa
This commit is contained in:
Paul Lawrence 2014-02-20 12:21:31 -08:00 committed by JP Abgrall
parent f8e9569507
commit 87999173dd
5 changed files with 389 additions and 134 deletions

View file

@ -14,6 +14,7 @@ common_src_files := \
Loop.cpp \
Devmapper.cpp \
ResponseCode.cpp \
CheckBattery.cpp \
VoldUtil.c \
fstrim.c \
cryptfs.c
@ -23,11 +24,13 @@ common_c_includes := \
external/openssl/include \
external/stlport/stlport \
bionic \
external/scrypt/lib/crypto
external/scrypt/lib/crypto \
frameworks/native/include
common_shared_libraries := \
libsysutils \
libstlport \
libbinder \
libcutils \
liblog \
libdiskconfig \
@ -35,12 +38,14 @@ common_shared_libraries := \
liblogwrap \
libext4_utils \
libcrypto \
libselinux
libselinux \
libutils
common_static_libraries := \
libfs_mgr \
libscrypt_static \
libmincrypt
libmincrypt \
libbatteryservice
include $(CLEAR_VARS)

75
CheckBattery.cpp Normal file
View file

@ -0,0 +1,75 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define LOG_TAG "VoldCheckBattery"
#include <cutils/log.h>
#include <binder/IServiceManager.h>
#include <batteryservice/IBatteryPropertiesRegistrar.h>
using namespace android;
namespace
{
// How often to check battery in seconds
const int CHECK_PERIOD = 30;
const String16 serviceName("batteryproperties");
sp<IBinder> bs;
sp<IBatteryPropertiesRegistrar> interface;
bool singletonInitialized = false;
time_t last_checked = {0};
int battery_ok = 1;
}
extern "C" int is_battery_ok()
{
time_t now = time(NULL);
if (now == -1 || difftime(now, last_checked) < 5) {
return battery_ok;
}
last_checked = now;
if (!singletonInitialized) {
bs = defaultServiceManager()->checkService(serviceName);
if (bs == NULL) {
SLOGE("No batteryproperties service!");
return 1;
}
interface = interface_cast<IBatteryPropertiesRegistrar>(bs);
if (interface == NULL) {
SLOGE("No IBatteryPropertiesRegistrar interface");
return 1;
}
singletonInitialized = true;
}
BatteryProperty val;
status_t status = interface->getProperty(android::BATTERY_PROP_CAPACITY,
&val);
if (status == NO_ERROR) {
SLOGD("Capacity is %d", val.valueInt);
battery_ok = val.valueInt > 5 ? 1 : 0;
} else {
SLOGE("Failed to get battery charge");
battery_ok = 1;
}
return battery_ok;
}

30
CheckBattery.h Normal file
View file

@ -0,0 +1,30 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _CHECKBATTERY_H__
#define _CHECKBATTERY_H__
#ifdef __cplusplus
extern "C" {
#endif
int is_battery_ok();
#ifdef __cplusplus
}
#endif
#endif

394
cryptfs.c
View file

@ -35,7 +35,6 @@
#include <string.h>
#include <sys/mount.h>
#include <openssl/evp.h>
#include <openssl/sha.h>
#include <errno.h>
#include <ext4.h>
#include <linux/kdev_t.h>
@ -51,6 +50,7 @@
#include "VoldUtil.h"
#include "crypto_scrypt.h"
#include "ext4_utils.h"
#include "CheckBattery.h"
#define UNUSED __attribute__((unused))
@ -87,13 +87,23 @@ static int just_decrypted = 0;
extern struct fstab *fstab;
static void cryptfs_reboot(int recovery)
enum RebootType {reboot, recovery, shutdown};
static void cryptfs_reboot(enum RebootType rt)
{
if (recovery) {
property_set(ANDROID_RB_PROPERTY, "reboot,recovery");
} else {
property_set(ANDROID_RB_PROPERTY, "reboot");
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 */
@ -1615,7 +1625,8 @@ static int cryptfs_enable_wipe(char *crypto_blkdev, off64_t size, int type)
}
#define CRYPT_INPLACE_BUFSIZE 4096
#define CRYPT_SECTORS_PER_BUFSIZE (CRYPT_INPLACE_BUFSIZE / 512)
#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.
@ -1633,6 +1644,8 @@ struct encryptGroupsData
int count;
off64_t offset;
char* buffer;
off64_t last_written_sector;
int completed;
};
static void update_progress(struct encryptGroupsData* data)
@ -1669,9 +1682,14 @@ static int flush_outstanding_data(struct encryptGroupsData* data)
SLOGE("Error writing crypto_blkdev %s for inplace encrypt",
data->crypto_blkdev);
return -1;
} else {
SLOGI("Encrypted %d blocks at sector %lld",
data->count, data->offset / info.block_size * CRYPT_SECTOR_SIZE);
}
data->count = 0;
data->last_written_sector = (data->offset + data->count)
/ info.block_size * CRYPT_SECTOR_SIZE - 1;
return 0;
}
@ -1737,12 +1755,20 @@ static int encrypt_groups(struct encryptGroupsData* data)
goto errout;
}
}
if (!is_battery_ok()) {
SLOGE("Stopping encryption due to low battery");
rc = 0;
goto errout;
}
}
if (flush_outstanding_data(data)) {
goto errout;
}
}
data->completed = 1;
rc = 0;
errout:
@ -1755,12 +1781,18 @@ 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 tot_size,
off64_t previously_encrypted_upto)
{
int i;
struct encryptGroupsData data;
int rc = -1;
if (previously_encrypted_upto > *size_already_done) {
SLOGD("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;
@ -1802,7 +1834,7 @@ static int cryptfs_enable_inplace_ext4(char *crypto_blkdev,
goto errout;
}
*size_already_done += size;
*size_already_done += data.completed ? size : data.last_written_sector;
rc = 0;
errout:
@ -1814,7 +1846,8 @@ errout:
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 tot_size,
off64_t previously_encrypted_upto)
{
int realfd, cryptofd;
char *buf[CRYPT_INPLACE_BUFSIZE];
@ -1846,10 +1879,37 @@ static int cryptfs_enable_inplace_full(char *crypto_blkdev, char *real_blkdev,
SLOGE("Encrypting filesystem in place...");
i = previously_encrypted_upto + 1 - *size_already_done;
if (lseek64(realfd, i * CRYPT_SECTOR_SIZE, SEEK_SET) < 0) {
SLOGE("Cannot seek to previously encrypted point on %s", real_blkdev);
goto errout;
}
if (lseek64(cryptofd, i * CRYPT_SECTOR_SIZE, SEEK_SET) < 0) {
SLOGE("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) {
SLOGE("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) {
SLOGE("Error writing initial sectors to crypto_blkdev %s for "
"inplace encrypt\n", crypto_blkdev);
goto errout;
} else {
SLOGI("Encrypted 1 block at %lld", i);
}
}
one_pct = tot_numblocks / 100;
cur_pct = 0;
/* process the majority of the filesystem in blocks */
for (i=0; i<numblocks; i++) {
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];
@ -1859,24 +1919,37 @@ static int cryptfs_enable_inplace_full(char *crypto_blkdev, char *real_blkdev,
property_set("vold.encrypt_progress", buf);
}
if (unix_read(realfd, buf, CRYPT_INPLACE_BUFSIZE) <= 0) {
SLOGE("Error reading real_blkdev %s for inplace encrypt\n", crypto_blkdev);
SLOGE("Error reading real_blkdev %s for inplace encrypt", crypto_blkdev);
goto errout;
}
if (unix_write(cryptofd, buf, CRYPT_INPLACE_BUFSIZE) <= 0) {
SLOGE("Error writing crypto_blkdev %s for inplace encrypt\n", crypto_blkdev);
SLOGE("Error writing crypto_blkdev %s for inplace encrypt", crypto_blkdev);
goto errout;
} else {
SLOGD("Encrypted %d block at %lld",
CRYPT_SECTORS_PER_BUFSIZE,
i * CRYPT_SECTORS_PER_BUFSIZE);
}
if (!is_battery_ok()) {
SLOGE("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, 512) <= 0) {
SLOGE("Error reading rival sectors from real_blkdev %s for inplace encrypt\n", crypto_blkdev);
if (unix_read(realfd, buf, CRYPT_SECTOR_SIZE) <= 0) {
SLOGE("Error reading final sectors from real_blkdev %s for inplace encrypt", crypto_blkdev);
goto errout;
}
if (unix_write(cryptofd, buf, 512) <= 0) {
SLOGE("Error writing final sectors to crypto_blkdev %s for inplace encrypt\n", crypto_blkdev);
if (unix_write(cryptofd, buf, CRYPT_SECTOR_SIZE) <= 0) {
SLOGE("Error writing final sectors to crypto_blkdev %s for inplace encrypt", crypto_blkdev);
goto errout;
} else {
SLOGI("Encrypted 1 block at next location");
}
}
@ -1892,15 +1965,27 @@ errout:
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 tot_size,
off64_t previously_encrypted_upto)
{
if (previously_encrypted_upto) {
SLOGD("Continuing encryption from %lld", previously_encrypted_upto);
}
if (*size_already_done + size < previously_encrypted_upto) {
*size_already_done += size;
return 0;
}
if (cryptfs_enable_inplace_ext4(crypto_blkdev, real_blkdev,
size, size_already_done, tot_size) == 0) {
size, size_already_done,
tot_size, previously_encrypted_upto) == 0) {
return 0;
}
return cryptfs_enable_inplace_full(crypto_blkdev, real_blkdev,
size, size_already_done, tot_size);
size, size_already_done, tot_size,
previously_encrypted_upto);
}
#define CRYPTO_ENABLE_WIPE 1
@ -1914,34 +1999,91 @@ static inline int should_encrypt(struct volume_info *volume)
(VOL_ENCRYPTABLE | VOL_NONREMOVABLE);
}
static int cryptfs_SHA256_fileblock(const char* filename, __le8* buf)
{
int fd = open(filename, O_RDONLY);
if (fd == -1) {
SLOGE("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) {
SLOGE("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 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 (!is_battery_ok()) {
SLOGE("Stopping 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) {
rc = cryptfs_enable_wipe(crypto_blkdev, crypt_ftr->fs_size, EXT4_FS);
} 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 && cur_encryption_done != (off64_t)crypt_ftr->fs_size) {
crypt_ftr->encrypted_upto = cur_encryption_done;
}
if (!rc && !crypt_ftr->encrypted_upto) {
/* 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 */
SLOGE("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], sd_crypto_blkdev[MAXPATHLEN];
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, sd_crypt_ftr;;
struct crypt_mnt_ftr crypt_ftr;
struct crypt_persist_data *pdata;
char tmpfs_options[PROPERTY_VALUE_MAX];
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;
char sd_blk_dev[256] = { 0 };
int num_vols;
struct volume_info *vol_list = 0;
off64_t cur_encryption_done=0, tot_encryption_size=0;
property_get("ro.crypto.state", encrypted_state, "");
if (!strcmp(encrypted_state, "encrypted")) {
SLOGE("Device is already running encrypted, aborting");
goto error_unencrypted;
}
fs_mgr_get_crypt_info(fstab, key_loc, 0, sizeof(key_loc));
off64_t previously_encrypted_upto = 0;
if (!strcmp(howarg, "wipe")) {
how = CRYPTO_ENABLE_WIPE;
@ -1952,6 +2094,22 @@ int cryptfs_enable_internal(char *howarg, int crypt_type, char *passwd,
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;
}
property_get("ro.crypto.state", encrypted_state, "");
if (!strcmp(encrypted_state, "encrypted") && !previously_encrypted_upto) {
SLOGE("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 */
@ -1967,7 +2125,7 @@ int cryptfs_enable_internal(char *howarg, int crypt_type, char *passwd,
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);
max_fs_size_sec = nr_sec - (CRYPT_FOOTER_OFFSET / CRYPT_SECTOR_SIZE);
if (fs_size_sec > max_fs_size_sec) {
SLOGE("Orig filesystem overlaps crypto footer region. Cannot encrypt in place.");
@ -1991,26 +2149,19 @@ int cryptfs_enable_internal(char *howarg, int crypt_type, char *passwd,
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=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])) {
fd = open(vol_list[i].blk_dev, O_RDONLY);
if ( (vol_list[i].size = get_blkdev_size(fd)) == 0) {
SLOGE("Cannot get size of block device %s\n", vol_list[i].blk_dev);
goto error_unencrypted;
}
close(fd);
ret=vold_disableVol(vol_list[i].label);
if ((ret < 0) && (ret != UNMOUNT_NOT_MOUNTED_ERR)) {
/* -2 is returned when the device exists but is not currently mounted.
* ignore the error and continue. */
SLOGE("Failed to unmount volume %s\n", vol_list[i].label);
goto error_unencrypted;
}
SLOGE("Cannot encrypt if there are multiple encryptable volumes"
"%s\n", vol_list[i].label);
goto error_unencrypted;
}
}
@ -2087,102 +2238,78 @@ int cryptfs_enable_internal(char *howarg, int crypt_type, char *passwd,
/* Start the actual work of making an encrypted filesystem */
/* Initialize a crypt_mnt_ftr for the partition */
cryptfs_init_crypt_mnt_ftr(&crypt_ftr);
if (previously_encrypted_upto == 0) {
cryptfs_init_crypt_mnt_ftr(&crypt_ftr);
if (!strcmp(key_loc, KEY_IN_FOOTER)) {
crypt_ftr.fs_size = nr_sec - (CRYPT_FOOTER_OFFSET / 512);
} else {
crypt_ftr.fs_size = nr_sec;
}
crypt_ftr.flags |= CRYPT_ENCRYPTION_IN_PROGRESS;
crypt_ftr.crypt_type = crypt_type;
strcpy((char *)crypt_ftr.crypto_type_name, "aes-cbc-essiv:sha256");
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;
}
crypt_ftr.flags |= CRYPT_ENCRYPTION_IN_PROGRESS;
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)) {
SLOGE("Cannot create encrypted master key\n");
goto error_shutting_down;
}
/* Make an encrypted master key */
if (create_encrypted_random_key(passwd, crypt_ftr.master_key, crypt_ftr.salt, &crypt_ftr)) {
SLOGE("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);
/* 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();
/* 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);
create_crypto_blk_dev(&crypt_ftr, decrypted_master_key, real_blkdev, crypto_blkdev,
"userdata");
/* The size of the userdata partition, and add in the vold volumes below */
tot_encryption_size = crypt_ftr.fs_size;
/* 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);
/* setup crypto mapping for all encryptable volumes handled by vold */
for (i=0; i<num_vols; i++) {
if (should_encrypt(&vol_list[i])) {
vol_list[i].crypt_ftr = crypt_ftr; /* gotta love struct assign */
vol_list[i].crypt_ftr.fs_size = vol_list[i].size;
create_crypto_blk_dev(&vol_list[i].crypt_ftr, decrypted_master_key,
vol_list[i].blk_dev, vol_list[i].crypto_blkdev,
vol_list[i].label);
tot_encryption_size += vol_list[i].size;
if (!rc && memcmp(hash_first_block, crypt_ftr.hash_first_block,
sizeof(hash_first_block)) != 0) {
SLOGE("Checksums do not match - trigger wipe");
rc = -1;
}
}
if (how == CRYPTO_ENABLE_WIPE) {
rc = cryptfs_enable_wipe(crypto_blkdev, crypt_ftr.fs_size, EXT4_FS);
/* Encrypt all encryptable volumes handled by vold */
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) {
rc = cryptfs_SHA256_fileblock(crypto_blkdev,
crypt_ftr.hash_first_block);
if (!rc) {
for (i=0; i<num_vols; i++) {
if (should_encrypt(&vol_list[i])) {
rc = cryptfs_enable_wipe(vol_list[i].crypto_blkdev,
vol_list[i].crypt_ftr.fs_size, FAT_FS);
}
}
SLOGE("Error calculating checksum for continuing encryption");
rc = -1;
}
} else if (how == CRYPTO_ENABLE_INPLACE) {
rc = cryptfs_enable_inplace(crypto_blkdev, real_blkdev, crypt_ftr.fs_size,
&cur_encryption_done, tot_encryption_size);
/* Encrypt all encryptable volumes handled by vold */
if (!rc) {
for (i=0; i<num_vols; i++) {
if (should_encrypt(&vol_list[i])) {
rc = cryptfs_enable_inplace(vol_list[i].crypto_blkdev,
vol_list[i].blk_dev,
vol_list[i].crypt_ftr.fs_size,
&cur_encryption_done, tot_encryption_size);
}
}
}
if (!rc) {
/* 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 */
SLOGE("cryptfs_enable: internal error, unknown option\n");
goto error_shutting_down;
}
/* Undo the dm-crypt mapping whether we succeed or not */
delete_crypto_blk_dev("userdata");
for (i=0; i<num_vols; i++) {
if (should_encrypt(&vol_list[i])) {
delete_crypto_blk_dev(vol_list[i].label);
}
}
free(vol_list);
@ -2190,11 +2317,22 @@ int cryptfs_enable_internal(char *howarg, int crypt_type, char *passwd,
/* Success */
/* Clear the encryption in progres flag in the footer */
crypt_ftr.flags &= ~CRYPT_ENCRYPTION_IN_PROGRESS;
if (!crypt_ftr.encrypted_upto) {
crypt_ftr.flags &= ~CRYPT_ENCRYPTION_IN_PROGRESS;
} else {
SLOGD("Encrypted up to sector %lld - will continue after reboot",
crypt_ftr.encrypted_upto);
}
put_crypt_ftr_and_key(&crypt_ftr);
sleep(2); /* Give the UI a chance to show 100% progress */
cryptfs_reboot(0);
/* Partially encrypted - ensure writes are flushed to ssd */
if (!crypt_ftr.encrypted_upto) {
cryptfs_reboot(reboot);
} else {
cryptfs_reboot(shutdown);
}
} else {
char value[PROPERTY_VALUE_MAX];
@ -2210,7 +2348,7 @@ int cryptfs_enable_internal(char *howarg, int crypt_type, char *passwd,
} else {
SLOGE("could not open /cache/recovery/command\n");
}
cryptfs_reboot(1);
cryptfs_reboot(recovery);
} else {
/* set property to trigger dialog */
property_set("vold.encrypt_progress", "error_partially_encrypted");
@ -2241,7 +2379,7 @@ error_shutting_down:
* vold to restart the system.
*/
SLOGE("Error enabling encryption after framework is shutdown, no data changed, restarting system");
cryptfs_reboot(0);
cryptfs_reboot(reboot);
/* shouldn't get here */
property_set("vold.encrypt_progress", "error_shutting_down");

View file

@ -27,6 +27,7 @@
*/
#include <cutils/properties.h>
#include <openssl/sha.h>
/* The current cryptfs version */
#define CURRENT_MAJOR_VERSION 1
@ -80,10 +81,10 @@ struct crypt_mnt_ftr {
* CRYPT_TYPE_XXX value */
__le64 fs_size; /* Size of the encrypted fs, in 512 byte sectors */
__le32 failed_decrypt_count; /* count of # of failed attempts to decrypt and
mount, set to 0 on successful mount */
mount, set to 0 on successful mount */
unsigned char crypto_type_name[MAX_CRYPTO_TYPE_NAME_LEN]; /* The type of encryption
needed to decrypt this
partition, null terminated */
needed to decrypt this
partition, null terminated */
__le32 spare2; /* ignored */
unsigned char master_key[MAX_KEY_LEN]; /* The encrypted key for decrypting the filesystem */
unsigned char salt[SALT_LEN]; /* The salt used for this encryption */
@ -100,6 +101,12 @@ struct crypt_mnt_ftr {
__le8 N_factor; /* (1 << N) */
__le8 r_factor; /* (1 << r) */
__le8 p_factor; /* (1 << p) */
__le64 encrypted_upto; /* If we are in state CRYPT_ENCRYPTION_IN_PROGRESS and
we have to stop (e.g. power low) this is the last
encrypted 512 byte sector.*/
__le8 hash_first_block[SHA256_DIGEST_LENGTH]; /* When CRYPT_ENCRYPTION_IN_PROGRESS
set, hash of first block, used
to validate before continuing*/
};
/* Persistant data that should be available before decryption.