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:
David Anderson 2019-05-13 13:02:54 -07:00
parent 19e74b3d1f
commit b92247368a
5 changed files with 91 additions and 485 deletions

View file

@ -30,6 +30,7 @@ cc_defaults {
static_libs: [ static_libs: [
"libavb", "libavb",
"libbootloader_message", "libbootloader_message",
"libdm",
"libfec", "libfec",
"libfec_rs", "libfec_rs",
"libfs_avb", "libfs_avb",

View file

@ -23,7 +23,6 @@
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#include <sys/ioctl.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/types.h> #include <sys/types.h>
@ -32,239 +31,72 @@
#include <android-base/logging.h> #include <android-base/logging.h>
#include <android-base/stringprintf.h> #include <android-base/stringprintf.h>
#include <android-base/strings.h> #include <android-base/strings.h>
#include <libdm/dm.h>
#include <utils/Trace.h> #include <utils/Trace.h>
#include "Devmapper.h" #include "Devmapper.h"
#define DEVMAPPER_BUFFER_SIZE 4096
using android::base::StringPrintf; using android::base::StringPrintf;
using namespace android::dm;
static const char* kVoldPrefix = "vold:"; 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, int Devmapper::create(const char* name_raw, const char* loopFile, const char* key,
unsigned long numSectors, char* ubuffer, size_t len) { unsigned long numSectors, char* ubuffer, size_t len) {
auto& dm = DeviceMapper::Instance();
auto name_string = StringPrintf("%s%s", kVoldPrefix, name_raw); auto name_string = StringPrintf("%s%s", kVoldPrefix, name_raw);
const char* name = name_string.c_str();
char* buffer = (char*)malloc(DEVMAPPER_BUFFER_SIZE); DmTable table;
if (!buffer) { table.Emplace<DmTargetCrypt>(0, numSectors, "twofish", key, 0, loopFile, 0);
PLOG(ERROR) << "Failed malloc";
if (!dm.CreateDevice(name_string, table)) {
LOG(ERROR) << "Failed to create device-mapper device " << name_string;
return -1; return -1;
} }
int fd; std::string path;
if ((fd = open("/dev/device-mapper", O_RDWR | O_CLOEXEC)) < 0) { if (!dm.GetDmDevicePathByName(name_string, &path)) {
PLOG(ERROR) << "Failed open"; LOG(ERROR) << "Failed to get device-mapper device path for " << name_string;
free(buffer);
return -1; return -1;
} }
snprintf(ubuffer, len, "%s", path.c_str());
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);
return 0; return 0;
} }
int Devmapper::destroy(const char* name_raw) { int Devmapper::destroy(const char* name_raw) {
auto& dm = DeviceMapper::Instance();
auto name_string = StringPrintf("%s%s", kVoldPrefix, name_raw); auto name_string = StringPrintf("%s%s", kVoldPrefix, name_raw);
const char* name = name_string.c_str(); if (!dm.DeleteDevice(name_string)) {
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 (errno != ENXIO) { if (errno != ENXIO) {
PLOG(ERROR) << "Failed DM_DEV_REMOVE"; PLOG(ERROR) << "Failed DM_DEV_REMOVE";
} }
free(buffer);
close(fd);
return -1; return -1;
} }
free(buffer);
close(fd);
return 0; return 0;
} }
int Devmapper::destroyAll() { int Devmapper::destroyAll() {
ATRACE_NAME("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); auto& dm = DeviceMapper::Instance();
if (!buffer2) { std::vector<DeviceMapper::DmBlockDevice> devices;
PLOG(ERROR) << "Failed malloc"; if (!dm.GetAvailableDevices(&devices)) {
free(buffer); LOG(ERROR) << "Failed to get dm devices";
return -1; return -1;
} }
int fd; for (const auto& device : devices) {
if ((fd = open("/dev/device-mapper", O_RDWR | O_CLOEXEC)) < 0) { if (android::base::StartsWith(device.name(), kVoldPrefix)) {
PLOG(ERROR) << "Failed open"; LOG(DEBUG) << "Tearing down stale dm device named " << device.name();
free(buffer); if (!dm.DeleteDevice(device.name())) {
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)) {
if (errno != ENXIO) { if (errno != ENXIO) {
PLOG(WARNING) << "Failed to destroy dm device named " << name; PLOG(WARNING) << "Failed to destroy dm device named " << device.name();
} }
} }
} else { } 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; return 0;
} }
void* Devmapper::_align(void* ptr, unsigned int a) {
unsigned long agn = --a;
return (void*)(((unsigned long)ptr + agn) & ~agn);
}

View file

@ -26,10 +26,6 @@ class Devmapper {
unsigned long numSectors, char* buffer, size_t len); unsigned long numSectors, char* buffer, size_t len);
static int destroy(const char* name); static int destroy(const char* name);
static int destroyAll(); 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 #endif

View file

