#include <android-base/logging.h>
#include <android-base/properties.h>
-// HORRIBLE HACK, FIXME
-#include "cryptfs.h"
-
// FIXME horrible cut-and-paste code
static inline int unix_read(int fd, void* buff, int len) {
return TEMP_FAILURE_RETRY(read(fd, buff, len));
struct encryptGroupsData {
int realfd;
int cryptofd;
- off64_t numblocks;
off64_t one_pct, cur_pct, new_pct;
- off64_t blocks_already_done, tot_numblocks;
+ off64_t blocks_already_done;
off64_t used_blocks_already_done, tot_used_blocks;
const char* real_blkdev;
const char* crypto_blkdev;
int count;
off64_t offset;
char* buffer;
- off64_t last_written_sector;
- int completed;
time_t time_started;
int remaining_time;
bool set_progress_properties;
}
data->count = 0;
- data->last_written_sector =
- (data->offset + data->count) / info.block_size * CRYPT_SECTOR_SIZE - 1;
return 0;
}
}
}
- data->completed = 1;
rc = 0;
errout:
}
static int cryptfs_enable_inplace_ext4(const char* crypto_blkdev, const char* real_blkdev,
- off64_t size, off64_t* size_already_done, off64_t tot_size,
- off64_t previously_encrypted_upto,
- bool set_progress_properties) {
+ off64_t size, bool set_progress_properties) {
u32 i;
struct encryptGroupsData data;
int rc; // Can't initialize without causing warning -Wclobbered
int retries = RETRY_MOUNT_ATTEMPTS;
struct timespec time_started = {0};
- if (previously_encrypted_upto > *size_already_done) {
- LOG(DEBUG) << "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;
goto errout;
}
- data.numblocks = size / CRYPT_SECTORS_PER_BUFSIZE;
- data.tot_numblocks = tot_size / CRYPT_SECTORS_PER_BUFSIZE;
- data.blocks_already_done = *size_already_done / CRYPT_SECTORS_PER_BUFSIZE;
+ data.blocks_already_done = 0;
LOG(INFO) << "Encrypting ext4 filesystem in place...";
- data.tot_used_blocks = data.numblocks;
+ data.tot_used_blocks = size / CRYPT_SECTORS_PER_BUFSIZE;
for (i = 0; i < aux_info.groups; ++i) {
data.tot_used_blocks -= aux_info.bg_desc[i].bg_free_blocks_count;
}
goto errout;
}
- *size_already_done += data.completed ? size : data.last_written_sector;
rc = 0;
errout:
}
static int cryptfs_enable_inplace_f2fs(const char* crypto_blkdev, const char* real_blkdev,
- off64_t size, off64_t* size_already_done, off64_t tot_size,
- off64_t previously_encrypted_upto,
- bool set_progress_properties) {
+ off64_t size, bool set_progress_properties) {
struct encryptGroupsData data;
struct f2fs_info* f2fs_info = NULL;
int rc = ENABLE_INPLACE_ERR_OTHER;
struct timespec time_started = {0};
- if (previously_encrypted_upto > *size_already_done) {
- LOG(DEBUG) << "Not fast encrypting since resuming part way through";
- return ENABLE_INPLACE_ERR_OTHER;
- }
memset(&data, 0, sizeof(data));
data.real_blkdev = real_blkdev;
data.crypto_blkdev = crypto_blkdev;
f2fs_info = generate_f2fs_info(data.realfd);
if (!f2fs_info) goto errout;
- data.numblocks = size / CRYPT_SECTORS_PER_BUFSIZE;
- data.tot_numblocks = tot_size / CRYPT_SECTORS_PER_BUFSIZE;
- data.blocks_already_done = *size_already_done / CRYPT_SECTORS_PER_BUFSIZE;
+ data.blocks_already_done = 0;
data.tot_used_blocks = get_num_blocks_used(f2fs_info);
goto errout;
}
- *size_already_done += size;
rc = 0;
errout:
}
static int cryptfs_enable_inplace_full(const char* crypto_blkdev, const char* real_blkdev,
- off64_t size, off64_t* size_already_done, off64_t tot_size,
- off64_t previously_encrypted_upto,
- bool set_progress_properties) {
+ off64_t size, bool set_progress_properties) {
int realfd, cryptofd;
char* buf[CRYPT_INPLACE_BUFSIZE];
int rc = ENABLE_INPLACE_ERR_OTHER;
off64_t numblocks, i, remainder;
off64_t one_pct, cur_pct, new_pct;
- off64_t blocks_already_done, tot_numblocks;
if ((realfd = open(real_blkdev, O_RDONLY | O_CLOEXEC)) < 0) {
PLOG(ERROR) << "Error opening real_blkdev " << real_blkdev << " for inplace encrypt";
*/
numblocks = size / CRYPT_SECTORS_PER_BUFSIZE;
remainder = size % CRYPT_SECTORS_PER_BUFSIZE;
- tot_numblocks = tot_size / CRYPT_SECTORS_PER_BUFSIZE;
- blocks_already_done = *size_already_done / CRYPT_SECTORS_PER_BUFSIZE;
LOG(ERROR) << "Encrypting filesystem in place...";
- i = previously_encrypted_upto + 1 - *size_already_done;
-
- if (lseek64(realfd, i * CRYPT_SECTOR_SIZE, SEEK_SET) < 0) {
- PLOG(ERROR) << "Cannot seek to previously encrypted point on " << real_blkdev;
- goto errout;
- }
-
- if (lseek64(cryptofd, i * CRYPT_SECTOR_SIZE, SEEK_SET) < 0) {
- PLOG(ERROR) << "Cannot seek to previously encrypted point on " << crypto_blkdev;
- goto errout;
- }
-
- for (; i < size && i % CRYPT_SECTORS_PER_BUFSIZE != 0; ++i) {
- if (unix_read(realfd, buf, CRYPT_SECTOR_SIZE) <= 0) {
- PLOG(ERROR) << "Error reading initial sectors from real_blkdev " << real_blkdev
- << " for inplace encrypt";
- goto errout;
- }
- if (unix_write(cryptofd, buf, CRYPT_SECTOR_SIZE) <= 0) {
- PLOG(ERROR) << "Error writing initial sectors to crypto_blkdev " << crypto_blkdev
- << " for inplace encrypt";
- goto errout;
- } else {
- LOG(INFO) << "Encrypted 1 block at " << i;
- }
- }
-
- one_pct = tot_numblocks / 100;
+ one_pct = numblocks / 100;
cur_pct = 0;
/* process the majority of the filesystem in blocks */
- for (i /= CRYPT_SECTORS_PER_BUFSIZE; i < numblocks; i++) {
- new_pct = (i + blocks_already_done) / one_pct;
+ for (i = 0; i < numblocks; i++) {
+ new_pct = i / one_pct;
if (set_progress_properties && new_pct > cur_pct) {
char property_buf[8];
}
}
- *size_already_done += size;
rc = 0;
errout:
/* returns on of the ENABLE_INPLACE_* return codes */
int cryptfs_enable_inplace(const char* crypto_blkdev, const char* real_blkdev, off64_t size,
- off64_t* size_already_done, off64_t tot_size,
- off64_t previously_encrypted_upto, bool set_progress_properties) {
+ bool set_progress_properties) {
int rc_ext4, rc_f2fs, rc_full;
LOG(DEBUG) << "cryptfs_enable_inplace(" << crypto_blkdev << ", " << real_blkdev << ", " << size
- << ", " << size_already_done << ", " << tot_size << ", " << previously_encrypted_upto
<< ", " << set_progress_properties << ")";
- if (previously_encrypted_upto) {
- LOG(DEBUG) << "Continuing encryption from " << previously_encrypted_upto;
- }
-
- if (*size_already_done + size < previously_encrypted_upto) {
- LOG(DEBUG) << "cryptfs_enable_inplace already done";
- *size_already_done += size;
- return 0;
- }
/* TODO: identify filesystem type.
* As is, cryptfs_enable_inplace_ext4 will fail on an f2fs partition, and
* then we will drop down to cryptfs_enable_inplace_f2fs.
* */
- if ((rc_ext4 = cryptfs_enable_inplace_ext4(crypto_blkdev, real_blkdev, size, size_already_done,
- tot_size, previously_encrypted_upto,
+ if ((rc_ext4 = cryptfs_enable_inplace_ext4(crypto_blkdev, real_blkdev, size,
set_progress_properties)) == 0) {
LOG(DEBUG) << "cryptfs_enable_inplace_ext4 success";
return 0;
}
LOG(DEBUG) << "cryptfs_enable_inplace_ext4()=" << rc_ext4;
- if ((rc_f2fs = cryptfs_enable_inplace_f2fs(crypto_blkdev, real_blkdev, size, size_already_done,
- tot_size, previously_encrypted_upto,
+ if ((rc_f2fs = cryptfs_enable_inplace_f2fs(crypto_blkdev, real_blkdev, size,
set_progress_properties)) == 0) {
LOG(DEBUG) << "cryptfs_enable_inplace_f2fs success";
return 0;
LOG(DEBUG) << "cryptfs_enable_inplace_f2fs()=" << rc_f2fs;
rc_full =
- cryptfs_enable_inplace_full(crypto_blkdev, real_blkdev, size, size_already_done, tot_size,
- previously_encrypted_upto, set_progress_properties);
+ cryptfs_enable_inplace_full(crypto_blkdev, real_blkdev, size, set_progress_properties);
LOG(DEBUG) << "cryptfs_enable_inplace_full()=" << rc_full;
/* Hack for b/17898962, the following is the symptom... */
#define ENABLE_INPLACE_ERR_DEV (-2) /* crypto_blkdev issue */
int cryptfs_enable_inplace(const char* crypto_blkdev, const char* real_blkdev, off64_t size,
- off64_t* size_already_done, off64_t tot_size,
- off64_t previously_encrypted_upto, bool set_progress_properties);
+ bool set_progress_properties);
#endif
// FIXME handle the corrupt case
if (needs_encrypt) {
LOG(INFO) << "Beginning inplace encryption, nr_sec: " << nr_sec;
- off64_t size_already_done = 0;
- auto rc = cryptfs_enable_inplace(crypto_blkdev.data(), blk_device.data(), nr_sec,
- &size_already_done, nr_sec, 0, false);
+ auto rc = cryptfs_enable_inplace(crypto_blkdev.data(), blk_device.data(), nr_sec, false);
if (rc != 0) {
LOG(ERROR) << "Inplace crypto failed with code: " << rc;
return false;
}
- if (static_cast<uint64_t>(size_already_done) != nr_sec) {
- LOG(ERROR) << "Inplace crypto only got up to sector: " << size_already_done;
- return false;
- }
LOG(INFO) << "Inplace encryption complete";
}
/* definitions of flags in the structure below */
#define CRYPT_MNT_KEY_UNENCRYPTED 0x1 /* The key for the partition is not encrypted. */
-#define CRYPT_ENCRYPTION_IN_PROGRESS \
- 0x2 /* Encryption partially completed, \
- encrypted_upto valid*/
+#define CRYPT_ENCRYPTION_IN_PROGRESS 0x2 /* no longer used */
#define CRYPT_INCONSISTENT_STATE \
0x4 /* Set when starting encryption, clear when \
exit cleanly, either through success or \
__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*/
+ __le64 encrypted_upto; /* no longer used */
+ __le8 hash_first_block[SHA256_DIGEST_LENGTH]; /* no longer used */
/* key_master key, used to sign the derived key which is then used to generate
* the intermediate key
#define FRAMEWORK_BOOT_WAIT 60
-static int cryptfs_SHA256_fileblock(const char* filename, __le8* buf) {
- int fd = open(filename, O_RDONLY | O_CLOEXEC);
- 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, const char* crypto_blkdev,
- const char* real_blkdev, int previously_encrypted_upto) {
- off64_t cur_encryption_done = 0, tot_encryption_size = 0;
+ const char* real_blkdev) {
int rc = -1;
- /* The size of the userdata partition, and add in the vold volumes below */
- tot_encryption_size = crypt_ftr->fs_size;
-
- rc = cryptfs_enable_inplace(crypto_blkdev, real_blkdev, crypt_ftr->fs_size, &cur_encryption_done,
- tot_encryption_size, previously_encrypted_upto, true);
+ rc = cryptfs_enable_inplace(crypto_blkdev, real_blkdev, crypt_ftr->fs_size, true);
if (rc == ENABLE_INPLACE_ERR_DEV) {
/* Hack for b/17898962 */
}
if (!rc) {
- crypt_ftr->encrypted_upto = cur_encryption_done;
- }
+ crypt_ftr->encrypted_upto = crypt_ftr->fs_size;
- if (!rc && crypt_ftr->encrypted_upto == crypt_ftr->fs_size) {
/* 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");
char lockid[32] = {0};
std::string key_loc;
int num_vols;
- off64_t previously_encrypted_upto = 0;
bool rebootEncryption = false;
bool onlyCreateHeader = false;
std::unique_ptr<android::wakelock::WakeLock> wakeLock = nullptr;
if (get_crypt_ftr_and_key(&crypt_ftr) == 0) {
- if (crypt_ftr.flags & CRYPT_ENCRYPTION_IN_PROGRESS) {
- /* An encryption was underway and was interrupted */
- previously_encrypted_upto = crypt_ftr.encrypted_upto;
- crypt_ftr.encrypted_upto = 0;
- crypt_ftr.flags &= ~CRYPT_ENCRYPTION_IN_PROGRESS;
-
- /* At this point, we are in an inconsistent state. Until we successfully
- complete encryption, a reboot will leave us broken. So mark the
- encryption failed in case that happens.
- On successfully completing encryption, remove this flag */
- crypt_ftr.flags |= CRYPT_INCONSISTENT_STATE;
-
- put_crypt_ftr_and_key(&crypt_ftr);
- } else if (crypt_ftr.flags & CRYPT_FORCE_ENCRYPTION) {
+ if (crypt_ftr.flags & CRYPT_FORCE_ENCRYPTION) {
if (!check_ftr_sha(&crypt_ftr)) {
memset(&crypt_ftr, 0, sizeof(crypt_ftr));
put_crypt_ftr_and_key(&crypt_ftr);
}
property_get("ro.crypto.state", encrypted_state, "");
- if (!strcmp(encrypted_state, "encrypted") && !previously_encrypted_upto) {
+ if (!strcmp(encrypted_state, "encrypted")) {
SLOGE("Device is already running encrypted, aborting");
goto error_unencrypted;
}
/* Start the actual work of making an encrypted filesystem */
/* Initialize a crypt_mnt_ftr for the partition */
- if (previously_encrypted_upto == 0 && !rebootEncryption) {
+ if (!rebootEncryption) {
if (cryptfs_init_crypt_mnt_ftr(&crypt_ftr)) {
goto error_shutting_down;
}
create_crypto_blk_dev(&crypt_ftr, decrypted_master_key, real_blkdev.c_str(), &crypto_blkdev,
CRYPTO_BLOCK_DEVICE, 0);
- /* 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.c_str(), hash_first_block);
-
- 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 (!rc) {
- rc = cryptfs_enable_all_volumes(&crypt_ftr, crypto_blkdev.c_str(), real_blkdev.data(),
- previously_encrypted_upto);
- }
-
- /* Calculate checksum if we are not finished */
- if (!rc && crypt_ftr.encrypted_upto != crypt_ftr.fs_size) {
- rc = cryptfs_SHA256_fileblock(crypto_blkdev.c_str(), crypt_ftr.hash_first_block);
- if (rc) {
- SLOGE("Error calculating checksum for continuing encryption");
- rc = -1;
- }
- }
+ rc = cryptfs_enable_all_volumes(&crypt_ftr, crypto_blkdev.c_str(), real_blkdev.data());
/* Undo the dm-crypt mapping whether we succeed or not */
delete_crypto_blk_dev(CRYPTO_BLOCK_DEVICE);
/* Success */
crypt_ftr.flags &= ~CRYPT_INCONSISTENT_STATE;
- if (crypt_ftr.encrypted_upto != crypt_ftr.fs_size) {
- SLOGD("Encrypted up to sector %lld - will continue after reboot",
- crypt_ftr.encrypted_upto);
- crypt_ftr.flags |= CRYPT_ENCRYPTION_IN_PROGRESS;
- }
-
put_crypt_ftr_and_key(&crypt_ftr);
- if (crypt_ftr.encrypted_upto == crypt_ftr.fs_size) {
- char value[PROPERTY_VALUE_MAX];
- property_get("ro.crypto.state", value, "");
- if (!strcmp(value, "")) {
- /* default encryption - continue first boot sequence */
- property_set("ro.crypto.state", "encrypted");
- property_set("ro.crypto.type", "block");
- wakeLock.reset(nullptr);
- if (rebootEncryption && crypt_ftr.crypt_type != CRYPT_TYPE_DEFAULT) {
- // Bring up cryptkeeper that will check the password and set it
- property_set("vold.decrypt", "trigger_shutdown_framework");
- sleep(2);
- property_set("vold.encrypt_progress", "");
- cryptfs_trigger_restart_min_framework();
- } else {
- cryptfs_check_passwd(DEFAULT_PASSWORD);
- cryptfs_restart_internal(1);
- }
- return 0;
+ char value[PROPERTY_VALUE_MAX];
+ property_get("ro.crypto.state", value, "");
+ if (!strcmp(value, "")) {
+ /* default encryption - continue first boot sequence */
+ property_set("ro.crypto.state", "encrypted");
+ property_set("ro.crypto.type", "block");
+ wakeLock.reset(nullptr);
+ if (rebootEncryption && crypt_ftr.crypt_type != CRYPT_TYPE_DEFAULT) {
+ // Bring up cryptkeeper that will check the password and set it
+ property_set("vold.decrypt", "trigger_shutdown_framework");
+ sleep(2);
+ property_set("vold.encrypt_progress", "");
+ cryptfs_trigger_restart_min_framework();
} else {
- sleep(2); /* Give the UI a chance to show 100% progress */
- cryptfs_reboot(RebootType::reboot);
+ cryptfs_check_passwd(DEFAULT_PASSWORD);
+ cryptfs_restart_internal(1);
}
+ return 0;
} else {
- sleep(2); /* Partially encrypted, ensure writes flushed to ssd */
- cryptfs_reboot(RebootType::shutdown);
+ sleep(2); /* Give the UI a chance to show 100% progress */
+ cryptfs_reboot(RebootType::reboot);
}
} else {
char value[PROPERTY_VALUE_MAX];