Merge "Merge Android 14" into main
This commit is contained in:
commit
ab9fe7e68a
9 changed files with 313 additions and 168 deletions
|
@ -16,6 +16,8 @@
|
||||||
|
|
||||||
#define LOG_TAG "Checkpoint"
|
#define LOG_TAG "Checkpoint"
|
||||||
#include "Checkpoint.h"
|
#include "Checkpoint.h"
|
||||||
|
#include "FsCrypt.h"
|
||||||
|
#include "KeyStorage.h"
|
||||||
#include "VoldUtil.h"
|
#include "VoldUtil.h"
|
||||||
#include "VolumeManager.h"
|
#include "VolumeManager.h"
|
||||||
|
|
||||||
|
@ -78,6 +80,18 @@ bool setBowState(std::string const& block_device, std::string const& state) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Do any work that was deferred until the userdata filesystem checkpoint was
|
||||||
|
// committed. This work involves the deletion of resources that aren't covered
|
||||||
|
// by the userdata filesystem checkpoint, e.g. Keystore keys.
|
||||||
|
void DoCheckpointCommittedWork() {
|
||||||
|
// Take the crypt lock to provide synchronization with the Binder calls that
|
||||||
|
// operate on key directories.
|
||||||
|
std::lock_guard<std::mutex> lock(VolumeManager::Instance()->getCryptLock());
|
||||||
|
|
||||||
|
DeferredCommitKeystoreKeys();
|
||||||
|
fscrypt_deferred_fixate_ce_keys();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
Status cp_supportsCheckpoint(bool& result) {
|
Status cp_supportsCheckpoint(bool& result) {
|
||||||
|
@ -206,6 +220,7 @@ Status cp_commitChanges() {
|
||||||
if (!android::base::RemoveFileIfExists(kMetadataCPFile, &err_str))
|
if (!android::base::RemoveFileIfExists(kMetadataCPFile, &err_str))
|
||||||
return error(err_str.c_str());
|
return error(err_str.c_str());
|
||||||
|
|
||||||
|
std::thread(DoCheckpointCommittedWork).detach();
|
||||||
return Status::ok();
|
return Status::ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -582,21 +597,31 @@ void restoreSector(int device_fd, Used_Sectors& used_sectors, std::vector<char>&
|
||||||
|
|
||||||
// Read from the device
|
// Read from the device
|
||||||
// If we are validating, the read occurs as though the relocations had happened
|
// If we are validating, the read occurs as though the relocations had happened
|
||||||
|
// returns the amount asked for or an empty buffer on error. Partial reads are considered a failure
|
||||||
std::vector<char> relocatedRead(int device_fd, Relocations const& relocations, bool validating,
|
std::vector<char> relocatedRead(int device_fd, Relocations const& relocations, bool validating,
|
||||||
sector_t sector, uint32_t size, uint32_t block_size) {
|
sector_t sector, uint32_t size, uint32_t block_size) {
|
||||||
if (!validating) {
|
if (!validating) {
|
||||||
std::vector<char> buffer(size);
|
std::vector<char> buffer(size);
|
||||||
lseek64(device_fd, sector * kSectorSize, SEEK_SET);
|
off64_t offset = sector * kSectorSize;
|
||||||
read(device_fd, &buffer[0], size);
|
if (lseek64(device_fd, offset, SEEK_SET) != offset) {
|
||||||
|
return std::vector<char>();
|
||||||
|
}
|
||||||
|
if (read(device_fd, &buffer[0], size) != static_cast<ssize_t>(size)) {
|
||||||
|
return std::vector<char>();
|
||||||
|
}
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<char> buffer(size);
|
std::vector<char> buffer(size);
|
||||||
for (uint32_t i = 0; i < size; i += block_size, sector += block_size / kSectorSize) {
|
for (uint32_t i = 0; i < size; i += block_size, sector += block_size / kSectorSize) {
|
||||||
auto relocation = --relocations.upper_bound(sector);
|
auto relocation = --relocations.upper_bound(sector);
|
||||||
lseek64(device_fd, (sector + relocation->second - relocation->first) * kSectorSize,
|
off64_t offset = (sector + relocation->second - relocation->first) * kSectorSize;
|
||||||
SEEK_SET);
|
if (lseek64(device_fd, offset, SEEK_SET) != offset) {
|
||||||
read(device_fd, &buffer[i], block_size);
|
return std::vector<char>();
|
||||||
|
}
|
||||||
|
if (read(device_fd, &buffer[i], block_size) != static_cast<ssize_t>(block_size)) {
|
||||||
|
return std::vector<char>();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return buffer;
|
return buffer;
|
||||||
|
@ -619,7 +644,10 @@ Status cp_restoreCheckpoint(const std::string& blockDevice, int restore_limit) {
|
||||||
if (device_fd < 0) return error("Cannot open " + blockDevice);
|
if (device_fd < 0) return error("Cannot open " + blockDevice);
|
||||||
|
|
||||||
log_sector_v1_0 original_ls;
|
log_sector_v1_0 original_ls;
|
||||||
read(device_fd, reinterpret_cast<char*>(&original_ls), sizeof(original_ls));
|
if (read(device_fd, reinterpret_cast<char*>(&original_ls), sizeof(original_ls)) !=
|
||||||
|
sizeof(original_ls)) {
|
||||||
|
return error(EINVAL, "Cannot read sector");
|
||||||
|
}
|
||||||
if (original_ls.magic == kPartialRestoreMagic) {
|
if (original_ls.magic == kPartialRestoreMagic) {
|
||||||
validating = false;
|
validating = false;
|
||||||
action = "Restoring";
|
action = "Restoring";
|
||||||
|
@ -627,11 +655,19 @@ Status cp_restoreCheckpoint(const std::string& blockDevice, int restore_limit) {
|
||||||
return error(EINVAL, "No magic");
|
return error(EINVAL, "No magic");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (original_ls.block_size < sizeof(log_sector_v1_0)) {
|
||||||
|
return error(EINVAL, "Block size is invalid");
|
||||||
|
}
|
||||||
|
|
||||||
LOG(INFO) << action << " " << original_ls.sequence << " log sectors";
|
LOG(INFO) << action << " " << original_ls.sequence << " log sectors";
|
||||||
|
|
||||||
for (int sequence = original_ls.sequence; sequence >= 0 && status.isOk(); sequence--) {
|
for (int sequence = original_ls.sequence; sequence >= 0 && status.isOk(); sequence--) {
|
||||||
auto ls_buffer = relocatedRead(device_fd, relocations, validating, 0,
|
auto ls_buffer = relocatedRead(device_fd, relocations, validating, 0,
|
||||||
original_ls.block_size, original_ls.block_size);
|
original_ls.block_size, original_ls.block_size);
|
||||||
|
if (ls_buffer.size() != original_ls.block_size) {
|
||||||
|
status = error(EINVAL, "Failed to read log sector");
|
||||||
|
break;
|
||||||
|
}
|
||||||
log_sector_v1_0& ls = *reinterpret_cast<log_sector_v1_0*>(&ls_buffer[0]);
|
log_sector_v1_0& ls = *reinterpret_cast<log_sector_v1_0*>(&ls_buffer[0]);
|
||||||
|
|
||||||
Used_Sectors used_sectors;
|
Used_Sectors used_sectors;
|
||||||
|
@ -653,6 +689,14 @@ Status cp_restoreCheckpoint(const std::string& blockDevice, int restore_limit) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ls.header_size < sizeof(log_sector_v1_0) || ls.header_size > ls.block_size) {
|
||||||
|
status = error(EINVAL, "Log sector header size is invalid");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (ls.count < 1 || ls.count > (ls.block_size - ls.header_size) / sizeof(log_entry)) {
|
||||||
|
status = error(EINVAL, "Log sector count is invalid");
|
||||||
|
break;
|
||||||
|
}
|
||||||
LOG(INFO) << action << " from log sector " << ls.sequence;
|
LOG(INFO) << action << " from log sector " << ls.sequence;
|
||||||
for (log_entry* le =
|
for (log_entry* le =
|
||||||
reinterpret_cast<log_entry*>(&ls_buffer[ls.header_size]) + ls.count - 1;
|
reinterpret_cast<log_entry*>(&ls_buffer[ls.header_size]) + ls.count - 1;
|
||||||
|
@ -662,8 +706,16 @@ Status cp_restoreCheckpoint(const std::string& blockDevice, int restore_limit) {
|
||||||
<< " to " << le->source << " with checksum " << std::hex
|
<< " to " << le->source << " with checksum " << std::hex
|
||||||
<< le->checksum;
|
<< le->checksum;
|
||||||
|
|
||||||
|
if (ls.block_size > UINT_MAX - le->size || le->size < ls.block_size) {
|
||||||
|
status = error(EINVAL, "log entry is invalid");
|
||||||
|
break;
|
||||||
|
}
|
||||||
auto buffer = relocatedRead(device_fd, relocations, validating, le->dest, le->size,
|
auto buffer = relocatedRead(device_fd, relocations, validating, le->dest, le->size,
|
||||||
ls.block_size);
|
ls.block_size);
|
||||||
|
if (buffer.size() != le->size) {
|
||||||
|
status = error(EINVAL, "Failed to read sector");
|
||||||
|
break;
|
||||||
|
}
|
||||||
uint32_t checksum = le->source / (ls.block_size / kSectorSize);
|
uint32_t checksum = le->source / (ls.block_size / kSectorSize);
|
||||||
for (size_t i = 0; i < le->size; i += ls.block_size) {
|
for (size_t i = 0; i < le->size; i += ls.block_size) {
|
||||||
crc32(&buffer[i], ls.block_size, &checksum);
|
crc32(&buffer[i], ls.block_size, &checksum);
|
||||||
|
@ -696,8 +748,17 @@ Status cp_restoreCheckpoint(const std::string& blockDevice, int restore_limit) {
|
||||||
LOG(WARNING) << "Checkpoint validation failed - attempting to roll forward";
|
LOG(WARNING) << "Checkpoint validation failed - attempting to roll forward";
|
||||||
auto buffer = relocatedRead(device_fd, relocations, false, original_ls.sector0,
|
auto buffer = relocatedRead(device_fd, relocations, false, original_ls.sector0,
|
||||||
original_ls.block_size, original_ls.block_size);
|
original_ls.block_size, original_ls.block_size);
|
||||||
lseek64(device_fd, 0, SEEK_SET);
|
if (buffer.size() != original_ls.block_size) {
|
||||||
write(device_fd, &buffer[0], original_ls.block_size);
|
return error(EINVAL, "Failed to read original sector");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lseek64(device_fd, 0, SEEK_SET) != 0) {
|
||||||
|
return error(EINVAL, "Failed to seek to sector 0");
|
||||||
|
}
|
||||||
|
if (write(device_fd, &buffer[0], original_ls.block_size) !=
|
||||||
|
static_cast<ssize_t>(original_ls.block_size)) {
|
||||||
|
return error(EINVAL, "Failed to write original sector");
|
||||||
|
}
|
||||||
return Status::ok();
|
return Status::ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
304
FsCrypt.cpp
304
FsCrypt.cpp
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
#include "FsCrypt.h"
|
#include "FsCrypt.h"
|
||||||
|
|
||||||
|
#include "Checkpoint.h"
|
||||||
#include "KeyStorage.h"
|
#include "KeyStorage.h"
|
||||||
#include "KeyUtil.h"
|
#include "KeyUtil.h"
|
||||||
#include "Utils.h"
|
#include "Utils.h"
|
||||||
|
@ -96,9 +97,15 @@ const std::string data_data_dir = std::string() + DATA_MNT_POINT + "/data";
|
||||||
const std::string data_user_0_dir = std::string() + DATA_MNT_POINT + "/user/0";
|
const std::string data_user_0_dir = std::string() + DATA_MNT_POINT + "/user/0";
|
||||||
const std::string media_obb_dir = std::string() + DATA_MNT_POINT + "/media/obb";
|
const std::string media_obb_dir = std::string() + DATA_MNT_POINT + "/media/obb";
|
||||||
|
|
||||||
// Some users are ephemeral, don't try to wipe their keys from disk
|
// The file encryption options to use on the /data filesystem
|
||||||
|
EncryptionOptions s_data_options;
|
||||||
|
|
||||||
|
// Some users are ephemeral; don't try to store or wipe their keys on disk.
|
||||||
std::set<userid_t> s_ephemeral_users;
|
std::set<userid_t> s_ephemeral_users;
|
||||||
|
|
||||||
|
// New CE keys that haven't been committed to disk yet
|
||||||
|
std::map<userid_t, KeyBuffer> s_new_ce_keys;
|
||||||
|
|
||||||
// The system DE encryption policy
|
// The system DE encryption policy
|
||||||
EncryptionPolicy s_device_policy;
|
EncryptionPolicy s_device_policy;
|
||||||
|
|
||||||
|
@ -106,10 +113,17 @@ EncryptionPolicy s_device_policy;
|
||||||
std::map<userid_t, EncryptionPolicy> s_de_policies;
|
std::map<userid_t, EncryptionPolicy> s_de_policies;
|
||||||
std::map<userid_t, EncryptionPolicy> s_ce_policies;
|
std::map<userid_t, EncryptionPolicy> s_ce_policies;
|
||||||
|
|
||||||
|
// CE key fixation operations that have been deferred to checkpoint commit
|
||||||
|
std::map<std::string, std::string> s_deferred_fixations;
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
// Returns KeyGeneration suitable for key as described in EncryptionOptions
|
// Returns KeyGeneration suitable for key as described in EncryptionOptions
|
||||||
static KeyGeneration makeGen(const EncryptionOptions& options) {
|
static KeyGeneration makeGen(const EncryptionOptions& options) {
|
||||||
|
if (options.version == 0) {
|
||||||
|
LOG(ERROR) << "EncryptionOptions not initialized";
|
||||||
|
return android::vold::neverGen();
|
||||||
|
}
|
||||||
return KeyGeneration{FSCRYPT_MAX_KEY_SIZE, true, options.use_hw_wrapped_key};
|
return KeyGeneration{FSCRYPT_MAX_KEY_SIZE, true, options.use_hw_wrapped_key};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -176,20 +190,23 @@ static bool get_ce_key_new_path(const std::string& directory_path,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Discard all keys but the named one; rename it to canonical name.
|
// Discard all keys but the named one; rename it to canonical name.
|
||||||
// No point in acting on errors in this; ignore them.
|
static bool fixate_user_ce_key(const std::string& directory_path, const std::string& to_fix,
|
||||||
static void fixate_user_ce_key(const std::string& directory_path, const std::string& to_fix,
|
|
||||||
const std::vector<std::string>& paths) {
|
const std::vector<std::string>& paths) {
|
||||||
|
bool need_sync = false;
|
||||||
for (auto const other_path : paths) {
|
for (auto const other_path : paths) {
|
||||||
if (other_path != to_fix) {
|
if (other_path != to_fix) {
|
||||||
android::vold::destroyKey(other_path);
|
android::vold::destroyKey(other_path);
|
||||||
|
need_sync = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
auto const current_path = get_ce_key_current_path(directory_path);
|
auto const current_path = get_ce_key_current_path(directory_path);
|
||||||
if (to_fix != current_path) {
|
if (to_fix != current_path) {
|
||||||
LOG(DEBUG) << "Renaming " << to_fix << " to " << current_path;
|
LOG(DEBUG) << "Renaming " << to_fix << " to " << current_path;
|
||||||
if (!android::vold::RenameKeyDir(to_fix, current_path)) return;
|
if (!android::vold::RenameKeyDir(to_fix, current_path)) return false;
|
||||||
|
need_sync = true;
|
||||||
}
|
}
|
||||||
android::vold::FsyncDirectory(directory_path);
|
if (need_sync && !android::vold::FsyncDirectory(directory_path)) return false;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool read_and_fixate_user_ce_key(userid_t user_id,
|
static bool read_and_fixate_user_ce_key(userid_t user_id,
|
||||||
|
@ -201,6 +218,7 @@ static bool read_and_fixate_user_ce_key(userid_t user_id,
|
||||||
LOG(DEBUG) << "Trying user CE key " << ce_key_path;
|
LOG(DEBUG) << "Trying user CE key " << ce_key_path;
|
||||||
if (retrieveKey(ce_key_path, auth, ce_key)) {
|
if (retrieveKey(ce_key_path, auth, ce_key)) {
|
||||||
LOG(DEBUG) << "Successfully retrieved key";
|
LOG(DEBUG) << "Successfully retrieved key";
|
||||||
|
s_deferred_fixations.erase(directory_path);
|
||||||
fixate_user_ce_key(directory_path, ce_key_path, paths);
|
fixate_user_ce_key(directory_path, ce_key_path, paths);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -236,19 +254,19 @@ static bool MightBeEmmcStorage(const std::string& blk_device) {
|
||||||
StartsWith(name, "vd");
|
StartsWith(name, "vd");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Retrieve the options to use for encryption policies on the /data filesystem.
|
// Sets s_data_options to the file encryption options for the /data filesystem.
|
||||||
static bool get_data_file_encryption_options(EncryptionOptions* options) {
|
static bool init_data_file_encryption_options() {
|
||||||
auto entry = GetEntryForMountPoint(&fstab_default, DATA_MNT_POINT);
|
auto entry = GetEntryForMountPoint(&fstab_default, DATA_MNT_POINT);
|
||||||
if (entry == nullptr) {
|
if (entry == nullptr) {
|
||||||
LOG(ERROR) << "No mount point entry for " << DATA_MNT_POINT;
|
LOG(ERROR) << "No mount point entry for " << DATA_MNT_POINT;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!ParseOptions(entry->encryption_options, options)) {
|
if (!ParseOptions(entry->encryption_options, &s_data_options)) {
|
||||||
LOG(ERROR) << "Unable to parse encryption options for " << DATA_MNT_POINT ": "
|
LOG(ERROR) << "Unable to parse encryption options for " << DATA_MNT_POINT ": "
|
||||||
<< entry->encryption_options;
|
<< entry->encryption_options;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if ((options->flags & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32) &&
|
if ((s_data_options.flags & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32) &&
|
||||||
!MightBeEmmcStorage(entry->blk_device)) {
|
!MightBeEmmcStorage(entry->blk_device)) {
|
||||||
LOG(ERROR) << "The emmc_optimized encryption flag is only allowed on eMMC storage. Remove "
|
LOG(ERROR) << "The emmc_optimized encryption flag is only allowed on eMMC storage. Remove "
|
||||||
"this flag from the device's fstab";
|
"this flag from the device's fstab";
|
||||||
|
@ -259,6 +277,10 @@ static bool get_data_file_encryption_options(EncryptionOptions* options) {
|
||||||
|
|
||||||
static bool install_storage_key(const std::string& mountpoint, const EncryptionOptions& options,
|
static bool install_storage_key(const std::string& mountpoint, const EncryptionOptions& options,
|
||||||
const KeyBuffer& key, EncryptionPolicy* policy) {
|
const KeyBuffer& key, EncryptionPolicy* policy) {
|
||||||
|
if (options.version == 0) {
|
||||||
|
LOG(ERROR) << "EncryptionOptions not initialized";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
KeyBuffer ephemeral_wrapped_key;
|
KeyBuffer ephemeral_wrapped_key;
|
||||||
if (options.use_hw_wrapped_key) {
|
if (options.use_hw_wrapped_key) {
|
||||||
if (!exportWrappedStorageKey(key, &ephemeral_wrapped_key)) {
|
if (!exportWrappedStorageKey(key, &ephemeral_wrapped_key)) {
|
||||||
|
@ -297,12 +319,10 @@ static bool get_volume_file_encryption_options(EncryptionOptions* options) {
|
||||||
static bool read_and_install_user_ce_key(userid_t user_id,
|
static bool read_and_install_user_ce_key(userid_t user_id,
|
||||||
const android::vold::KeyAuthentication& auth) {
|
const android::vold::KeyAuthentication& auth) {
|
||||||
if (s_ce_policies.count(user_id) != 0) return true;
|
if (s_ce_policies.count(user_id) != 0) return true;
|
||||||
EncryptionOptions options;
|
|
||||||
if (!get_data_file_encryption_options(&options)) return false;
|
|
||||||
KeyBuffer ce_key;
|
KeyBuffer ce_key;
|
||||||
if (!read_and_fixate_user_ce_key(user_id, auth, &ce_key)) return false;
|
if (!read_and_fixate_user_ce_key(user_id, auth, &ce_key)) return false;
|
||||||
EncryptionPolicy ce_policy;
|
EncryptionPolicy ce_policy;
|
||||||
if (!install_storage_key(DATA_MNT_POINT, options, ce_key, &ce_policy)) return false;
|
if (!install_storage_key(DATA_MNT_POINT, s_data_options, ce_key, &ce_policy)) return false;
|
||||||
s_ce_policies[user_id] = ce_policy;
|
s_ce_policies[user_id] = ce_policy;
|
||||||
LOG(DEBUG) << "Installed ce key for user " << user_id;
|
LOG(DEBUG) << "Installed ce key for user " << user_id;
|
||||||
return true;
|
return true;
|
||||||
|
@ -366,39 +386,50 @@ static bool destroy_dir(const std::string& dir) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// NB this assumes that there is only one thread listening for crypt commands, because
|
// Checks whether the DE key directory exists for the given user.
|
||||||
// it creates keys in a fixed location.
|
static bool de_key_exists(userid_t user_id) {
|
||||||
static bool create_and_install_user_keys(userid_t user_id, bool create_ephemeral) {
|
return android::vold::pathExists(get_de_key_path(user_id));
|
||||||
EncryptionOptions options;
|
}
|
||||||
if (!get_data_file_encryption_options(&options)) return false;
|
|
||||||
KeyBuffer de_key, ce_key;
|
// Checks whether at least one CE key subdirectory exists for the given user.
|
||||||
if (!generateStorageKey(makeGen(options), &de_key)) return false;
|
static bool ce_key_exists(userid_t user_id) {
|
||||||
if (!generateStorageKey(makeGen(options), &ce_key)) return false;
|
auto directory_path = get_ce_key_directory_path(user_id);
|
||||||
if (create_ephemeral) {
|
// The common case is that "$dir/current" exists, so check for that first.
|
||||||
// If the key should be created as ephemeral, don't store it.
|
if (android::vold::pathExists(get_ce_key_current_path(directory_path))) return true;
|
||||||
s_ephemeral_users.insert(user_id);
|
|
||||||
} else {
|
// Else, there could still be another subdirectory of $dir (if a crash
|
||||||
auto const directory_path = get_ce_key_directory_path(user_id);
|
// occurred during fixate_user_ce_key()), so check for one.
|
||||||
if (!prepare_dir(directory_path, 0700, AID_ROOT, AID_ROOT)) return false;
|
return android::vold::pathExists(directory_path) && !get_ce_key_paths(directory_path).empty();
|
||||||
auto const paths = get_ce_key_paths(directory_path);
|
}
|
||||||
std::string ce_key_path;
|
|
||||||
if (!get_ce_key_new_path(directory_path, paths, &ce_key_path)) return false;
|
static bool create_de_key(userid_t user_id, bool ephemeral) {
|
||||||
if (!android::vold::storeKeyAtomically(ce_key_path, user_key_temp, kEmptyAuthentication,
|
KeyBuffer de_key;
|
||||||
ce_key))
|
if (!generateStorageKey(makeGen(s_data_options), &de_key)) return false;
|
||||||
return false;
|
if (!ephemeral && !android::vold::storeKeyAtomically(get_de_key_path(user_id), user_key_temp,
|
||||||
fixate_user_ce_key(directory_path, ce_key_path, paths);
|
kEmptyAuthentication, de_key))
|
||||||
// Write DE key second; once this is written, all is good.
|
return false;
|
||||||
if (!android::vold::storeKeyAtomically(get_de_key_path(user_id), user_key_temp,
|
|
||||||
kEmptyAuthentication, de_key))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
EncryptionPolicy de_policy;
|
EncryptionPolicy de_policy;
|
||||||
if (!install_storage_key(DATA_MNT_POINT, options, de_key, &de_policy)) return false;
|
if (!install_storage_key(DATA_MNT_POINT, s_data_options, de_key, &de_policy)) return false;
|
||||||
s_de_policies[user_id] = de_policy;
|
s_de_policies[user_id] = de_policy;
|
||||||
|
LOG(INFO) << "Created DE key for user " << user_id;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool create_ce_key(userid_t user_id, bool ephemeral) {
|
||||||
|
KeyBuffer ce_key;
|
||||||
|
if (!generateStorageKey(makeGen(s_data_options), &ce_key)) return false;
|
||||||
|
if (!ephemeral) {
|
||||||
|
if (!prepare_dir(get_ce_key_directory_path(user_id), 0700, AID_ROOT, AID_ROOT))
|
||||||
|
return false;
|
||||||
|
// We don't store the CE key on disk here, since here we don't have the
|
||||||
|
// secret needed to do so securely. Instead, we cache it in memory for
|
||||||
|
// now, and we store it later in fscrypt_set_user_key_protection().
|
||||||
|
s_new_ce_keys.insert({user_id, ce_key});
|
||||||
|
}
|
||||||
EncryptionPolicy ce_policy;
|
EncryptionPolicy ce_policy;
|
||||||
if (!install_storage_key(DATA_MNT_POINT, options, ce_key, &ce_policy)) return false;
|
if (!install_storage_key(DATA_MNT_POINT, s_data_options, ce_key, &ce_policy)) return false;
|
||||||
s_ce_policies[user_id] = ce_policy;
|
s_ce_policies[user_id] = ce_policy;
|
||||||
LOG(DEBUG) << "Created keys for user " << user_id;
|
LOG(INFO) << "Created CE key for user " << user_id;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -420,8 +451,6 @@ static bool is_numeric(const char* name) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool load_all_de_keys() {
|
static bool load_all_de_keys() {
|
||||||
EncryptionOptions options;
|
|
||||||
if (!get_data_file_encryption_options(&options)) return false;
|
|
||||||
auto de_dir = user_key_dir + "/de";
|
auto de_dir = user_key_dir + "/de";
|
||||||
auto dirp = std::unique_ptr<DIR, int (*)(DIR*)>(opendir(de_dir.c_str()), closedir);
|
auto dirp = std::unique_ptr<DIR, int (*)(DIR*)>(opendir(de_dir.c_str()), closedir);
|
||||||
if (!dirp) {
|
if (!dirp) {
|
||||||
|
@ -452,7 +481,7 @@ static bool load_all_de_keys() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
EncryptionPolicy de_policy;
|
EncryptionPolicy de_policy;
|
||||||
if (!install_storage_key(DATA_MNT_POINT, options, de_key, &de_policy)) return false;
|
if (!install_storage_key(DATA_MNT_POINT, s_data_options, de_key, &de_policy)) return false;
|
||||||
auto ret = s_de_policies.insert({user_id, de_policy});
|
auto ret = s_de_policies.insert({user_id, de_policy});
|
||||||
if (!ret.second && ret.first->second != de_policy) {
|
if (!ret.second && ret.first->second != de_policy) {
|
||||||
LOG(ERROR) << "DE policy for user" << user_id << " changed";
|
LOG(ERROR) << "DE policy for user" << user_id << " changed";
|
||||||
|
@ -479,17 +508,17 @@ static bool try_reload_ce_keys() {
|
||||||
bool fscrypt_initialize_systemwide_keys() {
|
bool fscrypt_initialize_systemwide_keys() {
|
||||||
LOG(INFO) << "fscrypt_initialize_systemwide_keys";
|
LOG(INFO) << "fscrypt_initialize_systemwide_keys";
|
||||||
|
|
||||||
EncryptionOptions options;
|
if (!init_data_file_encryption_options()) return false;
|
||||||
if (!get_data_file_encryption_options(&options)) return false;
|
|
||||||
|
|
||||||
KeyBuffer device_key;
|
KeyBuffer device_key;
|
||||||
if (!retrieveOrGenerateKey(device_key_path, device_key_temp, kEmptyAuthentication,
|
if (!retrieveOrGenerateKey(device_key_path, device_key_temp, kEmptyAuthentication,
|
||||||
makeGen(options), &device_key))
|
makeGen(s_data_options), &device_key))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// This initializes s_device_policy, which is a global variable so that
|
// This initializes s_device_policy, which is a global variable so that
|
||||||
// fscrypt_init_user0() can access it later.
|
// fscrypt_init_user0() can access it later.
|
||||||
if (!install_storage_key(DATA_MNT_POINT, options, device_key, &s_device_policy)) return false;
|
if (!install_storage_key(DATA_MNT_POINT, s_data_options, device_key, &s_device_policy))
|
||||||
|
return false;
|
||||||
|
|
||||||
std::string options_string;
|
std::string options_string;
|
||||||
if (!OptionsToString(s_device_policy.options, &options_string)) {
|
if (!OptionsToString(s_device_policy.options, &options_string)) {
|
||||||
|
@ -504,9 +533,10 @@ bool fscrypt_initialize_systemwide_keys() {
|
||||||
LOG(INFO) << "Wrote system DE key reference to:" << ref_filename;
|
LOG(INFO) << "Wrote system DE key reference to:" << ref_filename;
|
||||||
|
|
||||||
KeyBuffer per_boot_key;
|
KeyBuffer per_boot_key;
|
||||||
if (!generateStorageKey(makeGen(options), &per_boot_key)) return false;
|
if (!generateStorageKey(makeGen(s_data_options), &per_boot_key)) return false;
|
||||||
EncryptionPolicy per_boot_policy;
|
EncryptionPolicy per_boot_policy;
|
||||||
if (!install_storage_key(DATA_MNT_POINT, options, per_boot_key, &per_boot_policy)) return false;
|
if (!install_storage_key(DATA_MNT_POINT, s_data_options, per_boot_key, &per_boot_policy))
|
||||||
|
return false;
|
||||||
std::string per_boot_ref_filename = std::string("/data") + fscrypt_key_per_boot_ref;
|
std::string per_boot_ref_filename = std::string("/data") + fscrypt_key_per_boot_ref;
|
||||||
if (!android::vold::writeStringToFile(per_boot_policy.key_raw_ref, per_boot_ref_filename))
|
if (!android::vold::writeStringToFile(per_boot_policy.key_raw_ref, per_boot_ref_filename))
|
||||||
return false;
|
return false;
|
||||||
|
@ -533,8 +563,17 @@ static bool prepare_special_dirs() {
|
||||||
// opportunity to also set the encryption policy of /data/data right away.
|
// opportunity to also set the encryption policy of /data/data right away.
|
||||||
EncryptionPolicy ce_policy;
|
EncryptionPolicy ce_policy;
|
||||||
if (lookup_policy(s_ce_policies, 0, &ce_policy)) {
|
if (lookup_policy(s_ce_policies, 0, &ce_policy)) {
|
||||||
if (!prepare_dir_with_policy(data_data_dir, 0771, AID_SYSTEM, AID_SYSTEM, ce_policy))
|
if (!prepare_dir_with_policy(data_data_dir, 0771, AID_SYSTEM, AID_SYSTEM, ce_policy)) {
|
||||||
return false;
|
// Preparing /data/data failed, yet we had just generated a new CE
|
||||||
|
// key because one wasn't stored. Before erroring out, try deleting
|
||||||
|
// the directory and retrying, as it's possible that the directory
|
||||||
|
// exists with different CE policy from an interrupted first boot.
|
||||||
|
if (rmdir(data_data_dir.c_str()) != 0) {
|
||||||
|
PLOG(ERROR) << "rmdir " << data_data_dir << " failed";
|
||||||
|
}
|
||||||
|
if (!prepare_dir_with_policy(data_data_dir, 0771, AID_SYSTEM, AID_SYSTEM, ce_policy))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!prepare_dir(data_data_dir, 0771, AID_SYSTEM, AID_SYSTEM)) return false;
|
if (!prepare_dir(data_data_dir, 0771, AID_SYSTEM, AID_SYSTEM)) return false;
|
||||||
// EnsurePolicy() will have to happen later, in fscrypt_prepare_user_storage().
|
// EnsurePolicy() will have to happen later, in fscrypt_prepare_user_storage().
|
||||||
|
@ -570,9 +609,13 @@ bool fscrypt_init_user0() {
|
||||||
if (!prepare_dir(user_key_dir, 0700, AID_ROOT, AID_ROOT)) return false;
|
if (!prepare_dir(user_key_dir, 0700, AID_ROOT, AID_ROOT)) return false;
|
||||||
if (!prepare_dir(user_key_dir + "/ce", 0700, AID_ROOT, AID_ROOT)) return false;
|
if (!prepare_dir(user_key_dir + "/ce", 0700, AID_ROOT, AID_ROOT)) return false;
|
||||||
if (!prepare_dir(user_key_dir + "/de", 0700, AID_ROOT, AID_ROOT)) return false;
|
if (!prepare_dir(user_key_dir + "/de", 0700, AID_ROOT, AID_ROOT)) return false;
|
||||||
if (!android::vold::pathExists(get_de_key_path(0))) {
|
|
||||||
if (!create_and_install_user_keys(0, false)) return false;
|
// Create user 0's DE and CE keys if they don't already exist. Check
|
||||||
}
|
// each key independently, since if the first boot was interrupted it is
|
||||||
|
// possible that the DE key exists but the CE key does not.
|
||||||
|
if (!de_key_exists(0) && !create_de_key(0, false)) return false;
|
||||||
|
if (!ce_key_exists(0) && !create_ce_key(0, false)) return false;
|
||||||
|
|
||||||
// TODO: switch to loading only DE_0 here once framework makes
|
// TODO: switch to loading only DE_0 here once framework makes
|
||||||
// explicit calls to install DE keys for secondary users
|
// explicit calls to install DE keys for secondary users
|
||||||
if (!load_all_de_keys()) return false;
|
if (!load_all_de_keys()) return false;
|
||||||
|
@ -613,9 +656,9 @@ bool fscrypt_vold_create_user_key(userid_t user_id, int serial, bool ephemeral)
|
||||||
// FIXME should we fail the command?
|
// FIXME should we fail the command?
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (!create_and_install_user_keys(user_id, ephemeral)) {
|
if (!create_de_key(user_id, ephemeral)) return false;
|
||||||
return false;
|
if (!create_ce_key(user_id, ephemeral)) return false;
|
||||||
}
|
if (ephemeral) s_ephemeral_users.insert(user_id);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -649,6 +692,7 @@ static bool evict_ce_key(userid_t user_id) {
|
||||||
drop_caches_if_needed();
|
drop_caches_if_needed();
|
||||||
}
|
}
|
||||||
s_ce_policies.erase(user_id);
|
s_ce_policies.erase(user_id);
|
||||||
|
s_new_ce_keys.erase(user_id);
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -663,14 +707,14 @@ bool fscrypt_destroy_user_key(userid_t user_id) {
|
||||||
success &= lookup_policy(s_de_policies, user_id, &de_policy) &&
|
success &= lookup_policy(s_de_policies, user_id, &de_policy) &&
|
||||||
android::vold::evictKey(DATA_MNT_POINT, de_policy);
|
android::vold::evictKey(DATA_MNT_POINT, de_policy);
|
||||||
s_de_policies.erase(user_id);
|
s_de_policies.erase(user_id);
|
||||||
auto it = s_ephemeral_users.find(user_id);
|
if (!s_ephemeral_users.erase(user_id)) {
|
||||||
if (it != s_ephemeral_users.end()) {
|
|
||||||
s_ephemeral_users.erase(it);
|
|
||||||
} else {
|
|
||||||
auto ce_path = get_ce_key_directory_path(user_id);
|
auto ce_path = get_ce_key_directory_path(user_id);
|
||||||
for (auto const path : get_ce_key_paths(ce_path)) {
|
if (!s_new_ce_keys.erase(user_id)) {
|
||||||
success &= android::vold::destroyKey(path);
|
for (auto const path : get_ce_key_paths(ce_path)) {
|
||||||
|
success &= android::vold::destroyKey(path);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
s_deferred_fixations.erase(ce_path);
|
||||||
success &= destroy_dir(ce_path);
|
success &= destroy_dir(ce_path);
|
||||||
|
|
||||||
auto de_key_path = get_de_key_path(user_id);
|
auto de_key_path = get_de_key_path(user_id);
|
||||||
|
@ -745,62 +789,102 @@ static bool destroy_volkey(const std::string& misc_path, const std::string& volu
|
||||||
return android::vold::destroyKey(path);
|
return android::vold::destroyKey(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool fscrypt_rewrap_user_key(userid_t user_id, int serial,
|
// (Re-)encrypts the user's CE key with the given secret. This function handles
|
||||||
const android::vold::KeyAuthentication& retrieve_auth,
|
// storing the CE key for a new user for the first time. It also handles
|
||||||
const android::vold::KeyAuthentication& store_auth) {
|
// re-encrypting the CE key upon upgrade from an Android version where the CE
|
||||||
if (s_ephemeral_users.count(user_id) != 0) return true;
|
// key was stored with kEmptyAuthentication when the user didn't have an LSKF.
|
||||||
auto const directory_path = get_ce_key_directory_path(user_id);
|
// See the comments below for the different cases handled.
|
||||||
KeyBuffer ce_key;
|
bool fscrypt_set_user_key_protection(userid_t user_id, const std::string& secret_hex) {
|
||||||
std::string ce_key_current_path = get_ce_key_current_path(directory_path);
|
LOG(DEBUG) << "fscrypt_set_user_key_protection " << user_id;
|
||||||
if (retrieveKey(ce_key_current_path, retrieve_auth, &ce_key)) {
|
if (!IsFbeEnabled()) return true;
|
||||||
LOG(DEBUG) << "Successfully retrieved key";
|
auto auth = authentication_from_hex(secret_hex);
|
||||||
// TODO(147732812): Remove this once Locksettingservice is fixed.
|
if (!auth) return false;
|
||||||
// Currently it calls fscrypt_clear_user_key_auth with a secret when lockscreen is
|
if (auth->secret.empty()) {
|
||||||
// changed from swipe to none or vice-versa
|
LOG(ERROR) << "fscrypt_set_user_key_protection: secret must be nonempty";
|
||||||
} else if (retrieveKey(ce_key_current_path, kEmptyAuthentication, &ce_key)) {
|
|
||||||
LOG(DEBUG) << "Successfully retrieved key with empty auth";
|
|
||||||
} else {
|
|
||||||
LOG(ERROR) << "Failed to retrieve key for user " << user_id;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
// We shouldn't store any keys for ephemeral users.
|
||||||
|
if (s_ephemeral_users.count(user_id) != 0) {
|
||||||
|
LOG(DEBUG) << "Not storing key because user is ephemeral";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
KeyBuffer ce_key;
|
||||||
|
auto it = s_new_ce_keys.find(user_id);
|
||||||
|
if (it != s_new_ce_keys.end()) {
|
||||||
|
// If the key exists in s_new_ce_keys, then the key is a
|
||||||
|
// not-yet-committed key for a new user, and we are committing it here.
|
||||||
|
// This happens when the user's synthetic password is created.
|
||||||
|
ce_key = it->second;
|
||||||
|
} else if (ce_key_exists(user_id)) {
|
||||||
|
// If the key doesn't exist in s_new_ce_keys but does exist on-disk,
|
||||||
|
// then we are setting the protection on an existing key. This happens
|
||||||
|
// at upgrade time, when CE keys that were previously protected by
|
||||||
|
// kEmptyAuthentication are encrypted by the user's synthetic password.
|
||||||
|
LOG(DEBUG) << "CE key already exists on-disk; re-protecting it with the given secret";
|
||||||
|
if (!read_and_fixate_user_ce_key(user_id, kEmptyAuthentication, &ce_key)) {
|
||||||
|
LOG(ERROR) << "Failed to retrieve CE key for user " << user_id << " using empty auth";
|
||||||
|
// Before failing, also check whether the key is already protected
|
||||||
|
// with the given secret. This isn't expected, but in theory it
|
||||||
|
// could happen if an upgrade is requested for a user more than once
|
||||||
|
// due to a power-off or other interruption.
|
||||||
|
if (read_and_fixate_user_ce_key(user_id, *auth, &ce_key)) {
|
||||||
|
LOG(WARNING) << "CE key is already protected by given secret";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// The key isn't protected by either kEmptyAuthentication or by
|
||||||
|
// |auth|. This should never happen, and there's nothing we can do
|
||||||
|
// besides return an error.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// If the key doesn't exist in memory or on-disk, then we need to
|
||||||
|
// generate it here, then commit it to disk. This is needed after the
|
||||||
|
// unusual case where a non-system user was created during early boot,
|
||||||
|
// and then the device was force-rebooted before the boot completed. In
|
||||||
|
// that case, the Android user record was committed but the CE key was
|
||||||
|
// not. So the CE key was lost, and we need to regenerate it. This
|
||||||
|
// should be fine, since the key should not have been used yet.
|
||||||
|
LOG(WARNING) << "CE key not found! Regenerating it";
|
||||||
|
if (!create_ce_key(user_id, false)) return false;
|
||||||
|
ce_key = s_new_ce_keys.find(user_id)->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto const directory_path = get_ce_key_directory_path(user_id);
|
||||||
auto const paths = get_ce_key_paths(directory_path);
|
auto const paths = get_ce_key_paths(directory_path);
|
||||||
std::string ce_key_path;
|
std::string ce_key_path;
|
||||||
if (!get_ce_key_new_path(directory_path, paths, &ce_key_path)) return false;
|
if (!get_ce_key_new_path(directory_path, paths, &ce_key_path)) return false;
|
||||||
if (!android::vold::storeKeyAtomically(ce_key_path, user_key_temp, store_auth, ce_key))
|
if (!android::vold::storeKeyAtomically(ce_key_path, user_key_temp, *auth, ce_key)) return false;
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool fscrypt_add_user_key_auth(userid_t user_id, int serial, const std::string& secret_hex) {
|
// Fixate the key, i.e. delete all other bindings of it. (In practice this
|
||||||
LOG(DEBUG) << "fscrypt_add_user_key_auth " << user_id << " serial=" << serial;
|
// just means the kEmptyAuthentication binding, if there is one.) However,
|
||||||
if (!IsFbeEnabled()) return true;
|
// if a userdata filesystem checkpoint is pending, then we need to delay the
|
||||||
auto auth = authentication_from_hex(secret_hex);
|
// fixation until the checkpoint has been committed, since deleting keys
|
||||||
if (!auth) return false;
|
// from Keystore cannot be rolled back.
|
||||||
return fscrypt_rewrap_user_key(user_id, serial, kEmptyAuthentication, *auth);
|
if (android::vold::cp_needsCheckpoint()) {
|
||||||
}
|
LOG(INFO) << "Deferring fixation of " << directory_path << " until checkpoint is committed";
|
||||||
|
s_deferred_fixations[directory_path] = ce_key_path;
|
||||||
bool fscrypt_clear_user_key_auth(userid_t user_id, int serial, const std::string& secret_hex) {
|
} else {
|
||||||
LOG(DEBUG) << "fscrypt_clear_user_key_auth " << user_id << " serial=" << serial;
|
s_deferred_fixations.erase(directory_path);
|
||||||
if (!IsFbeEnabled()) return true;
|
if (!fixate_user_ce_key(directory_path, ce_key_path, paths)) return false;
|
||||||
auto auth = authentication_from_hex(secret_hex);
|
}
|
||||||
if (!auth) return false;
|
|
||||||
return fscrypt_rewrap_user_key(user_id, serial, *auth, kEmptyAuthentication);
|
if (s_new_ce_keys.erase(user_id)) {
|
||||||
}
|
LOG(INFO) << "Stored CE key for new user " << user_id;
|
||||||
|
|
||||||
bool fscrypt_fixate_newest_user_key_auth(userid_t user_id) {
|
|
||||||
LOG(DEBUG) << "fscrypt_fixate_newest_user_key_auth " << user_id;
|
|
||||||
if (!IsFbeEnabled()) return true;
|
|
||||||
if (s_ephemeral_users.count(user_id) != 0) return true;
|
|
||||||
auto const directory_path = get_ce_key_directory_path(user_id);
|
|
||||||
auto const paths = get_ce_key_paths(directory_path);
|
|
||||||
if (paths.empty()) {
|
|
||||||
LOG(ERROR) << "No ce keys present, cannot fixate for user " << user_id;
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
fixate_user_ce_key(directory_path, paths[0], paths);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void fscrypt_deferred_fixate_ce_keys() {
|
||||||
|
for (const auto& it : s_deferred_fixations) {
|
||||||
|
const auto& directory_path = it.first;
|
||||||
|
const auto& to_fix = it.second;
|
||||||
|
LOG(INFO) << "Doing deferred fixation of " << directory_path;
|
||||||
|
fixate_user_ce_key(directory_path, to_fix, get_ce_key_paths(directory_path));
|
||||||
|
// Continue on error.
|
||||||
|
}
|
||||||
|
s_deferred_fixations.clear();
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<int> fscrypt_get_unlocked_users() {
|
std::vector<int> fscrypt_get_unlocked_users() {
|
||||||
std::vector<int> user_ids;
|
std::vector<int> user_ids;
|
||||||
for (const auto& it : s_ce_policies) {
|
for (const auto& it : s_ce_policies) {
|
||||||
|
|
|
@ -25,9 +25,8 @@ bool fscrypt_init_user0();
|
||||||
extern bool fscrypt_init_user0_done;
|
extern bool fscrypt_init_user0_done;
|
||||||
bool fscrypt_vold_create_user_key(userid_t user_id, int serial, bool ephemeral);
|
bool fscrypt_vold_create_user_key(userid_t user_id, int serial, bool ephemeral);
|
||||||
bool fscrypt_destroy_user_key(userid_t user_id);
|
bool fscrypt_destroy_user_key(userid_t user_id);
|
||||||
bool fscrypt_add_user_key_auth(userid_t user_id, int serial, const std::string& secret);
|
bool fscrypt_set_user_key_protection(userid_t user_id, const std::string& secret);
|
||||||
bool fscrypt_clear_user_key_auth(userid_t user_id, int serial, const std::string& secret);
|
void fscrypt_deferred_fixate_ce_keys();
|
||||||
bool fscrypt_fixate_newest_user_key_auth(userid_t user_id);
|
|
||||||
|
|
||||||
std::vector<int> fscrypt_get_unlocked_users();
|
std::vector<int> fscrypt_get_unlocked_users();
|
||||||
bool fscrypt_unlock_user_key(userid_t user_id, int serial, const std::string& secret);
|
bool fscrypt_unlock_user_key(userid_t user_id, int serial, const std::string& secret);
|
||||||
|
|
|
@ -23,7 +23,6 @@
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <thread>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
@ -231,9 +230,8 @@ static bool CommitUpgradedKey(Keystore& keystore, const std::string& dir) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void DeferredCommitKeys() {
|
void DeferredCommitKeystoreKeys() {
|
||||||
android::base::WaitForProperty("vold.checkpoint_committed", "1");
|
LOG(INFO) << "Committing upgraded Keystore keys";
|
||||||
LOG(INFO) << "Committing upgraded keys";
|
|
||||||
Keystore keystore;
|
Keystore keystore;
|
||||||
if (!keystore) {
|
if (!keystore) {
|
||||||
LOG(ERROR) << "Failed to open Keystore; old keys won't be deleted from Keystore";
|
LOG(ERROR) << "Failed to open Keystore; old keys won't be deleted from Keystore";
|
||||||
|
@ -241,10 +239,11 @@ static void DeferredCommitKeys() {
|
||||||
}
|
}
|
||||||
std::lock_guard<std::mutex> lock(key_upgrade_lock);
|
std::lock_guard<std::mutex> lock(key_upgrade_lock);
|
||||||
for (auto& dir : key_dirs_to_commit) {
|
for (auto& dir : key_dirs_to_commit) {
|
||||||
LOG(INFO) << "Committing upgraded key " << dir;
|
LOG(INFO) << "Committing upgraded Keystore key for " << dir;
|
||||||
CommitUpgradedKey(keystore, dir);
|
CommitUpgradedKey(keystore, dir);
|
||||||
}
|
}
|
||||||
key_dirs_to_commit.clear();
|
key_dirs_to_commit.clear();
|
||||||
|
LOG(INFO) << "Done committing upgraded Keystore keys";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns true if the Keystore key in |dir| has already been upgraded and is
|
// Returns true if the Keystore key in |dir| has already been upgraded and is
|
||||||
|
@ -260,7 +259,6 @@ static bool IsKeyCommitPending(const std::string& dir) {
|
||||||
// that key_upgrade_lock is held and that a commit isn't already pending for the
|
// that key_upgrade_lock is held and that a commit isn't already pending for the
|
||||||
// directory.
|
// directory.
|
||||||
static void ScheduleKeyCommit(const std::string& dir) {
|
static void ScheduleKeyCommit(const std::string& dir) {
|
||||||
if (key_dirs_to_commit.empty()) std::thread(DeferredCommitKeys).detach();
|
|
||||||
key_dirs_to_commit.push_back(dir);
|
key_dirs_to_commit.push_back(dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -592,7 +590,7 @@ bool storeKeyAtomically(const std::string& key_path, const std::string& tmp_path
|
||||||
if (!RenameKeyDir(tmp_path, key_path)) return false;
|
if (!RenameKeyDir(tmp_path, key_path)) return false;
|
||||||
|
|
||||||
if (!FsyncParentDirectory(key_path)) return false;
|
if (!FsyncParentDirectory(key_path)) return false;
|
||||||
LOG(DEBUG) << "Created key: " << key_path;
|
LOG(DEBUG) << "Stored key " << key_path;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -41,6 +41,8 @@ extern const KeyAuthentication kEmptyAuthentication;
|
||||||
bool createSecdiscardable(const std::string& path, std::string* hash);
|
bool createSecdiscardable(const std::string& path, std::string* hash);
|
||||||
bool readSecdiscardable(const std::string& path, std::string* hash);
|
bool readSecdiscardable(const std::string& path, std::string* hash);
|
||||||
|
|
||||||
|
void DeferredCommitKeystoreKeys();
|
||||||
|
|
||||||
// Renames a key directory while also managing deferred commits appropriately.
|
// Renames a key directory while also managing deferred commits appropriately.
|
||||||
// This method should be used whenever a key directory needs to be moved/renamed.
|
// This method should be used whenever a key directory needs to be moved/renamed.
|
||||||
bool RenameKeyDir(const std::string& old_name, const std::string& new_name);
|
bool RenameKeyDir(const std::string& old_name, const std::string& new_name);
|
||||||
|
|
53
Utils.cpp
53
Utils.cpp
|
@ -1771,24 +1771,45 @@ std::pair<android::base::unique_fd, std::string> OpenDirInProcfs(std::string_vie
|
||||||
return {std::move(fd), std::move(linkPath)};
|
return {std::move(fd), std::move(linkPath)};
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsFuseBpfEnabled() {
|
static bool IsPropertySet(const char* name, bool& value) {
|
||||||
// TODO Once kernel supports flag, trigger off kernel flag unless
|
if (base::GetProperty(name, "") == "") return false;
|
||||||
// ro.fuse.bpf.enabled is explicitly set to false
|
|
||||||
bool enabled;
|
|
||||||
if (base::GetProperty("ro.fuse.bpf.is_running", "") != "")
|
|
||||||
enabled = base::GetBoolProperty("ro.fuse.bpf.is_running", false);
|
|
||||||
else if (base::GetProperty("persist.sys.fuse.bpf.override", "") != "")
|
|
||||||
enabled = base::GetBoolProperty("persist.sys.fuse.bpf.override", false);
|
|
||||||
else
|
|
||||||
enabled = base::GetBoolProperty("ro.fuse.bpf.enabled", false);
|
|
||||||
|
|
||||||
if (enabled) {
|
value = base::GetBoolProperty(name, false);
|
||||||
base::SetProperty("ro.fuse.bpf.is_running", "true");
|
LOG(INFO) << "fuse-bpf is " << (value ? "enabled" : "disabled") << " because of property "
|
||||||
return true;
|
<< name;
|
||||||
} else {
|
return true;
|
||||||
base::SetProperty("ro.fuse.bpf.is_running", "false");
|
}
|
||||||
return false;
|
|
||||||
|
bool IsFuseBpfEnabled() {
|
||||||
|
// This logic is reproduced in packages/providers/MediaProvider/jni/FuseDaemon.cpp
|
||||||
|
// so changes made here must be reflected there
|
||||||
|
bool enabled = false;
|
||||||
|
|
||||||
|
if (IsPropertySet("ro.fuse.bpf.is_running", enabled)) return enabled;
|
||||||
|
|
||||||
|
if (!IsPropertySet("persist.sys.fuse.bpf.override", enabled) &&
|
||||||
|
!IsPropertySet("ro.fuse.bpf.enabled", enabled)) {
|
||||||
|
// If the kernel has fuse-bpf, /sys/fs/fuse/features/fuse_bpf will exist and have the
|
||||||
|
// contents 'supported\n' - see fs/fuse/inode.c in the kernel source
|
||||||
|
std::string contents;
|
||||||
|
const char* filename = "/sys/fs/fuse/features/fuse_bpf";
|
||||||
|
if (!base::ReadFileToString(filename, &contents)) {
|
||||||
|
LOG(INFO) << "fuse-bpf is disabled because " << filename << " cannot be read";
|
||||||
|
enabled = false;
|
||||||
|
} else if (contents == "supported\n") {
|
||||||
|
LOG(INFO) << "fuse-bpf is enabled because " << filename << " reads 'supported'";
|
||||||
|
enabled = true;
|
||||||
|
} else {
|
||||||
|
LOG(INFO) << "fuse-bpf is disabled because " << filename
|
||||||
|
<< " does not read 'supported'";
|
||||||
|
enabled = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string value = enabled ? "true" : "false";
|
||||||
|
LOG(INFO) << "Setting ro.fuse.bpf.is_running to " << value;
|
||||||
|
base::SetProperty("ro.fuse.bpf.is_running", value);
|
||||||
|
return enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace vold
|
} // namespace vold
|
||||||
|
|
|
@ -612,27 +612,11 @@ binder::Status VoldNativeService::destroyUserKey(int32_t userId) {
|
||||||
return translateBool(fscrypt_destroy_user_key(userId));
|
return translateBool(fscrypt_destroy_user_key(userId));
|
||||||
}
|
}
|
||||||
|
|
||||||
binder::Status VoldNativeService::addUserKeyAuth(int32_t userId, int32_t userSerial,
|
binder::Status VoldNativeService::setUserKeyProtection(int32_t userId, const std::string& secret) {
|
||||||
const std::string& secret) {
|
|
||||||
ENFORCE_SYSTEM_OR_ROOT;
|
ENFORCE_SYSTEM_OR_ROOT;
|
||||||
ACQUIRE_CRYPT_LOCK;
|
ACQUIRE_CRYPT_LOCK;
|
||||||
|
|
||||||
return translateBool(fscrypt_add_user_key_auth(userId, userSerial, secret));
|
return translateBool(fscrypt_set_user_key_protection(userId, secret));
|
||||||
}
|
|
||||||
|
|
||||||
binder::Status VoldNativeService::clearUserKeyAuth(int32_t userId, int32_t userSerial,
|
|
||||||
const std::string& secret) {
|
|
||||||
ENFORCE_SYSTEM_OR_ROOT;
|
|
||||||
ACQUIRE_CRYPT_LOCK;
|
|
||||||
|
|
||||||
return translateBool(fscrypt_clear_user_key_auth(userId, userSerial, secret));
|
|
||||||
}
|
|
||||||
|
|
||||||
binder::Status VoldNativeService::fixateNewestUserKeyAuth(int32_t userId) {
|
|
||||||
ENFORCE_SYSTEM_OR_ROOT;
|
|
||||||
ACQUIRE_CRYPT_LOCK;
|
|
||||||
|
|
||||||
return translateBool(fscrypt_fixate_newest_user_key_auth(userId));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
binder::Status VoldNativeService::getUnlockedUsers(std::vector<int>* _aidl_return) {
|
binder::Status VoldNativeService::getUnlockedUsers(std::vector<int>* _aidl_return) {
|
||||||
|
|
|
@ -115,9 +115,7 @@ class VoldNativeService : public BinderService<VoldNativeService>, public os::Bn
|
||||||
binder::Status createUserKey(int32_t userId, int32_t userSerial, bool ephemeral);
|
binder::Status createUserKey(int32_t userId, int32_t userSerial, bool ephemeral);
|
||||||
binder::Status destroyUserKey(int32_t userId);
|
binder::Status destroyUserKey(int32_t userId);
|
||||||
|
|
||||||
binder::Status addUserKeyAuth(int32_t userId, int32_t userSerial, const std::string& secret);
|
binder::Status setUserKeyProtection(int32_t userId, const std::string& secret);
|
||||||
binder::Status clearUserKeyAuth(int32_t userId, int32_t userSerial, const std::string& secret);
|
|
||||||
binder::Status fixateNewestUserKeyAuth(int32_t userId);
|
|
||||||
|
|
||||||
binder::Status getUnlockedUsers(std::vector<int>* _aidl_return);
|
binder::Status getUnlockedUsers(std::vector<int>* _aidl_return);
|
||||||
binder::Status unlockUserKey(int32_t userId, int32_t userSerial, const std::string& secret);
|
binder::Status unlockUserKey(int32_t userId, int32_t userSerial, const std::string& secret);
|
||||||
|
|
|
@ -88,9 +88,7 @@ interface IVold {
|
||||||
void createUserKey(int userId, int userSerial, boolean ephemeral);
|
void createUserKey(int userId, int userSerial, boolean ephemeral);
|
||||||
void destroyUserKey(int userId);
|
void destroyUserKey(int userId);
|
||||||
|
|
||||||
void addUserKeyAuth(int userId, int userSerial, @utf8InCpp String secret);
|
void setUserKeyProtection(int userId, @utf8InCpp String secret);
|
||||||
void clearUserKeyAuth(int userId, int userSerial, @utf8InCpp String secret);
|
|
||||||
void fixateNewestUserKeyAuth(int userId);
|
|
||||||
|
|
||||||
int[] getUnlockedUsers();
|
int[] getUnlockedUsers();
|
||||||
void unlockUserKey(int userId, int userSerial, @utf8InCpp String secret);
|
void unlockUserKey(int userId, int userSerial, @utf8InCpp String secret);
|
||||||
|
|
Loading…
Reference in a new issue