@ -23,19 +23,17 @@
#include <vector> #include <vector>
#include <fcntl.h> #include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/param.h> #include <sys/param.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/types.h> #include <sys/types.h>
#include <linux/dm-ioctl.h>
#include <android-base/file.h> #include <android-base/file.h>
#include <android-base/logging.h> #include <android-base/logging.h>
#include <android-base/properties.h> #include <android-base/properties.h>
#include <android-base/unique_fd.h> #include <android-base/unique_fd.h>
#include <cutils/fs.h> #include <cutils/fs.h>
#include <fs_mgr.h> #include <fs_mgr.h>
#include <libdm/dm.h>
#include "Checkpoint.h" #include "Checkpoint.h"
#include "EncryptInplace.h" #include "EncryptInplace.h"
@ -45,13 +43,12 @@
#include "Utils.h" #include "Utils.h"
#include "VoldUtil.h" #include "VoldUtil.h"
#define DM_CRYPT_BUF_SIZE 4096
#define TABLE_LOAD_RETRIES 10 #define TABLE_LOAD_RETRIES 10
#define DEFAULT_KEY_TARGET_TYPE "default-key"
using android::fs_mgr::FstabEntry; using android::fs_mgr::FstabEntry;
using android::fs_mgr::GetEntryForMountPoint; using android::fs_mgr::GetEntryForMountPoint;
using android::vold::KeyBuffer; using android::vold::KeyBuffer;
using namespace android::dm;
static const std::string kDmNameUserdata = "userdata"; 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 vold
} // namespace android } // 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) { 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) { if (android::vold::GetBlockDev512Sectors(real_blkdev, nr_sec) != android::OK) {
PLOG(ERROR) << "Unable to measure size of " << real_blkdev; 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; 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, 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) { std::string* crypto_blkdev) {
android::base::unique_fd dm_fd( auto& dm = DeviceMapper::Instance();
TEMP_FAILURE_RETRY(open("/dev/device-mapper", O_RDWR | O_CLOEXEC, 0)));
if (dm_fd == -1) { KeyBuffer hex_key_buffer;
PLOG(ERROR) << "Cannot open device-mapper"; if (android::vold::StrToHex(key, hex_key_buffer) != android::OK) {
return false; LOG(ERROR) << "Failed to turn key to hex";
}
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;
return false; 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 DmTable table;
io = dm_ioctl_init(buffer, sizeof(buffer), dm_name); table.Emplace<DmTargetDefaultKey>(0, nr_sec, "AES-256-XTS", hex_key, real_blkdev, 0);
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;
for (int i = 0;; i++) { for (int i = 0;; i++) {
if (ioctl(dm_fd.get(), DM_TABLE_LOAD, io) == 0) { if (dm.CreateDevice(dm_name, table)) {
break; break;
} }
if (i + 1 >= TABLE_LOAD_RETRIES) { 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; return false;
} }
PLOG(INFO) << "DM_TABLE_LOAD ioctl failed, retrying"; PLOG(INFO) << "Could not create default-key device, retrying";
usleep(500000); usleep(500000);
} }
// Resume this device to activate it if (!dm.GetDmDevicePathByName(dm_name, crypto_blkdev)) {
io = dm_ioctl_init(buffer, sizeof(buffer), dm_name); LOG(ERROR) << "Cannot retrieve default-key device status " << dm_name;
if (ioctl(dm_fd.get(), DM_DEV_SUSPEND, io)) {
PLOG(ERROR) << "Cannot resume dm-crypt device " << dm_name;
return false; return false;
} }
return true; return true;
@ -267,8 +203,7 @@ bool fscrypt_mount_metadata_encrypted(const std::string& mount_point, bool needs
uint64_t nr_sec; uint64_t nr_sec;
if (!get_number_of_sectors(data_rec->blk_device, &nr_sec)) return false; if (!get_number_of_sectors(data_rec->blk_device, &nr_sec)) return false;
std::string crypto_blkdev; std::string crypto_blkdev;
if (!create_crypto_blk_dev(kDmNameUserdata, nr_sec, DEFAULT_KEY_TARGET_TYPE, if (!create_crypto_blk_dev(kDmNameUserdata, nr_sec, data_rec->blk_device, key, &crypto_blkdev))
default_key_params(data_rec->blk_device, key), &crypto_blkdev))
return false; return false;
// FIXME handle the corrupt case // FIXME handle the corrupt case
if (needs_encrypt) { if (needs_encrypt) {

View file

@ -45,6 +45,7 @@
#include <fs_mgr.h> #include <fs_mgr.h>
#include <fscrypt/fscrypt.h> #include <fscrypt/fscrypt.h>
#include <hardware_legacy/power.h> #include <hardware_legacy/power.h>
#include <libdm/dm.h>
#include <log/log.h> #include <log/log.h>
#include <logwrap/logwrap.h> #include <logwrap/logwrap.h>
#include <openssl/evp.h> #include <openssl/evp.h>
@ -56,13 +57,11 @@
#include <fcntl.h> #include <fcntl.h>
#include <inttypes.h> #include <inttypes.h>
#include <libgen.h> #include <libgen.h>
#include <linux/dm-ioctl.h>
#include <linux/kdev_t.h> #include <linux/kdev_t.h>
#include <math.h> #include <math.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <sys/ioctl.h>
#include <sys/mount.h> #include <sys/mount.h>
#include <sys/param.h> #include <sys/param.h>
#include <sys/stat.h> #include <sys/stat.h>
@ -78,12 +77,11 @@ extern "C" {
using android::base::ParseUint; using android::base::ParseUint;
using android::base::StringPrintf; using android::base::StringPrintf;
using android::fs_mgr::GetEntryForMountPoint; using android::fs_mgr::GetEntryForMountPoint;
using namespace android::dm;
using namespace std::chrono_literals; using namespace std::chrono_literals;
#define UNUSED __attribute__((unused)) #define UNUSED __attribute__((unused))
#define DM_CRYPT_BUF_SIZE 4096
#define HASH_COUNT 2000 #define HASH_COUNT 2000
constexpr size_t INTERMEDIATE_KEY_LEN_BYTES = 16; constexpr size_t INTERMEDIATE_KEY_LEN_BYTES = 16;
@ -253,19 +251,6 @@ static void cryptfs_reboot(RebootType rt) {
return; 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 { namespace {
struct CryptoType; 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'; 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 * 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 * parameters to make dm-crypt use the specified crypto sector size and round
* the crypto device size down to a crypto sector boundary. * the crypto device size down to a crypto sector boundary.
*/ */
static int add_sector_size_param(std::vector<std::string>* extra_params_vec, static int add_sector_size_param(DmTargetCrypt* target, struct crypt_mnt_ftr* ftr) {
struct crypt_mnt_ftr* ftr) {
constexpr char DM_CRYPT_SECTOR_SIZE[] = "ro.crypto.fde_sector_size"; constexpr char DM_CRYPT_SECTOR_SIZE[] = "ro.crypto.fde_sector_size";
char value[PROPERTY_VALUE_MAX]; char value[PROPERTY_VALUE_MAX];
@ -1089,12 +977,11 @@ static int add_sector_size_param(std::vector<std::string>* extra_params_vec,
return -1; return -1;
} }
std::string param = StringPrintf("sector_size:%u", sector_size); target->SetSectorSize(sector_size);
extra_params_vec->push_back(std::move(param));
// With this option, IVs will match the sector numbering, instead // With this option, IVs will match the sector numbering, instead
// of being hard-coded to being based on 512-byte sectors. // 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. // Round the crypto device size down to a crypto sector boundary.
ftr->fs_size &= ~((sector_size / 512) - 1); 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, 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, const char* real_blk_name, char* crypto_blk_name, const char* name,
uint32_t flags) { uint32_t flags) {
char buffer[DM_CRYPT_BUF_SIZE]; auto& dm = DeviceMapper::Instance();
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;
if ((fd = open("/dev/device-mapper", O_RDWR | O_CLOEXEC)) < 0) { // We need two ASCII characters to represent each byte, and need space for
SLOGE("Cannot open device-mapper\n"); // the '\0' terminator.
goto errout; 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) { 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"); 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()); DmTable table;
if (load_count < 0) { 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"); SLOGE("Cannot load dm-crypt mapping table.\n");
goto errout; return -1;
} else if (load_count > 1) { }
if (load_count > 1) {
SLOGI("Took %d tries to load dmcrypt table.\n", load_count); SLOGI("Took %d tries to load dmcrypt table.\n", load_count);
} }
/* Resume this device to activate it */ std::string path;
ioctl_init(io, DM_CRYPT_BUF_SIZE, name, 0); if (!dm.GetDmDevicePathByName(name, &path)) {
SLOGE("Cannot determine dm-crypt path for %s.\n", name);
if (ioctl(fd, DM_DEV_SUSPEND, io)) { return -1;
SLOGE("Cannot resume the dm-crypt device\n");
goto errout;
} }
snprintf(crypto_blk_name, MAXPATHLEN, "%s", path.c_str());
/* Ensure the dm device has been created before returning. */ /* Ensure the dm device has been created before returning. */
if (android::vold::WaitForFile(crypto_blk_name, 1s) < 0) { if (android::vold::WaitForFile(crypto_blk_name, 1s) < 0) {
// WaitForFile generates a suitable log message // WaitForFile generates a suitable log message
goto errout; return -1;
} }
return 0;
/* 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;
} }
static int delete_crypto_blk_dev(const char* name) { static int delete_crypto_blk_dev(const std::string& name) {
int fd; auto& dm = DeviceMapper::Instance();
char buffer[DM_CRYPT_BUF_SIZE]; if (!dm.DeleteDevice(name)) {
struct dm_ioctl* io; SLOGE("Cannot remove dm-crypt device %s: %s\n", name.c_str(), strerror(errno));
int retval = -1; return -1;
int err;
if ((fd = open("/dev/device-mapper", O_RDWR | O_CLOEXEC)) < 0) {
SLOGE("Cannot open device-mapper\n");
goto errout;
} }
return 0;
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;
} }
static int pbkdf2(const char* passwd, const unsigned char* salt, unsigned char* ikey, 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. * storage volume.
*/ */
int cryptfs_revert_ext_volume(const char* label) { 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) { int cryptfs_crypto_complete(void) {