summaryrefslogtreecommitdiffstats
path: root/debian/patches/osdep-devmapper-getroot-set-up-cheated-luks2-cryptodisk-mount-from-dm-parameters.patch
blob: a23d0f7dc71ea381bafd003b59edd690708e09fa (plain)
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, &params);
+              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