1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
|
From: Josselin Poiret <dev@jpoiret.xyz>
Date: Thu, 12 Jan 2023 17:05:09 -0600
Subject: osdep/devmapper/getroot: Set up cheated LUKS2 cryptodisk mount from
DM parameters
Origin: https://git.savannah.gnu.org/cgit/grub.git/commit/?id=aa5172a55cfabdd0bed3161ad44fc228b9d019f7
Bug-Debian: https://bugs.debian.org/1028301
This lets a LUKS2 cryptodisk have its cipher and hash filled out,
otherwise they wouldn't be initialized if cheat mounted.
Signed-off-by: Josselin Poiret <dev@jpoiret.xyz>
Tested-by: Glenn Washburn <development@efficientek.com>
Reviewed-by: Patrick Steinhardt <ps@pks.im>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/osdep/devmapper/getroot.c | 107 +++++++++++++++++++++++++++++++++++-
1 file changed, 106 insertions(+), 1 deletion(-)
diff --git a/grub-core/osdep/devmapper/getroot.c b/grub-core/osdep/devmapper/getroot.c
index 2bf4264..cc3f7da 100644
--- a/grub-core/osdep/devmapper/getroot.c
+++ b/grub-core/osdep/devmapper/getroot.c
@@ -51,6 +51,8 @@
#include <grub/emu/misc.h>
#include <grub/emu/hostdisk.h>
+#include <grub/cryptodisk.h>
+
static int
grub_util_open_dm (const char *os_dev, struct dm_tree **tree,
struct dm_tree_node **node)
@@ -186,7 +188,6 @@ grub_util_pull_devmapper (const char *os_dev)
&& lastsubdev)
{
char *grdev = grub_util_get_grub_dev (lastsubdev);
- dm_tree_free (tree);
if (grdev)
{
grub_err_t err;
@@ -194,7 +195,111 @@ grub_util_pull_devmapper (const char *os_dev)
if (err)
grub_util_error (_("can't mount encrypted volume `%s': %s"),
lastsubdev, grub_errmsg);
+ if (strncmp (uuid, "CRYPT-LUKS2-", sizeof ("CRYPT-LUKS2-") - 1) == 0)
+ {
+ /*
+ * Set LUKS2 cipher from dm parameters, since it is not
+ * possible to determine the correct one without
+ * unlocking, as there might be multiple segments.
+ */
+ grub_disk_t source;
+ grub_cryptodisk_t cryptodisk;
+ grub_uint64_t start, length;
+ char *target_type;
+ char *params;
+ const char *name;
+ char *cipher, *cipher_mode;
+ struct dm_task *dmt;
+ char *seek_head, *c;
+ unsigned int remaining;
+
+ source = grub_disk_open (grdev);
+ if (! source)
+ grub_util_error (_("cannot open grub disk `%s'"), grdev);
+ cryptodisk = grub_cryptodisk_get_by_source_disk (source);
+ if (! cryptodisk)
+ grub_util_error (_("cannot get cryptodisk from source disk `%s'"), grdev);
+ grub_disk_close (source);
+
+ /*
+ * The following function always returns a non-NULL pointer,
+ * but the string may be empty if the relevant info is not present.
+ */
+ name = dm_tree_node_get_name (node);
+ if (*name == '\0')
+ grub_util_error (_("cannot get dm node name for grub dev `%s'"), grdev);
+
+ grub_util_info ("populating parameters of cryptomount `%s' from DM device `%s'",
+ uuid, name);
+
+ dmt = dm_task_create (DM_DEVICE_TABLE);
+ if (dmt == NULL)
+ grub_util_error (_("can't create dm task DM_DEVICE_TABLE"));
+ if (dm_task_set_name (dmt, name) == 0)
+ grub_util_error (_("can't set dm task name to `%s'"), name);
+ if (dm_task_run (dmt) == 0)
+ grub_util_error (_("can't run dm task for `%s'"), name);
+ /*
+ * dm_get_next_target() doesn't have any error modes, everything has
+ * been handled by dm_task_run().
+ */
+ dm_get_next_target (dmt, NULL, &start, &length,
+ &target_type, ¶ms);
+ if (strncmp (target_type, "crypt", sizeof ("crypt")) != 0)
+ grub_util_error (_("dm target of type `%s' is not `crypt'"), target_type);
+
+ /*
+ * The dm target parameters for dm-crypt are
+ * <cipher> <key> <iv_offset> <device path> <offset> [<#opt_params> <opt_param1> ...]
+ */
+ c = params;
+ remaining = grub_strlen (c);
+
+ /* First, get the cipher name from the cipher. */
+ seek_head = grub_memchr (c, '-', remaining);
+ if (seek_head == NULL)
+ grub_util_error (_("can't get cipher from dm-crypt parameters `%s'"),
+ params);
+ cipher = grub_strndup (c, seek_head - c);
+ if (cipher == NULL)
+ grub_util_error (_("could not strndup cipher of length `%lu'"), (unsigned long)(seek_head - c));
+ remaining -= seek_head - c + 1;
+ c = seek_head + 1;
+
+ /* Now, the cipher mode. */
+ seek_head = grub_memchr (c, ' ', remaining);
+ if (seek_head == NULL)
+ grub_util_error (_("can't get cipher mode from dm-crypt parameters `%s'"),
+ params);
+ cipher_mode = grub_strndup (c, seek_head - c);
+ if (cipher_mode == NULL)
+ grub_util_error (_("could not strndup cipher_mode of length `%lu'"), (unsigned long)(seek_head - c));
+
+ remaining -= seek_head - c + 1;
+ c = seek_head + 1;
+
+ err = grub_cryptodisk_setcipher (cryptodisk, cipher, cipher_mode);
+ if (err)
+ grub_util_error (_("can't set cipher of cryptodisk `%s' to `%s' with mode `%s'"),
+ uuid, cipher, cipher_mode);
+
+ grub_free (cipher);
+ grub_free (cipher_mode);
+
+ /*
+ * This is the only hash usable by PBKDF2, and we don't
+ * have Argon2 support yet, so set it by default,
+ * otherwise grub-probe would miss the required
+ * abstraction.
+ */
+ cryptodisk->hash = grub_crypto_lookup_md_by_name ("sha256");
+ if (cryptodisk->hash == NULL)
+ grub_util_error (_("can't lookup hash sha256 by name"));
+
+ dm_task_destroy (dmt);
+ }
}
+ dm_tree_free (tree);
grub_free (grdev);
}
else
--
cgit v1.1
|