Replace manual dm ioctls with libdm.
This mostly 1:1 replaces manual ioctls to device-mapper with calls to libdm. There were two exceptions: (1) There is a very old table-load-retry loop to workaround issues with umount (b/7220345). This loop has been preserved, however, it now includes DM_DEV_CREATE as well as DM_TABLE_LOAD. (2) There was some ancient code to set DM_DEV_GEOMETRY for obb dm-devices. This never did anything since geometry must be set after loading a table. When setting it before (as vold was doing), the subsequent DM_TABLE_LOAD will clear it. Bug: 132206403 Test: FBE device boots FBE device w/ metadata encryption boots FDE device boots atest StorageManagerIntegrationTest Change-Id: Ib6db6b47329f093ac7084edaf604eddace8b9ac6
This commit is contained in:
parent
19e74b3d1f
commit
b92247368a
5 changed files with 91 additions and 485 deletions
|
@ -30,6 +30,7 @@ cc_defaults {
|
|||
static_libs: [
|
||||
"libavb",
|
||||
"libbootloader_message",
|
||||
"libdm",
|
||||
"libfec",
|
||||
"libfec_rs",
|
||||
"libfs_avb",
|
||||
|
|
220
Devmapper.cpp
220
Devmapper.cpp
|
@ -23,7 +23,6 @@
|
|||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
|
@ -32,239 +31,72 @@
|
|||
#include <android-base/logging.h>
|
||||
#include <android-base/stringprintf.h>
|
||||
#include <android-base/strings.h>
|
||||
#include <libdm/dm.h>
|
||||
#include <utils/Trace.h>
|
||||
|
||||
#include "Devmapper.h"
|
||||
|
||||
#define DEVMAPPER_BUFFER_SIZE 4096
|
||||
|
||||
using android::base::StringPrintf;
|
||||
using namespace android::dm;
|
||||
|
||||
static const char* kVoldPrefix = "vold:";
|
||||
|
||||
void Devmapper::ioctlInit(struct dm_ioctl* io, size_t dataSize, const char* name, unsigned flags) {
|
||||
memset(io, 0, dataSize);
|
||||
io->data_size = dataSize;
|
||||
io->data_start = sizeof(struct dm_ioctl);
|
||||
io->version[0] = 4;
|
||||
io->version[1] = 0;
|
||||
io->version[2] = 0;
|
||||
io->flags = flags;
|
||||
if (name) {
|
||||
size_t ret = strlcpy(io->name, name, sizeof(io->name));
|
||||
if (ret >= sizeof(io->name)) abort();
|
||||
}
|
||||
}
|
||||
|
||||
int Devmapper::create(const char* name_raw, const char* loopFile, const char* key,
|
||||
unsigned long numSectors, char* ubuffer, size_t len) {
|
||||
auto& dm = DeviceMapper::Instance();
|
||||
auto name_string = StringPrintf("%s%s", kVoldPrefix, name_raw);
|
||||
const char* name = name_string.c_str();
|
||||
|
||||
char* buffer = (char*)malloc(DEVMAPPER_BUFFER_SIZE);
|
||||
if (!buffer) {
|
||||
PLOG(ERROR) << "Failed malloc";
|
||||
DmTable table;
|
||||
table.Emplace<DmTargetCrypt>(0, numSectors, "twofish", key, 0, loopFile, 0);
|
||||
|
||||
if (!dm.CreateDevice(name_string, table)) {
|
||||
LOG(ERROR) << "Failed to create device-mapper device " << name_string;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int fd;
|
||||
if ((fd = open("/dev/device-mapper", O_RDWR | O_CLOEXEC)) < 0) {
|
||||
PLOG(ERROR) << "Failed open";
|
||||
free(buffer);
|
||||
std::string path;
|
||||
if (!dm.GetDmDevicePathByName(name_string, &path)) {
|
||||
LOG(ERROR) << "Failed to get device-mapper device path for " << name_string;
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct dm_ioctl* io = (struct dm_ioctl*)buffer;
|
||||
|
||||
// Create the DM device
|
||||
ioctlInit(io, DEVMAPPER_BUFFER_SIZE, name, 0);
|
||||
|
||||
if (ioctl(fd, DM_DEV_CREATE, io)) {
|
||||
PLOG(ERROR) << "Failed DM_DEV_CREATE";
|
||||
free(buffer);
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Set the legacy geometry
|
||||
ioctlInit(io, DEVMAPPER_BUFFER_SIZE, name, 0);
|
||||
|
||||
char* geoParams = buffer + sizeof(struct dm_ioctl);
|
||||
// bps=512 spc=8 res=32 nft=2 sec=8190 mid=0xf0 spt=63 hds=64 hid=0 bspf=8 rdcl=2 infs=1 bkbs=2
|
||||
strlcpy(geoParams, "0 64 63 0", DEVMAPPER_BUFFER_SIZE - sizeof(struct dm_ioctl));
|
||||
geoParams += strlen(geoParams) + 1;
|
||||
geoParams = (char*)_align(geoParams, 8);
|
||||
if (ioctl(fd, DM_DEV_SET_GEOMETRY, io)) {
|
||||
PLOG(ERROR) << "Failed DM_DEV_SET_GEOMETRY";
|
||||
free(buffer);
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Retrieve the device number we were allocated
|
||||
ioctlInit(io, DEVMAPPER_BUFFER_SIZE, name, 0);
|
||||
if (ioctl(fd, DM_DEV_STATUS, io)) {
|
||||
PLOG(ERROR) << "Failed DM_DEV_STATUS";
|
||||
free(buffer);
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
unsigned minor = (io->dev & 0xff) | ((io->dev >> 12) & 0xfff00);
|
||||
snprintf(ubuffer, len, "/dev/block/dm-%u", minor);
|
||||
|
||||
// Load the table
|
||||
struct dm_target_spec* tgt;
|
||||
tgt = (struct dm_target_spec*)&buffer[sizeof(struct dm_ioctl)];
|
||||
|
||||
ioctlInit(io, DEVMAPPER_BUFFER_SIZE, name, DM_STATUS_TABLE_FLAG);
|
||||
io->target_count = 1;
|
||||
tgt->status = 0;
|
||||
|
||||
tgt->sector_start = 0;
|
||||
tgt->length = numSectors;
|
||||
|
||||
strlcpy(tgt->target_type, "crypt", sizeof(tgt->target_type));
|
||||
|
||||
char* cryptParams = buffer + sizeof(struct dm_ioctl) + sizeof(struct dm_target_spec);
|
||||
snprintf(cryptParams,
|
||||
DEVMAPPER_BUFFER_SIZE - (sizeof(struct dm_ioctl) + sizeof(struct dm_target_spec)),
|
||||
"twofish %s 0 %s 0", key, loopFile);
|
||||
cryptParams += strlen(cryptParams) + 1;
|
||||
cryptParams = (char*)_align(cryptParams, 8);
|
||||
tgt->next = cryptParams - buffer;
|
||||
|
||||
if (ioctl(fd, DM_TABLE_LOAD, io)) {
|
||||
PLOG(ERROR) << "Failed DM_TABLE_LOAD";
|
||||
free(buffer);
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Resume the new table
|
||||
ioctlInit(io, DEVMAPPER_BUFFER_SIZE, name, 0);
|
||||
|
||||
if (ioctl(fd, DM_DEV_SUSPEND, io)) {
|
||||
PLOG(ERROR) << "Failed DM_DEV_SUSPEND";
|
||||
free(buffer);
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free(buffer);
|
||||
|
||||
close(fd);
|
||||
snprintf(ubuffer, len, "%s", path.c_str());
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Devmapper::destroy(const char* name_raw) {
|
||||
auto& dm = DeviceMapper::Instance();
|
||||
|
||||
auto name_string = StringPrintf("%s%s", kVoldPrefix, name_raw);
|
||||
const char* name = name_string.c_str();
|
||||
|
||||
char* buffer = (char*)malloc(DEVMAPPER_BUFFER_SIZE);
|
||||
if (!buffer) {
|
||||
PLOG(ERROR) << "Failed malloc";
|
||||
return -1;
|
||||
}
|
||||
|
||||
int fd;
|
||||
if ((fd = open("/dev/device-mapper", O_RDWR | O_CLOEXEC)) < 0) {
|
||||
PLOG(ERROR) << "Failed open";
|
||||
free(buffer);
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct dm_ioctl* io = (struct dm_ioctl*)buffer;
|
||||
|
||||
// Create the DM device
|
||||
ioctlInit(io, DEVMAPPER_BUFFER_SIZE, name, 0);
|
||||
|
||||
if (ioctl(fd, DM_DEV_REMOVE, io)) {
|
||||
if (!dm.DeleteDevice(name_string)) {
|
||||
if (errno != ENXIO) {
|
||||
PLOG(ERROR) << "Failed DM_DEV_REMOVE";
|
||||
}
|
||||
free(buffer);
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free(buffer);
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Devmapper::destroyAll() {
|
||||
ATRACE_NAME("Devmapper::destroyAll");
|
||||
char* buffer = (char*)malloc(1024 * 64);
|
||||
if (!buffer) {
|
||||
PLOG(ERROR) << "Failed malloc";
|
||||
return -1;
|
||||
}
|
||||
memset(buffer, 0, (1024 * 64));
|
||||
|
||||
char* buffer2 = (char*)malloc(DEVMAPPER_BUFFER_SIZE);
|
||||
if (!buffer2) {
|
||||
PLOG(ERROR) << "Failed malloc";
|
||||
free(buffer);
|
||||
auto& dm = DeviceMapper::Instance();
|
||||
std::vector<DeviceMapper::DmBlockDevice> devices;
|
||||
if (!dm.GetAvailableDevices(&devices)) {
|
||||
LOG(ERROR) << "Failed to get dm devices";
|
||||
return -1;
|
||||
}
|
||||
|
||||
int fd;
|
||||
if ((fd = open("/dev/device-mapper", O_RDWR | O_CLOEXEC)) < 0) {
|
||||
PLOG(ERROR) << "Failed open";
|
||||
free(buffer);
|
||||
free(buffer2);
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct dm_ioctl* io = (struct dm_ioctl*)buffer;
|
||||
ioctlInit(io, (1024 * 64), NULL, 0);
|
||||
|
||||
if (ioctl(fd, DM_LIST_DEVICES, io)) {
|
||||
PLOG(ERROR) << "Failed DM_LIST_DEVICES";
|
||||
free(buffer);
|
||||
free(buffer2);
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct dm_name_list* n = (struct dm_name_list*)(((char*)buffer) + io->data_start);
|
||||
if (!n->dev) {
|
||||
free(buffer);
|
||||
free(buffer2);
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned nxt = 0;
|
||||
do {
|
||||
n = (struct dm_name_list*)(((char*)n) + nxt);
|
||||
auto name = std::string(n->name);
|
||||
if (android::base::StartsWith(name, kVoldPrefix)) {
|
||||
LOG(DEBUG) << "Tearing down stale dm device named " << name;
|
||||
|
||||
memset(buffer2, 0, DEVMAPPER_BUFFER_SIZE);
|
||||
struct dm_ioctl* io2 = (struct dm_ioctl*)buffer2;
|
||||
ioctlInit(io2, DEVMAPPER_BUFFER_SIZE, n->name, 0);
|
||||
if (ioctl(fd, DM_DEV_REMOVE, io2)) {
|
||||
for (const auto& device : devices) {
|
||||
if (android::base::StartsWith(device.name(), kVoldPrefix)) {
|
||||
LOG(DEBUG) << "Tearing down stale dm device named " << device.name();
|
||||
if (!dm.DeleteDevice(device.name())) {
|
||||
if (errno != ENXIO) {
|
||||
PLOG(WARNING) << "Failed to destroy dm device named " << name;
|
||||
PLOG(WARNING) << "Failed to destroy dm device named " << device.name();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
LOG(DEBUG) << "Found unmanaged dm device named " << name;
|
||||
LOG(DEBUG) << "Found unmanaged dm device named " << device.name();
|
||||
}
|
||||
nxt = n->next;
|
||||
} while (nxt);
|
||||
|
||||
free(buffer);
|
||||
free(buffer2);
|
||||
close(fd);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void* Devmapper::_align(void* ptr, unsigned int a) {
|
||||
unsigned long agn = --a;
|
||||
|
||||
return (void*)(((unsigned long)ptr + agn) & ~agn);
|
||||
}
|
||||
|
|
|
@ -26,10 +26,6 @@ class Devmapper {
|
|||
unsigned long numSectors, char* buffer, size_t len);
|
||||
static int destroy(const char* name);
|
||||
static int destroyAll();
|
||||
|
||||
private:
|
||||
static void* _align(void* ptr, unsigned int a);
|
||||
static void ioctlInit(struct dm_ioctl* io, size_t data_size, const char* name, unsigned flags);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -23,19 +23,17 @@
|
|||
#include <vector>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <linux/dm-ioctl.h>
|
||||
|
||||
#include <android-base/file.h>
|
||||
#include <android-base/logging.h>
|
||||
#include <android-base/properties.h>
|
||||
#include <android-base/unique_fd.h>
|
||||
#include <cutils/fs.h>
|
||||
#include <fs_mgr.h>
|
||||
#include <libdm/dm.h>
|
||||
|
||||
#include "Checkpoint.h"
|
||||
#include "EncryptInplace.h"
|
||||
|
@ -45,13 +43,12 @@
|
|||
#include "Utils.h"
|
||||
#include "VoldUtil.h"
|
||||
|
||||
#define DM_CRYPT_BUF_SIZE 4096
|
||||
#define TABLE_LOAD_RETRIES 10
|
||||
#define DEFAULT_KEY_TARGET_TYPE "default-key"
|
||||
|
||||
using android::fs_mgr::FstabEntry;
|
||||
using android::fs_mgr::GetEntryForMountPoint;
|
||||
using android::vold::KeyBuffer;
|
||||
using namespace android::dm;
|
||||
|
||||
static const std::string kDmNameUserdata = "userdata";
|
||||
|
||||
|
@ -146,16 +143,6 @@ static bool read_key(const FstabEntry& data_rec, bool create_if_absent, KeyBuffe
|
|||
} // namespace vold
|
||||
} // namespace android
|
||||
|
||||
static KeyBuffer default_key_params(const std::string& real_blkdev, const KeyBuffer& key) {
|
||||
KeyBuffer hex_key;
|
||||
if (android::vold::StrToHex(key, hex_key) != android::OK) {
|
||||
LOG(ERROR) << "Failed to turn key to hex";
|
||||
return KeyBuffer();
|
||||
}
|
||||
auto res = KeyBuffer() + "AES-256-XTS " + hex_key + " " + real_blkdev.c_str() + " 0";
|
||||
return res;
|
||||
}
|
||||
|
||||
static bool get_number_of_sectors(const std::string& real_blkdev, uint64_t* nr_sec) {
|
||||
if (android::vold::GetBlockDev512Sectors(real_blkdev, nr_sec) != android::OK) {
|
||||
PLOG(ERROR) << "Unable to measure size of " << real_blkdev;
|
||||
|
@ -164,86 +151,35 @@ static bool get_number_of_sectors(const std::string& real_blkdev, uint64_t* nr_s
|
|||
return true;
|
||||
}
|
||||
|
||||
static struct dm_ioctl* dm_ioctl_init(char* buffer, size_t buffer_size, const std::string& dm_name) {
|
||||
if (buffer_size < sizeof(dm_ioctl)) {
|
||||
LOG(ERROR) << "dm_ioctl buffer too small";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
memset(buffer, 0, buffer_size);
|
||||
struct dm_ioctl* io = (struct dm_ioctl*)buffer;
|
||||
io->data_size = buffer_size;
|
||||
io->data_start = sizeof(struct dm_ioctl);
|
||||
io->version[0] = 4;
|
||||
io->version[1] = 0;
|
||||
io->version[2] = 0;
|
||||
io->flags = 0;
|
||||
dm_name.copy(io->name, sizeof(io->name));
|
||||
return io;
|
||||
}
|
||||
|
||||
static bool create_crypto_blk_dev(const std::string& dm_name, uint64_t nr_sec,
|
||||
const std::string& target_type, const KeyBuffer& crypt_params,
|
||||
const std::string& real_blkdev, const KeyBuffer& key,
|
||||
std::string* crypto_blkdev) {
|
||||
android::base::unique_fd dm_fd(
|
||||
TEMP_FAILURE_RETRY(open("/dev/device-mapper", O_RDWR | O_CLOEXEC, 0)));
|
||||
if (dm_fd == -1) {
|
||||
PLOG(ERROR) << "Cannot open device-mapper";
|
||||
return false;
|
||||
}
|
||||
alignas(struct dm_ioctl) char buffer[DM_CRYPT_BUF_SIZE];
|
||||
auto io = dm_ioctl_init(buffer, sizeof(buffer), dm_name);
|
||||
if (!io || ioctl(dm_fd.get(), DM_DEV_CREATE, io) != 0) {
|
||||
PLOG(ERROR) << "Cannot create dm-crypt device " << dm_name;
|
||||
auto& dm = DeviceMapper::Instance();
|
||||
|
||||
KeyBuffer hex_key_buffer;
|
||||
if (android::vold::StrToHex(key, hex_key_buffer) != android::OK) {
|
||||
LOG(ERROR) << "Failed to turn key to hex";
|
||||
return false;
|
||||
}
|
||||
std::string hex_key(hex_key_buffer.data(), hex_key_buffer.size());
|
||||
|
||||
// Get the device status, in particular, the name of its device file
|
||||
io = dm_ioctl_init(buffer, sizeof(buffer), dm_name);
|
||||
if (ioctl(dm_fd.get(), DM_DEV_STATUS, io) != 0) {
|
||||
PLOG(ERROR) << "Cannot retrieve dm-crypt device status " << dm_name;
|
||||
return false;
|
||||
}
|
||||
*crypto_blkdev = std::string() + "/dev/block/dm-" +
|
||||
std::to_string((io->dev & 0xff) | ((io->dev >> 12) & 0xfff00));
|
||||
|
||||
io = dm_ioctl_init(buffer, sizeof(buffer), dm_name);
|
||||
size_t paramix = io->data_start + sizeof(struct dm_target_spec);
|
||||
size_t nullix = paramix + crypt_params.size();
|
||||
size_t endix = (nullix + 1 + 7) & 8; // Add room for \0 and align to 8 byte boundary
|
||||
|
||||
if (endix > sizeof(buffer)) {
|
||||
LOG(ERROR) << "crypt_params too big for DM_CRYPT_BUF_SIZE";
|
||||
return false;
|
||||
}
|
||||
|
||||
io->target_count = 1;
|
||||
auto tgt = (struct dm_target_spec*)(buffer + io->data_start);
|
||||
tgt->status = 0;
|
||||
tgt->sector_start = 0;
|
||||
tgt->length = nr_sec;
|
||||
target_type.copy(tgt->target_type, sizeof(tgt->target_type));
|
||||
memcpy(buffer + paramix, crypt_params.data(),
|
||||
std::min(crypt_params.size(), sizeof(buffer) - paramix));
|
||||
buffer[nullix] = '\0';
|
||||
tgt->next = endix;
|
||||
DmTable table;
|
||||
table.Emplace<DmTargetDefaultKey>(0, nr_sec, "AES-256-XTS", hex_key, real_blkdev, 0);
|
||||
|
||||
for (int i = 0;; i++) {
|
||||
if (ioctl(dm_fd.get(), DM_TABLE_LOAD, io) == 0) {
|
||||
if (dm.CreateDevice(dm_name, table)) {
|
||||
break;
|
||||
}
|
||||
if (i + 1 >= TABLE_LOAD_RETRIES) {
|
||||
PLOG(ERROR) << "DM_TABLE_LOAD ioctl failed";
|
||||
LOG(ERROR) << "Could not create default-key device " << dm_name;
|
||||
return false;
|
||||
}
|
||||
PLOG(INFO) << "DM_TABLE_LOAD ioctl failed, retrying";
|
||||
PLOG(INFO) << "Could not create default-key device, retrying";
|
||||
usleep(500000);
|
||||
}
|
||||
|
||||
// Resume this device to activate it
|
||||
io = dm_ioctl_init(buffer, sizeof(buffer), dm_name);
|
||||
if (ioctl(dm_fd.get(), DM_DEV_SUSPEND, io)) {
|
||||
PLOG(ERROR) << "Cannot resume dm-crypt device " << dm_name;
|
||||
if (!dm.GetDmDevicePathByName(dm_name, crypto_blkdev)) {
|
||||
LOG(ERROR) << "Cannot retrieve default-key device status " << dm_name;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -267,8 +203,7 @@ bool fscrypt_mount_metadata_encrypted(const std::string& mount_point, bool needs
|
|||
uint64_t nr_sec;
|
||||
if (!get_number_of_sectors(data_rec->blk_device, &nr_sec)) return false;
|
||||
std::string crypto_blkdev;
|
||||
if (!create_crypto_blk_dev(kDmNameUserdata, nr_sec, DEFAULT_KEY_TARGET_TYPE,
|
||||
default_key_params(data_rec->blk_device, key), &crypto_blkdev))
|
||||
if (!create_crypto_blk_dev(kDmNameUserdata, nr_sec, data_rec->blk_device, key, &crypto_blkdev))
|
||||
return false;
|
||||
// FIXME handle the corrupt case
|
||||
if (needs_encrypt) {
|
||||
|
|
252
cryptfs.cpp
252
cryptfs.cpp
|
@ -45,6 +45,7 @@
|
|||
#include <fs_mgr.h>
|
||||
#include <fscrypt/fscrypt.h>
|
||||
#include <hardware_legacy/power.h>
|
||||
#include <libdm/dm.h>
|
||||
#include <log/log.h>
|
||||
#include <logwrap/logwrap.h>
|
||||
#include <openssl/evp.h>
|
||||
|
@ -56,13 +57,11 @@
|
|||
#include <fcntl.h>
|
||||
#include <inttypes.h>
|
||||
#include <libgen.h>
|
||||
#include <linux/dm-ioctl.h>
|
||||
#include <linux/kdev_t.h>
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/stat.h>
|
||||
|
@ -78,12 +77,11 @@ extern "C" {
|
|||
using android::base::ParseUint;
|
||||
using android::base::StringPrintf;
|
||||
using android::fs_mgr::GetEntryForMountPoint;
|
||||
using namespace android::dm;
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
#define UNUSED __attribute__((unused))
|
||||
|
||||
#define DM_CRYPT_BUF_SIZE 4096
|
||||
|
||||
#define HASH_COUNT 2000
|
||||
|
||||
constexpr size_t INTERMEDIATE_KEY_LEN_BYTES = 16;
|
||||
|
@ -253,19 +251,6 @@ static void cryptfs_reboot(RebootType rt) {
|
|||
return;
|
||||
}
|
||||
|
||||
static void ioctl_init(struct dm_ioctl* io, size_t dataSize, const char* name, unsigned flags) {
|
||||
memset(io, 0, dataSize);
|
||||
io->data_size = dataSize;
|
||||
io->data_start = sizeof(struct dm_ioctl);
|
||||
io->version[0] = 4;
|
||||
io->version[1] = 0;
|
||||
io->version[2] = 0;
|
||||
io->flags = flags;
|
||||
if (name) {
|
||||
strlcpy(io->name, name, sizeof(io->name));
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
struct CryptoType;
|
||||
|
@ -973,109 +958,12 @@ static void convert_key_to_hex_ascii(const unsigned char* master_key, unsigned i
|
|||
master_key_ascii[a] = '\0';
|
||||
}
|
||||
|
||||
static int load_crypto_mapping_table(struct crypt_mnt_ftr* crypt_ftr,
|
||||
const unsigned char* master_key, const char* real_blk_name,
|
||||
const char* name, int fd, const char* extra_params) {
|
||||
alignas(struct dm_ioctl) char buffer[DM_CRYPT_BUF_SIZE];
|
||||
struct dm_ioctl* io;
|
||||
struct dm_target_spec* tgt;
|
||||
char* crypt_params;
|
||||
// We need two ASCII characters to represent each byte, and need space for
|
||||
// the '\0' terminator.
|
||||
char master_key_ascii[MAX_KEY_LEN * 2 + 1];
|
||||
size_t buff_offset;
|
||||
int i;
|
||||
|
||||
io = (struct dm_ioctl*)buffer;
|
||||
|
||||
/* Load the mapping table for this device */
|
||||
tgt = (struct dm_target_spec*)&buffer[sizeof(struct dm_ioctl)];
|
||||
|
||||
ioctl_init(io, DM_CRYPT_BUF_SIZE, name, 0);
|
||||
io->target_count = 1;
|
||||
tgt->status = 0;
|
||||
tgt->sector_start = 0;
|
||||
tgt->length = crypt_ftr->fs_size;
|
||||
strlcpy(tgt->target_type, "crypt", DM_MAX_TYPE_NAME);
|
||||
|
||||
crypt_params = buffer + sizeof(struct dm_ioctl) + sizeof(struct dm_target_spec);
|
||||
convert_key_to_hex_ascii(master_key, crypt_ftr->keysize, master_key_ascii);
|
||||
|
||||
buff_offset = crypt_params - buffer;
|
||||
SLOGI(
|
||||
"Creating crypto dev \"%s\"; cipher=%s, keysize=%u, real_dev=%s, len=%llu, params=\"%s\"\n",
|
||||
name, crypt_ftr->crypto_type_name, crypt_ftr->keysize, real_blk_name, tgt->length * 512,
|
||||
extra_params);
|
||||
snprintf(crypt_params, sizeof(buffer) - buff_offset, "%s %s 0 %s 0 %s",
|
||||
crypt_ftr->crypto_type_name, master_key_ascii, real_blk_name, extra_params);
|
||||
crypt_params += strlen(crypt_params) + 1;
|
||||
crypt_params =
|
||||
(char*)(((unsigned long)crypt_params + 7) & ~8); /* Align to an 8 byte boundary */
|
||||
tgt->next = crypt_params - buffer;
|
||||
|
||||
for (i = 0; i < TABLE_LOAD_RETRIES; i++) {
|
||||
if (!ioctl(fd, DM_TABLE_LOAD, io)) {
|
||||
break;
|
||||
}
|
||||
usleep(500000);
|
||||
}
|
||||
|
||||
if (i == TABLE_LOAD_RETRIES) {
|
||||
/* We failed to load the table, return an error */
|
||||
return -1;
|
||||
} else {
|
||||
return i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
static int get_dm_crypt_version(int fd, const char* name, int* version) {
|
||||
char buffer[DM_CRYPT_BUF_SIZE];
|
||||
struct dm_ioctl* io;
|
||||
struct dm_target_versions* v;
|
||||
|
||||
io = (struct dm_ioctl*)buffer;
|
||||
|
||||
ioctl_init(io, DM_CRYPT_BUF_SIZE, name, 0);
|
||||
|
||||
if (ioctl(fd, DM_LIST_VERSIONS, io)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Iterate over the returned versions, looking for name of "crypt".
|
||||
* When found, get and return the version.
|
||||
*/
|
||||
v = (struct dm_target_versions*)&buffer[sizeof(struct dm_ioctl)];
|
||||
while (v->next) {
|
||||
if (!strcmp(v->name, "crypt")) {
|
||||
/* We found the crypt driver, return the version, and get out */
|
||||
version[0] = v->version[0];
|
||||
version[1] = v->version[1];
|
||||
version[2] = v->version[2];
|
||||
return 0;
|
||||
}
|
||||
v = (struct dm_target_versions*)(((char*)v) + v->next);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static std::string extra_params_as_string(const std::vector<std::string>& extra_params_vec) {
|
||||
if (extra_params_vec.empty()) return "";
|
||||
std::string extra_params = std::to_string(extra_params_vec.size());
|
||||
for (const auto& p : extra_params_vec) {
|
||||
extra_params.append(" ");
|
||||
extra_params.append(p);
|
||||
}
|
||||
return extra_params;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the ro.crypto.fde_sector_size system property is set, append the
|
||||
* parameters to make dm-crypt use the specified crypto sector size and round
|
||||
* the crypto device size down to a crypto sector boundary.
|
||||
*/
|
||||
static int add_sector_size_param(std::vector<std::string>* extra_params_vec,
|
||||
struct crypt_mnt_ftr* ftr) {
|
||||
static int add_sector_size_param(DmTargetCrypt* target, struct crypt_mnt_ftr* ftr) {
|
||||
constexpr char DM_CRYPT_SECTOR_SIZE[] = "ro.crypto.fde_sector_size";
|
||||
char value[PROPERTY_VALUE_MAX];
|
||||
|
||||
|
@ -1089,12 +977,11 @@ static int add_sector_size_param(std::vector<std::string>* extra_params_vec,
|
|||
return -1;
|
||||
}
|
||||
|
||||
std::string param = StringPrintf("sector_size:%u", sector_size);
|
||||
extra_params_vec->push_back(std::move(param));
|
||||
target->SetSectorSize(sector_size);
|
||||
|
||||
// With this option, IVs will match the sector numbering, instead
|
||||
// of being hard-coded to being based on 512-byte sectors.
|
||||
extra_params_vec->emplace_back("iv_large_sectors");
|
||||
target->SetIvLargeSectors();
|
||||
|
||||
// Round the crypto device size down to a crypto sector boundary.
|
||||
ftr->fs_size &= ~((sector_size / 512) - 1);
|
||||
|
@ -1105,112 +992,67 @@ static int add_sector_size_param(std::vector<std::string>* extra_params_vec,
|
|||
static int create_crypto_blk_dev(struct crypt_mnt_ftr* crypt_ftr, const unsigned char* master_key,
|
||||
const char* real_blk_name, char* crypto_blk_name, const char* name,
|
||||
uint32_t flags) {
|
||||
char buffer[DM_CRYPT_BUF_SIZE];
|
||||
struct dm_ioctl* io;
|
||||
unsigned int minor;
|
||||
int fd = 0;
|
||||
int err;
|
||||
int retval = -1;
|
||||
int version[3];
|
||||
int load_count;
|
||||
std::vector<std::string> extra_params_vec;
|
||||
auto& dm = DeviceMapper::Instance();
|
||||
|
||||
if ((fd = open("/dev/device-mapper", O_RDWR | O_CLOEXEC)) < 0) {
|
||||
SLOGE("Cannot open device-mapper\n");
|
||||
goto errout;
|
||||
}
|
||||
// We need two ASCII characters to represent each byte, and need space for
|
||||
// the '\0' terminator.
|
||||
char master_key_ascii[MAX_KEY_LEN * 2 + 1];
|
||||
convert_key_to_hex_ascii(master_key, crypt_ftr->keysize, master_key_ascii);
|
||||
|
||||
io = (struct dm_ioctl*)buffer;
|
||||
auto target = std::make_unique<DmTargetCrypt>(0, crypt_ftr->fs_size,
|
||||
(const char*)crypt_ftr->crypto_type_name,
|
||||
master_key_ascii, 0, real_blk_name, 0);
|
||||
target->AllowDiscards();
|
||||
|
||||
ioctl_init(io, DM_CRYPT_BUF_SIZE, name, 0);
|
||||
err = ioctl(fd, DM_DEV_CREATE, io);
|
||||
if (err) {
|
||||
SLOGE("Cannot create dm-crypt device %s: %s\n", name, strerror(errno));
|
||||
goto errout;
|
||||
}
|
||||
|
||||
/* Get the device status, in particular, the name of it's device file */
|
||||
ioctl_init(io, DM_CRYPT_BUF_SIZE, name, 0);
|
||||
if (ioctl(fd, DM_DEV_STATUS, io)) {
|
||||
SLOGE("Cannot retrieve dm-crypt device status\n");
|
||||
goto errout;
|
||||
}
|
||||
minor = (io->dev & 0xff) | ((io->dev >> 12) & 0xfff00);
|
||||
snprintf(crypto_blk_name, MAXPATHLEN, "/dev/block/dm-%u", minor);
|
||||
|
||||
if (!get_dm_crypt_version(fd, name, version)) {
|
||||
/* Support for allow_discards was added in version 1.11.0 */
|
||||
if ((version[0] >= 2) || ((version[0] == 1) && (version[1] >= 11))) {
|
||||
extra_params_vec.emplace_back("allow_discards");
|
||||
}
|
||||
}
|
||||
if (flags & CREATE_CRYPTO_BLK_DEV_FLAGS_ALLOW_ENCRYPT_OVERRIDE) {
|
||||
extra_params_vec.emplace_back("allow_encrypt_override");
|
||||
target->AllowEncryptOverride();
|
||||
}
|
||||
if (add_sector_size_param(&extra_params_vec, crypt_ftr)) {
|
||||
if (add_sector_size_param(target.get(), crypt_ftr)) {
|
||||
SLOGE("Error processing dm-crypt sector size param\n");
|
||||
goto errout;
|
||||
return -1;
|
||||
}
|
||||
load_count = load_crypto_mapping_table(crypt_ftr, master_key, real_blk_name, name, fd,
|
||||
extra_params_as_string(extra_params_vec).c_str());
|
||||
if (load_count < 0) {
|
||||
|
||||
DmTable table;
|
||||
table.AddTarget(std::move(target));
|
||||
|
||||
int load_count = 1;
|
||||
while (load_count < TABLE_LOAD_RETRIES) {
|
||||
if (dm.CreateDevice(name, table)) {
|
||||
break;
|
||||
}
|
||||
load_count++;
|
||||
}
|
||||
|
||||
if (load_count >= TABLE_LOAD_RETRIES) {
|
||||
SLOGE("Cannot load dm-crypt mapping table.\n");
|
||||
goto errout;
|
||||
} else if (load_count > 1) {
|
||||
return -1;
|
||||
}
|
||||
if (load_count > 1) {
|
||||
SLOGI("Took %d tries to load dmcrypt table.\n", load_count);
|
||||
}
|
||||
|
||||
/* Resume this device to activate it */
|
||||
ioctl_init(io, DM_CRYPT_BUF_SIZE, name, 0);
|
||||
|
||||
if (ioctl(fd, DM_DEV_SUSPEND, io)) {
|
||||
SLOGE("Cannot resume the dm-crypt device\n");
|
||||
goto errout;
|
||||
std::string path;
|
||||
if (!dm.GetDmDevicePathByName(name, &path)) {
|
||||
SLOGE("Cannot determine dm-crypt path for %s.\n", name);
|
||||
return -1;
|
||||
}
|
||||
snprintf(crypto_blk_name, MAXPATHLEN, "%s", path.c_str());
|
||||
|
||||
/* Ensure the dm device has been created before returning. */
|
||||
if (android::vold::WaitForFile(crypto_blk_name, 1s) < 0) {
|
||||
// WaitForFile generates a suitable log message
|
||||
goto errout;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* We made it here with no errors. Woot! */
|
||||
retval = 0;
|
||||
|
||||
errout:
|
||||
close(fd); /* If fd is <0 from a failed open call, it's safe to just ignore the close error */
|
||||
|
||||
return retval;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int delete_crypto_blk_dev(const char* name) {
|
||||
int fd;
|
||||
char buffer[DM_CRYPT_BUF_SIZE];
|
||||
struct dm_ioctl* io;
|
||||
int retval = -1;
|
||||
int err;
|
||||
|
||||
if ((fd = open("/dev/device-mapper", O_RDWR | O_CLOEXEC)) < 0) {
|
||||
SLOGE("Cannot open device-mapper\n");
|
||||
goto errout;
|
||||
static int delete_crypto_blk_dev(const std::string& name) {
|
||||
auto& dm = DeviceMapper::Instance();
|
||||
if (!dm.DeleteDevice(name)) {
|
||||
SLOGE("Cannot remove dm-crypt device %s: %s\n", name.c_str(), strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
io = (struct dm_ioctl*)buffer;
|
||||
|
||||
ioctl_init(io, DM_CRYPT_BUF_SIZE, name, 0);
|
||||
err = ioctl(fd, DM_DEV_REMOVE, io);
|
||||
if (err) {
|
||||
SLOGE("Cannot remove dm-crypt device %s: %s\n", name, strerror(errno));
|
||||
goto errout;
|
||||
}
|
||||
|
||||
/* We made it here with no errors. Woot! */
|
||||
retval = 0;
|
||||
|
||||
errout:
|
||||
close(fd); /* If fd is <0 from a failed open call, it's safe to just ignore the close error */
|
||||
|
||||
return retval;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pbkdf2(const char* passwd, const unsigned char* salt, unsigned char* ikey,
|
||||
|
@ -1924,7 +1766,7 @@ int cryptfs_setup_ext_volume(const char* label, const char* real_blkdev, const u
|
|||
* storage volume.
|
||||
*/
|
||||
int cryptfs_revert_ext_volume(const char* label) {
|
||||
return delete_crypto_blk_dev((char*)label);
|
||||
return delete_crypto_blk_dev(label);
|
||||
}
|
||||
|
||||
int cryptfs_crypto_complete(void) {
|
||||
|
|
Loading…
Reference in a new issue