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
diff --git a/cryptfs.cpp b/cryptfs.cpp
index 0b7101e..c5d0307 100644
--- a/cryptfs.cpp
+++ b/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 @@
 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 @@
     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 @@
     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 @@
             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 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 @@
  * 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) {