/src/cryptsetup/lib/luks2/luks2_disk_metadata.c
Line | Count | Source |
1 | | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | | /* |
3 | | * LUKS - Linux Unified Key Setup v2 |
4 | | * |
5 | | * Copyright (C) 2015-2026 Red Hat, Inc. All rights reserved. |
6 | | * Copyright (C) 2015-2026 Milan Broz |
7 | | */ |
8 | | |
9 | | #include "luks2_internal.h" |
10 | | |
11 | | /* |
12 | | * Helper functions |
13 | | */ |
14 | | static json_object *parse_json_len(struct crypt_device *cd, const char *json_area, |
15 | | uint64_t max_length, int *json_len) |
16 | 7.17k | { |
17 | 7.17k | json_object *jobj; |
18 | 7.17k | json_tokener *jtok; |
19 | | |
20 | | /* INT32_MAX is internal (json-c) json_tokener_parse_ex() limit */ |
21 | 7.17k | if (!json_area || max_length > INT32_MAX) |
22 | 0 | return NULL; |
23 | | |
24 | 7.17k | jtok = json_tokener_new(); |
25 | 7.17k | if (!jtok) { |
26 | 0 | log_dbg(cd, "ERROR: Failed to init json tokener"); |
27 | 0 | return NULL; |
28 | 0 | } |
29 | | |
30 | 7.17k | jobj = json_tokener_parse_ex(jtok, json_area, max_length); |
31 | 7.17k | if (!jobj) |
32 | 412 | log_dbg(cd, "ERROR: Failed to parse json data (%d): %s", |
33 | 7.17k | json_tokener_get_error(jtok), |
34 | 7.17k | json_tokener_error_desc(json_tokener_get_error(jtok))); |
35 | 6.76k | else |
36 | 6.76k | *json_len = jtok->char_offset; |
37 | | |
38 | 7.17k | json_tokener_free(jtok); |
39 | | |
40 | 7.17k | return jobj; |
41 | 7.17k | } |
42 | | |
43 | | static void log_dbg_checksum(struct crypt_device *cd, |
44 | | const uint8_t *csum, const char *csum_alg, const char *info) |
45 | 17.9k | { |
46 | 17.9k | char csum_txt[2*LUKS2_CHECKSUM_L+1]; |
47 | 17.9k | int i; |
48 | | |
49 | 830k | for (i = 0; i < crypt_hash_size(csum_alg); i++) |
50 | 812k | if (snprintf(&csum_txt[i*2], 3, "%02hhx", (const char)csum[i]) != 2) |
51 | 0 | return; |
52 | | |
53 | 17.9k | log_dbg(cd, "Checksum:%s (%s)", &csum_txt[0], info); |
54 | 17.9k | } |
55 | | |
56 | | /* |
57 | | * Calculate hash (checksum) of |LUKS2_bin|LUKS2_JSON_area| from in-memory structs. |
58 | | * LUKS2 on-disk header contains uniques salt both for primary and secondary header. |
59 | | * Checksum is always calculated with zeroed checksum field in binary header. |
60 | | */ |
61 | | static int hdr_checksum_calculate(const char *alg, struct luks2_hdr_disk *hdr_disk, |
62 | | const char *json_area, size_t json_len) |
63 | 10.0k | { |
64 | 10.0k | struct crypt_hash *hd = NULL; |
65 | 10.0k | int hash_size, r; |
66 | | |
67 | 10.0k | hash_size = crypt_hash_size(alg); |
68 | 10.0k | if (hash_size <= 0 || crypt_hash_init(&hd, alg)) |
69 | 0 | return -EINVAL; |
70 | | |
71 | | /* Binary header, csum zeroed. */ |
72 | 10.0k | r = crypt_hash_write(hd, (char*)hdr_disk, LUKS2_HDR_BIN_LEN); |
73 | | |
74 | | /* JSON area (including unused space) */ |
75 | 10.0k | if (!r) |
76 | 10.0k | r = crypt_hash_write(hd, json_area, json_len); |
77 | | |
78 | 10.0k | if (!r) |
79 | 10.0k | r = crypt_hash_final(hd, (char*)hdr_disk->csum, (size_t)hash_size); |
80 | | |
81 | 10.0k | crypt_hash_destroy(hd); |
82 | 10.0k | return r; |
83 | 10.0k | } |
84 | | |
85 | | /* |
86 | | * Compare hash (checksum) of on-disk and in-memory header. |
87 | | */ |
88 | | static int hdr_checksum_check(struct crypt_device *cd, |
89 | | const char *alg, struct luks2_hdr_disk *hdr_disk, |
90 | | const char *json_area, size_t json_len) |
91 | 8.33k | { |
92 | 8.33k | struct luks2_hdr_disk hdr_tmp; |
93 | 8.33k | int hash_size, r; |
94 | | |
95 | 8.33k | hash_size = crypt_hash_size(alg); |
96 | 8.33k | if (hash_size <= 0) |
97 | 470 | return -EINVAL; |
98 | | |
99 | | /* Copy header and zero checksum. */ |
100 | 7.86k | memcpy(&hdr_tmp, hdr_disk, LUKS2_HDR_BIN_LEN); |
101 | 7.86k | memset(&hdr_tmp.csum, 0, sizeof(hdr_tmp.csum)); |
102 | | |
103 | 7.86k | r = hdr_checksum_calculate(alg, &hdr_tmp, json_area, json_len); |
104 | 7.86k | if (r < 0) |
105 | 0 | return r; |
106 | | |
107 | 7.86k | log_dbg_checksum(cd, hdr_disk->csum, alg, "on-disk"); |
108 | 7.86k | log_dbg_checksum(cd, hdr_tmp.csum, alg, "in-memory"); |
109 | | |
110 | 7.86k | if (memcmp(hdr_tmp.csum, hdr_disk->csum, (size_t)hash_size)) |
111 | 686 | return -EINVAL; |
112 | | |
113 | 7.17k | return 0; |
114 | 7.86k | } |
115 | | |
116 | | /* |
117 | | * Convert header from on-disk format to in-memory struct |
118 | | */ |
119 | | static void hdr_from_disk(struct luks2_hdr_disk *hdr_disk1, |
120 | | struct luks2_hdr_disk *hdr_disk2, |
121 | | struct luks2_hdr *hdr, |
122 | | int secondary) |
123 | 6.64k | { |
124 | 6.64k | hdr->version = be16_to_cpu(hdr_disk1->version); |
125 | 6.64k | hdr->hdr_size = be64_to_cpu(hdr_disk1->hdr_size); |
126 | 6.64k | hdr->seqid = be64_to_cpu(hdr_disk1->seqid); |
127 | | |
128 | 6.64k | memcpy(hdr->label, hdr_disk1->label, LUKS2_LABEL_L); |
129 | 6.64k | hdr->label[LUKS2_LABEL_L - 1] = '\0'; |
130 | 6.64k | memcpy(hdr->subsystem, hdr_disk1->subsystem, LUKS2_LABEL_L); |
131 | 6.64k | hdr->subsystem[LUKS2_LABEL_L - 1] = '\0'; |
132 | 6.64k | memcpy(hdr->checksum_alg, hdr_disk1->checksum_alg, LUKS2_CHECKSUM_ALG_L); |
133 | 6.64k | hdr->checksum_alg[LUKS2_CHECKSUM_ALG_L - 1] = '\0'; |
134 | 6.64k | memcpy(hdr->uuid, hdr_disk1->uuid, LUKS2_UUID_L); |
135 | 6.64k | hdr->uuid[LUKS2_UUID_L - 1] = '\0'; |
136 | | |
137 | 6.64k | if (secondary) { |
138 | 5.71k | memcpy(hdr->salt1, hdr_disk2->salt, LUKS2_SALT_L); |
139 | 5.71k | memcpy(hdr->salt2, hdr_disk1->salt, LUKS2_SALT_L); |
140 | 5.71k | } else { |
141 | 930 | memcpy(hdr->salt1, hdr_disk1->salt, LUKS2_SALT_L); |
142 | 930 | memcpy(hdr->salt2, hdr_disk2->salt, LUKS2_SALT_L); |
143 | 930 | } |
144 | 6.64k | } |
145 | | |
146 | | /* |
147 | | * Convert header from in-memory struct to on-disk format |
148 | | */ |
149 | | static void hdr_to_disk(struct luks2_hdr *hdr, |
150 | | struct luks2_hdr_disk *hdr_disk, |
151 | | int secondary, uint64_t offset) |
152 | 2.21k | { |
153 | 2.21k | assert(((char*)&(hdr_disk->_padding4096) - (char*)&(hdr_disk->magic)) == 512); |
154 | | |
155 | 2.21k | memset(hdr_disk, 0, LUKS2_HDR_BIN_LEN); |
156 | | |
157 | 2.21k | memcpy(&hdr_disk->magic, secondary ? LUKS2_MAGIC_2ND : LUKS2_MAGIC_1ST, LUKS2_MAGIC_L); |
158 | 2.21k | hdr_disk->version = cpu_to_be16(hdr->version); |
159 | 2.21k | hdr_disk->hdr_size = cpu_to_be64(hdr->hdr_size); |
160 | 2.21k | hdr_disk->hdr_offset = cpu_to_be64(offset); |
161 | 2.21k | hdr_disk->seqid = cpu_to_be64(hdr->seqid); |
162 | | |
163 | 2.21k | memcpy(hdr_disk->label, hdr->label, MIN(strlen(hdr->label), LUKS2_LABEL_L)); |
164 | 2.21k | hdr_disk->label[LUKS2_LABEL_L - 1] = '\0'; |
165 | 2.21k | memcpy(hdr_disk->subsystem, hdr->subsystem, MIN(strlen(hdr->subsystem), LUKS2_LABEL_L)); |
166 | 2.21k | hdr_disk->subsystem[LUKS2_LABEL_L - 1] = '\0'; |
167 | 2.21k | memcpy(hdr_disk->checksum_alg, hdr->checksum_alg, MIN(strlen(hdr->checksum_alg), LUKS2_CHECKSUM_ALG_L)); |
168 | 2.21k | hdr_disk->checksum_alg[LUKS2_CHECKSUM_ALG_L - 1] = '\0'; |
169 | 2.21k | memcpy(hdr_disk->uuid, hdr->uuid, MIN(strlen(hdr->uuid), LUKS2_UUID_L)); |
170 | 2.21k | hdr_disk->uuid[LUKS2_UUID_L - 1] = '\0'; |
171 | | |
172 | 2.21k | memcpy(hdr_disk->salt, secondary ? hdr->salt2 : hdr->salt1, LUKS2_SALT_L); |
173 | 2.21k | } |
174 | | |
175 | | /* |
176 | | * Sanity checks before checksum is validated |
177 | | */ |
178 | | static int hdr_disk_sanity_check_pre(struct crypt_device *cd, |
179 | | struct luks2_hdr_disk *hdr, |
180 | | size_t *hdr_json_size, int secondary, |
181 | | uint64_t offset) |
182 | 38.1k | { |
183 | 38.1k | uint64_t hdr_size; |
184 | | |
185 | 38.1k | if (memcmp(hdr->magic, secondary ? LUKS2_MAGIC_2ND : LUKS2_MAGIC_1ST, LUKS2_MAGIC_L)) |
186 | 29.4k | return -EINVAL; |
187 | | |
188 | 8.74k | if (be16_to_cpu(hdr->version) != 2) { |
189 | 94 | log_dbg(cd, "Unsupported LUKS2 header version %u.", be16_to_cpu(hdr->version)); |
190 | 94 | return -EINVAL; |
191 | 94 | } |
192 | | |
193 | 8.64k | if (offset != be64_to_cpu(hdr->hdr_offset)) { |
194 | 158 | log_dbg(cd, "LUKS2 offset 0x%04" PRIx64 " on device differs to expected offset 0x%04" PRIx64 ".", |
195 | 158 | be64_to_cpu(hdr->hdr_offset), offset); |
196 | 158 | return -EINVAL; |
197 | 158 | } |
198 | | |
199 | 8.48k | hdr_size = be64_to_cpu(hdr->hdr_size); |
200 | | |
201 | 8.48k | if (hdr_size < LUKS2_HDR_16K_LEN || hdr_size > LUKS2_HDR_OFFSET_MAX) { |
202 | 140 | log_dbg(cd, "LUKS2 header has bogus size 0x%04" PRIx64 ".", hdr_size); |
203 | 140 | return -EINVAL; |
204 | 140 | } |
205 | | |
206 | 8.34k | if (secondary && (offset != hdr_size)) { |
207 | 17 | log_dbg(cd, "LUKS2 offset 0x%04" PRIx64 " in secondary header does not match size 0x%04" PRIx64 ".", |
208 | 17 | offset, hdr_size); |
209 | 17 | return -EINVAL; |
210 | 17 | } |
211 | | |
212 | | /* FIXME: sanity check checksum alg. */ |
213 | | |
214 | 8.33k | log_dbg(cd, "LUKS2 header version %u of size %" PRIu64 " bytes, checksum %s.", |
215 | 8.33k | be16_to_cpu(hdr->version), hdr_size, |
216 | 8.33k | hdr->checksum_alg); |
217 | | |
218 | 8.33k | *hdr_json_size = hdr_size - LUKS2_HDR_BIN_LEN; |
219 | 8.33k | return 0; |
220 | 8.34k | } |
221 | | |
222 | | /* |
223 | | * Read LUKS2 header from disk at specific offset. |
224 | | */ |
225 | | static int hdr_read_disk(struct crypt_device *cd, |
226 | | struct device *device, struct luks2_hdr_disk *hdr_disk, |
227 | | char **json_area, uint64_t offset, int secondary) |
228 | 38.1k | { |
229 | 38.1k | size_t hdr_json_size = 0; |
230 | 38.1k | int devfd, r; |
231 | | |
232 | 38.1k | log_dbg(cd, "Trying to read %s LUKS2 header at offset 0x%" PRIx64 ".", |
233 | 38.1k | secondary ? "secondary" : "primary", offset); |
234 | | |
235 | 38.1k | devfd = device_open_locked(cd, device, O_RDONLY); |
236 | 38.1k | if (devfd < 0) |
237 | 0 | return devfd == -1 ? -EIO : devfd; |
238 | | |
239 | | /* |
240 | | * Read binary header and run sanity check before reading |
241 | | * JSON area and validating checksum. |
242 | | */ |
243 | 38.1k | if (read_lseek_blockwise(devfd, device_block_size(cd, device), |
244 | 38.1k | device_alignment(device), hdr_disk, |
245 | 38.1k | LUKS2_HDR_BIN_LEN, offset) != LUKS2_HDR_BIN_LEN) { |
246 | 0 | memset(hdr_disk, 0, LUKS2_HDR_BIN_LEN); |
247 | 0 | return -EIO; |
248 | 0 | } |
249 | | |
250 | | /* |
251 | | * hdr_json_size is validated if this call succeeds |
252 | | */ |
253 | 38.1k | r = hdr_disk_sanity_check_pre(cd, hdr_disk, &hdr_json_size, secondary, offset); |
254 | 38.1k | if (r < 0) |
255 | 29.8k | return r; |
256 | | |
257 | | /* |
258 | | * Allocate and read JSON area. Always the whole area must be read. |
259 | | */ |
260 | 8.33k | *json_area = malloc(hdr_json_size); |
261 | 8.33k | if (!*json_area) |
262 | 0 | return -ENOMEM; |
263 | | |
264 | 8.33k | if (read_lseek_blockwise(devfd, device_block_size(cd, device), |
265 | 8.33k | device_alignment(device), *json_area, hdr_json_size, |
266 | 8.33k | offset + LUKS2_HDR_BIN_LEN) != (ssize_t)hdr_json_size) { |
267 | 0 | free(*json_area); |
268 | 0 | *json_area = NULL; |
269 | 0 | return -EIO; |
270 | 0 | } |
271 | | |
272 | | /* |
273 | | * Calculate and validate checksum and zero it afterwards. |
274 | | */ |
275 | 8.33k | if (hdr_checksum_check(cd, hdr_disk->checksum_alg, hdr_disk, |
276 | 8.33k | *json_area, hdr_json_size)) { |
277 | 1.15k | log_dbg(cd, "LUKS2 header checksum error (offset %" PRIu64 ").", offset); |
278 | 1.15k | free(*json_area); |
279 | 1.15k | *json_area = NULL; |
280 | 1.15k | r = -EINVAL; |
281 | 1.15k | } |
282 | 8.33k | memset(hdr_disk->csum, 0, LUKS2_CHECKSUM_L); |
283 | | |
284 | 8.33k | return r; |
285 | 8.33k | } |
286 | | |
287 | | /* |
288 | | * Write LUKS2 header to disk at specific offset. |
289 | | */ |
290 | | static int hdr_write_disk(struct crypt_device *cd, |
291 | | struct device *device, struct luks2_hdr *hdr, |
292 | | const char *json_area, size_t write_area_len, |
293 | | int secondary) |
294 | 4.43k | { |
295 | 4.43k | struct luks2_hdr_disk hdr_disk; |
296 | 4.43k | uint64_t offset = secondary ? hdr->hdr_size : 0; |
297 | 4.43k | size_t hdr_json_len; |
298 | 4.43k | int devfd, r; |
299 | | |
300 | 4.43k | hdr_json_len = hdr->hdr_size - LUKS2_HDR_BIN_LEN; |
301 | | |
302 | 4.43k | assert(write_area_len <= hdr_json_len); |
303 | | |
304 | 4.43k | log_dbg(cd, "Trying to write LUKS2 header (%zu bytes) at offset %" PRIu64 ".", |
305 | 4.43k | write_area_len, offset); |
306 | | |
307 | 4.43k | devfd = device_open_locked(cd, device, O_RDWR); |
308 | 4.43k | if (devfd < 0) |
309 | 2.21k | return devfd == -1 ? -EINVAL : devfd; |
310 | | |
311 | 2.21k | hdr_to_disk(hdr, &hdr_disk, secondary, offset); |
312 | | |
313 | | /* |
314 | | * Write header without checksum but with proper seqid. |
315 | | */ |
316 | 2.21k | if (write_lseek_blockwise(devfd, device_block_size(cd, device), |
317 | 2.21k | device_alignment(device), (char *)&hdr_disk, |
318 | 2.21k | LUKS2_HDR_BIN_LEN, offset) < (ssize_t)LUKS2_HDR_BIN_LEN) { |
319 | 0 | return -EIO; |
320 | 0 | } |
321 | | |
322 | | /* |
323 | | * Write json area. |
324 | | */ |
325 | 2.21k | if (write_lseek_blockwise(devfd, device_block_size(cd, device), |
326 | 2.21k | device_alignment(device), |
327 | 2.21k | CONST_CAST(char*)json_area, write_area_len, |
328 | 2.21k | LUKS2_HDR_BIN_LEN + offset) < (ssize_t)write_area_len) { |
329 | 0 | return -EIO; |
330 | 0 | } |
331 | | |
332 | | /* |
333 | | * Calculate checksum and write header with checksum. |
334 | | */ |
335 | 2.21k | r = hdr_checksum_calculate(hdr_disk.checksum_alg, &hdr_disk, |
336 | 2.21k | json_area, hdr_json_len); |
337 | 2.21k | if (r < 0) { |
338 | 0 | return r; |
339 | 0 | } |
340 | 2.21k | log_dbg_checksum(cd, hdr_disk.csum, hdr_disk.checksum_alg, "in-memory"); |
341 | | |
342 | 2.21k | if (write_lseek_blockwise(devfd, device_block_size(cd, device), |
343 | 2.21k | device_alignment(device), (char *)&hdr_disk, |
344 | 2.21k | LUKS2_HDR_BIN_LEN, offset) < (ssize_t)LUKS2_HDR_BIN_LEN) |
345 | 0 | r = -EIO; |
346 | | |
347 | 2.21k | device_sync(cd, device); |
348 | 2.21k | return r; |
349 | 2.21k | } |
350 | | |
351 | | static int LUKS2_check_sequence_id(struct crypt_device *cd, struct luks2_hdr *hdr, struct device *device) |
352 | 0 | { |
353 | 0 | int devfd; |
354 | 0 | struct luks2_hdr_disk dhdr; |
355 | |
|
356 | 0 | if (!hdr) |
357 | 0 | return -EINVAL; |
358 | | |
359 | 0 | devfd = device_open_locked(cd, device, O_RDONLY); |
360 | 0 | if (devfd < 0) |
361 | 0 | return devfd == -1 ? -EINVAL : devfd; |
362 | | |
363 | | /* we need only first 512 bytes, see luks2_hdr_disk structure */ |
364 | 0 | if ((read_lseek_blockwise(devfd, device_block_size(cd, device), |
365 | 0 | device_alignment(device), &dhdr, 512, 0) != 512)) |
366 | 0 | return -EIO; |
367 | | |
368 | | /* there's nothing to check if there's no LUKS2 header */ |
369 | 0 | if ((be16_to_cpu(dhdr.version) != 2) || |
370 | 0 | memcmp(dhdr.magic, LUKS2_MAGIC_1ST, LUKS2_MAGIC_L) || |
371 | 0 | strcmp(dhdr.uuid, hdr->uuid)) |
372 | 0 | return 0; |
373 | | |
374 | 0 | return hdr->seqid != be64_to_cpu(dhdr.seqid); |
375 | 0 | } |
376 | | |
377 | | int LUKS2_device_write_lock(struct crypt_device *cd, struct luks2_hdr *hdr, struct device *device) |
378 | 0 | { |
379 | 0 | int r = device_write_lock(cd, device); |
380 | |
|
381 | 0 | if (r < 0) { |
382 | 0 | log_err(cd, _("Failed to acquire write lock on device %s."), device_path(device)); |
383 | 0 | return r; |
384 | 0 | } |
385 | | |
386 | | /* run sequence id check only on first write lock (r == 1) and w/o LUKS2 reencryption in-progress */ |
387 | 0 | if (r == 1 && !crypt_get_luks2_reencrypt(cd)) { |
388 | 0 | log_dbg(cd, "Checking context sequence id matches value stored on disk."); |
389 | 0 | if (LUKS2_check_sequence_id(cd, hdr, device)) { |
390 | 0 | device_write_unlock(cd, device); |
391 | 0 | log_err(cd, _("Detected attempt for concurrent LUKS2 metadata update. Aborting operation.")); |
392 | 0 | return -EINVAL; |
393 | 0 | } |
394 | 0 | } |
395 | | |
396 | 0 | return 0; |
397 | 0 | } |
398 | | |
399 | | /* |
400 | | * Convert in-memory LUKS2 header and write it to disk. |
401 | | * This will increase sequence id, write both header copies and calculate checksum. |
402 | | */ |
403 | | int LUKS2_disk_hdr_write(struct crypt_device *cd, struct luks2_hdr *hdr, struct device *device, bool seqid_check) |
404 | 0 | { |
405 | 0 | char *json_area; |
406 | 0 | const char *json_text; |
407 | 0 | size_t json_data_len, json_area_len, json_area_write_len; |
408 | 0 | int r; |
409 | |
|
410 | 0 | if (hdr->version != 2) { |
411 | 0 | log_dbg(cd, "Unsupported LUKS2 header version (%u).", hdr->version); |
412 | 0 | return -EINVAL; |
413 | 0 | } |
414 | | |
415 | 0 | r = device_check_size(cd, crypt_metadata_device(cd), LUKS2_hdr_and_areas_size(hdr), 1); |
416 | 0 | if (r) |
417 | 0 | return r; |
418 | | |
419 | | /* |
420 | | * Generate text space-efficient JSON representation to json area. |
421 | | */ |
422 | 0 | json_text = crypt_jobj_to_string_on_disk(hdr->jobj); |
423 | 0 | if (!json_text || !*json_text) { |
424 | 0 | log_dbg(cd, "Cannot parse JSON object to text representation."); |
425 | 0 | return -ENOMEM; |
426 | 0 | } |
427 | | |
428 | 0 | json_area_len = hdr->hdr_size - LUKS2_HDR_BIN_LEN; |
429 | 0 | json_area_write_len = json_data_len = strlen(json_text); |
430 | |
|
431 | 0 | if (json_data_len > (json_area_len - 1)) { |
432 | 0 | log_dbg(cd, "JSON is too large (%zu > %zu).", json_data_len, json_area_len - 1); |
433 | 0 | return -EINVAL; |
434 | 0 | } |
435 | | |
436 | | /* |
437 | | * Allocate and zero JSON area (of proper header size). |
438 | | */ |
439 | 0 | json_area = crypt_zalloc(json_area_len); |
440 | 0 | if (!json_area) |
441 | 0 | return -ENOMEM; |
442 | | |
443 | | /* |
444 | | * If the metadata in 'json_area' buffer is smaller than last on-disk |
445 | | * metadata we also have to erase the remaining bytes between the tail |
446 | | * of current metadata and the on-disk metadata end pointer. Set write |
447 | | * area length large enough to overwrite it. |
448 | | * |
449 | | * If seqid_check is turned off (during LUKS2 format) write entire |
450 | | * LUKS2 metadata size instead. |
451 | | * |
452 | | * Turn off the optimization also during metadata upconversion |
453 | | * (hdr->on_disk_json_end_offset == 0). |
454 | | */ |
455 | 0 | if (seqid_check && (json_data_len < hdr->on_disk_json_end_offset)) |
456 | 0 | json_area_write_len = hdr->on_disk_json_end_offset; |
457 | 0 | else if (!seqid_check || !hdr->on_disk_json_end_offset) |
458 | 0 | json_area_write_len = json_area_len; |
459 | |
|
460 | 0 | strncpy(json_area, json_text, json_area_len); |
461 | |
|
462 | 0 | if (seqid_check) |
463 | 0 | r = LUKS2_device_write_lock(cd, hdr, device); |
464 | 0 | else |
465 | 0 | r = device_write_lock(cd, device); |
466 | 0 | if (r < 0) { |
467 | 0 | free(json_area); |
468 | 0 | return r; |
469 | 0 | } |
470 | | |
471 | | /* Increase sequence id before writing it to disk. */ |
472 | 0 | hdr->seqid++; |
473 | | |
474 | | /* Write primary and secondary header */ |
475 | 0 | r = hdr_write_disk(cd, device, hdr, json_area, json_area_write_len, 0); |
476 | 0 | if (!r) |
477 | 0 | r = hdr_write_disk(cd, device, hdr, json_area, json_area_write_len, 1); |
478 | |
|
479 | 0 | if (r) |
480 | 0 | log_dbg(cd, "LUKS2 header write failed (%d).", r); |
481 | | |
482 | | /* store new json end pointer or reset it on error */ |
483 | 0 | hdr->on_disk_json_end_offset = r ? 0 : json_data_len; |
484 | |
|
485 | 0 | device_write_unlock(cd, device); |
486 | |
|
487 | 0 | free(json_area); |
488 | 0 | return r; |
489 | 0 | } |
490 | | static int validate_json_area(struct crypt_device *cd, const char *json_area, |
491 | | uint64_t json_len, uint64_t max_length) |
492 | 6.76k | { |
493 | 6.76k | char c; |
494 | | |
495 | | /* Enforce there are no needless opening bytes */ |
496 | 6.76k | if (*json_area != '{') { |
497 | 104 | log_dbg(cd, "ERROR: Opening character must be left curly bracket: '{'."); |
498 | 104 | return -EINVAL; |
499 | 104 | } |
500 | | |
501 | 6.66k | if (json_len >= max_length) { |
502 | 0 | log_dbg(cd, "ERROR: Missing trailing null byte beyond parsed json data string."); |
503 | 0 | return -EINVAL; |
504 | 0 | } |
505 | | |
506 | | /* |
507 | | * TODO: |
508 | | * validate there are legal json format characters between |
509 | | * 'json_area' and 'json_area + json_len' |
510 | | */ |
511 | | |
512 | 399M | do { |
513 | 399M | c = *(json_area + json_len); |
514 | 399M | if (c != '\0') { |
515 | 11 | log_dbg(cd, "ERROR: Forbidden ascii code 0x%02hhx found beyond json data string at offset %" PRIu64, |
516 | 11 | c, json_len); |
517 | 11 | return -EINVAL; |
518 | 11 | } |
519 | 399M | } while (++json_len < max_length); |
520 | | |
521 | 6.64k | return 0; |
522 | 6.66k | } |
523 | | |
524 | | static int validate_luks2_json_object(struct crypt_device *cd, json_object *jobj_hdr, uint64_t length) |
525 | 6.64k | { |
526 | 6.64k | int r; |
527 | | |
528 | | /* we require top level object to be of json_type_object */ |
529 | 6.64k | r = !json_object_is_type(jobj_hdr, json_type_object); |
530 | 6.64k | if (r) { |
531 | 2 | log_dbg(cd, "ERROR: Resulting object is not a json object type"); |
532 | 2 | return r; |
533 | 2 | } |
534 | | |
535 | 6.64k | r = LUKS2_hdr_validate(cd, jobj_hdr, length); |
536 | 6.64k | if (r) { |
537 | 268 | log_dbg(cd, "Repairing JSON metadata."); |
538 | | /* try to correct known glitches */ |
539 | 268 | LUKS2_hdr_repair(cd, jobj_hdr); |
540 | | |
541 | | /* run validation again */ |
542 | 268 | r = LUKS2_hdr_validate(cd, jobj_hdr, length); |
543 | 268 | } |
544 | | |
545 | 6.64k | if (r) |
546 | 268 | log_dbg(cd, "ERROR: LUKS2 validation failed"); |
547 | | |
548 | 6.64k | return r; |
549 | 6.64k | } |
550 | | |
551 | | static json_object *parse_and_validate_json(struct crypt_device *cd, |
552 | | const char *json_area, uint64_t hdr_size, |
553 | | uint64_t *json_area_end) |
554 | 7.17k | { |
555 | 7.17k | int json_len, r; |
556 | 7.17k | json_object *jobj; |
557 | 7.17k | uint64_t max_length; |
558 | | |
559 | 7.17k | assert(json_area_end); |
560 | | |
561 | 7.17k | if (hdr_size <= LUKS2_HDR_BIN_LEN || hdr_size > LUKS2_HDR_OFFSET_MAX) { |
562 | 0 | log_dbg(cd, "LUKS2 header JSON has bogus size 0x%04" PRIx64 ".", hdr_size); |
563 | 0 | return NULL; |
564 | 0 | } |
565 | | |
566 | 7.17k | max_length = hdr_size - LUKS2_HDR_BIN_LEN; |
567 | | |
568 | 7.17k | jobj = parse_json_len(cd, json_area, max_length, &json_len); |
569 | 7.17k | if (!jobj) |
570 | 412 | return NULL; |
571 | | |
572 | | /* successful parse_json_len must not return offset <= 0 */ |
573 | 7.17k | assert(json_len > 0); |
574 | | |
575 | 6.76k | r = validate_json_area(cd, json_area, json_len, max_length); |
576 | 6.76k | if (!r) |
577 | 6.64k | r = validate_luks2_json_object(cd, jobj, max_length); |
578 | | |
579 | 6.76k | if (r) { |
580 | 385 | json_object_put(jobj); |
581 | 385 | jobj = NULL; |
582 | 385 | } |
583 | | |
584 | 6.76k | *json_area_end = json_len; |
585 | | |
586 | 6.76k | return jobj; |
587 | 6.76k | } |
588 | | |
589 | | static int detect_device_signatures(struct crypt_device *cd, const char *path) |
590 | 6.37k | { |
591 | 6.37k | blk_probe_status prb_state; |
592 | 6.37k | int r; |
593 | 6.37k | struct blkid_handle *h; |
594 | | |
595 | 6.37k | if (!blk_supported()) { |
596 | 0 | log_dbg(cd, "Blkid probing of device signatures disabled."); |
597 | 0 | return 0; |
598 | 0 | } |
599 | | |
600 | 6.37k | if ((r = blk_init_by_path(&h, path))) { |
601 | 0 | log_dbg(cd, "Failed to initialize blkid_handle by path."); |
602 | 0 | return -EINVAL; |
603 | 0 | } |
604 | | |
605 | | /* We don't care about details. Be fast. */ |
606 | 6.37k | blk_set_chains_for_fast_detection(h); |
607 | | |
608 | | /* Filter out crypto_LUKS. we don't care now */ |
609 | 6.37k | blk_superblocks_filter_luks(h); |
610 | | |
611 | 6.37k | prb_state = blk_safeprobe(h); |
612 | | |
613 | 6.37k | switch (prb_state) { |
614 | 0 | case PRB_AMBIGUOUS: |
615 | 0 | log_dbg(cd, "Blkid probe couldn't decide device type unambiguously."); |
616 | | /* fall through */ |
617 | 515 | case PRB_FAIL: |
618 | 515 | log_dbg(cd, "Blkid probe failed."); |
619 | 515 | r = -EINVAL; |
620 | 515 | break; |
621 | 1.43k | case PRB_OK: /* crypto_LUKS type is filtered out */ |
622 | 1.43k | r = -EINVAL; |
623 | | |
624 | 1.43k | if (blk_is_partition(h)) |
625 | 510 | log_dbg(cd, "Blkid probe detected partition type '%s'", blk_get_partition_type(h)); |
626 | 923 | else if (blk_is_superblock(h)) |
627 | 923 | log_dbg(cd, "blkid probe detected superblock type '%s'", blk_get_superblock_type(h)); |
628 | 1.43k | break; |
629 | 4.43k | case PRB_EMPTY: |
630 | 4.43k | log_dbg(cd, "Blkid probe detected no foreign device signature."); |
631 | 6.37k | } |
632 | 6.37k | blk_free(h); |
633 | 6.37k | return r; |
634 | 6.37k | } |
635 | | |
636 | | /* |
637 | | * Read and convert on-disk LUKS2 header to in-memory representation.. |
638 | | * Try to do recovery if on-disk state is not consistent. |
639 | | */ |
640 | | int LUKS2_disk_hdr_read(struct crypt_device *cd, struct luks2_hdr *hdr, |
641 | | struct device *device, int do_recovery, int do_blkprobe) |
642 | 8.40k | { |
643 | 8.40k | enum { HDR_OK, HDR_OBSOLETE, HDR_FAIL, HDR_FAIL_IO } state_hdr1, state_hdr2; |
644 | 8.40k | struct luks2_hdr_disk hdr_disk1, hdr_disk2; |
645 | 8.40k | char *json_area1 = NULL, *json_area2 = NULL; |
646 | 8.40k | json_object *jobj_hdr1 = NULL, *jobj_hdr2 = NULL; |
647 | 8.40k | unsigned int i; |
648 | 8.40k | int r; |
649 | 8.40k | uint64_t hdr_size, json_area_end1 = 0, json_area_end2 = 0; |
650 | 8.40k | uint64_t hdr2_offsets[] = LUKS2_HDR2_OFFSETS; |
651 | | |
652 | | /* Skip auto-recovery if locks are disabled and we're not doing LUKS2 explicit repair */ |
653 | 8.40k | if (do_recovery && do_blkprobe && !crypt_metadata_locking_enabled()) { |
654 | 0 | do_recovery = 0; |
655 | 0 | log_dbg(cd, "Disabling header auto-recovery due to locking being disabled."); |
656 | 0 | } |
657 | | |
658 | | /* |
659 | | * Read primary LUKS2 header (offset 0). |
660 | | */ |
661 | 8.40k | state_hdr1 = HDR_FAIL; |
662 | 8.40k | r = hdr_read_disk(cd, device, &hdr_disk1, &json_area1, 0, 0); |
663 | 8.40k | if (r == 0) { |
664 | 1.43k | jobj_hdr1 = parse_and_validate_json(cd, json_area1, be64_to_cpu(hdr_disk1.hdr_size), &json_area_end1); |
665 | 1.43k | state_hdr1 = jobj_hdr1 ? HDR_OK : HDR_OBSOLETE; |
666 | 6.97k | } else if (r == -EIO) |
667 | 0 | state_hdr1 = HDR_FAIL_IO; |
668 | | |
669 | | /* |
670 | | * Read secondary LUKS2 header (follows primary). |
671 | | */ |
672 | 8.40k | state_hdr2 = HDR_FAIL; |
673 | 8.40k | if (state_hdr1 != HDR_FAIL && state_hdr1 != HDR_FAIL_IO) { |
674 | 1.43k | r = hdr_read_disk(cd, device, &hdr_disk2, &json_area2, be64_to_cpu(hdr_disk1.hdr_size), 1); |
675 | 1.43k | if (r == 0) { |
676 | 0 | jobj_hdr2 = parse_and_validate_json(cd, json_area2, be64_to_cpu(hdr_disk2.hdr_size), &json_area_end2); |
677 | 0 | state_hdr2 = jobj_hdr2 ? HDR_OK : HDR_OBSOLETE; |
678 | 1.43k | } else if (r == -EIO) |
679 | 0 | state_hdr2 = HDR_FAIL_IO; |
680 | 6.97k | } else { |
681 | | /* |
682 | | * No header size, check all known offsets. |
683 | | */ |
684 | 6.97k | hdr_disk2.hdr_size = 0; |
685 | 35.2k | for (r = -EINVAL,i = 0; r < 0 && i < ARRAY_SIZE(hdr2_offsets); i++) |
686 | 28.3k | r = hdr_read_disk(cd, device, &hdr_disk2, &json_area2, hdr2_offsets[i], 1); |
687 | | |
688 | 6.97k | if (r == 0) { |
689 | 5.74k | jobj_hdr2 = parse_and_validate_json(cd, json_area2, be64_to_cpu(hdr_disk2.hdr_size), &json_area_end2); |
690 | 5.74k | state_hdr2 = jobj_hdr2 ? HDR_OK : HDR_OBSOLETE; |
691 | 5.74k | } else if (r == -EIO) |
692 | 0 | state_hdr2 = HDR_FAIL_IO; |
693 | 6.97k | } |
694 | | |
695 | | /* |
696 | | * Check sequence id if both headers are read correctly. |
697 | | */ |
698 | 8.40k | if (state_hdr1 == HDR_OK && state_hdr2 == HDR_OK) { |
699 | 0 | if (be64_to_cpu(hdr_disk1.seqid) > be64_to_cpu(hdr_disk2.seqid)) |
700 | 0 | state_hdr2 = HDR_OBSOLETE; |
701 | 0 | else if (be64_to_cpu(hdr_disk1.seqid) < be64_to_cpu(hdr_disk2.seqid)) |
702 | 0 | state_hdr1 = HDR_OBSOLETE; |
703 | 0 | } |
704 | | |
705 | | /* check header with keyslots to fit the device */ |
706 | 8.40k | if (state_hdr1 == HDR_OK) |
707 | 646 | hdr_size = LUKS2_hdr_and_areas_size_jobj(jobj_hdr1); |
708 | 7.76k | else if (state_hdr2 == HDR_OK) |
709 | 5.73k | hdr_size = LUKS2_hdr_and_areas_size_jobj(jobj_hdr2); |
710 | 2.02k | else { |
711 | 2.02k | r = (state_hdr1 == HDR_FAIL_IO && state_hdr2 == HDR_FAIL_IO) ? -EIO : -EINVAL; |
712 | 2.02k | goto err; |
713 | 2.02k | } |
714 | | |
715 | 6.37k | r = device_check_size(cd, device, hdr_size, 0); |
716 | 6.37k | if (r) |
717 | 1 | goto err; |
718 | | |
719 | | /* |
720 | | * Try to rewrite (recover) bad header. Always regenerate salt for bad header. |
721 | | */ |
722 | 6.37k | if (state_hdr1 == HDR_OK && state_hdr2 != HDR_OK) { |
723 | 645 | log_dbg(cd, "Secondary LUKS2 header requires recovery."); |
724 | | |
725 | 645 | if (do_blkprobe && (r = detect_device_signatures(cd, device_path(device)))) { |
726 | 25 | log_err(cd, _("Device contains ambiguous signatures, cannot auto-recover LUKS2.\n" |
727 | 25 | "Please run \"cryptsetup repair\" for recovery.")); |
728 | 25 | goto err; |
729 | 25 | } |
730 | | |
731 | 620 | if (do_recovery) { |
732 | 620 | memcpy(&hdr_disk2, &hdr_disk1, LUKS2_HDR_BIN_LEN); |
733 | 620 | r = crypt_random_get(cd, (char*)hdr_disk2.salt, sizeof(hdr_disk2.salt), CRYPT_RND_SALT); |
734 | 620 | if (r) |
735 | 0 | log_dbg(cd, "Cannot generate header salt."); |
736 | 620 | else { |
737 | 620 | hdr_from_disk(&hdr_disk1, &hdr_disk2, hdr, 0); |
738 | 620 | r = hdr_write_disk(cd, device, hdr, json_area1, hdr->hdr_size - LUKS2_HDR_BIN_LEN, 1); |
739 | 620 | } |
740 | 620 | if (r) |
741 | 310 | log_dbg(cd, "Secondary LUKS2 header recovery failed."); |
742 | 620 | } |
743 | 5.73k | } else if (state_hdr1 != HDR_OK && state_hdr2 == HDR_OK) { |
744 | 5.73k | log_dbg(cd, "Primary LUKS2 header requires recovery."); |
745 | | |
746 | 5.73k | if (do_blkprobe && (r = detect_device_signatures(cd, device_path(device)))) { |
747 | 1.92k | log_err(cd, _("Device contains ambiguous signatures, cannot auto-recover LUKS2.\n" |
748 | 1.92k | "Please run \"cryptsetup repair\" for recovery.")); |
749 | 1.92k | goto err; |
750 | 1.92k | } |
751 | | |
752 | 3.81k | if (do_recovery) { |
753 | 3.81k | memcpy(&hdr_disk1, &hdr_disk2, LUKS2_HDR_BIN_LEN); |
754 | 3.81k | r = crypt_random_get(cd, (char*)hdr_disk1.salt, sizeof(hdr_disk1.salt), CRYPT_RND_SALT); |
755 | 3.81k | if (r) |
756 | 0 | log_dbg(cd, "Cannot generate header salt."); |
757 | 3.81k | else { |
758 | 3.81k | hdr_from_disk(&hdr_disk2, &hdr_disk1, hdr, 1); |
759 | 3.81k | r = hdr_write_disk(cd, device, hdr, json_area2, hdr->hdr_size - LUKS2_HDR_BIN_LEN, 0); |
760 | 3.81k | } |
761 | 3.81k | if (r) |
762 | 1.90k | log_dbg(cd, "Primary LUKS2 header recovery failed."); |
763 | 3.81k | } |
764 | 3.81k | } |
765 | | |
766 | 4.43k | free(json_area1); |
767 | 4.43k | json_area1 = NULL; |
768 | 4.43k | free(json_area2); |
769 | 4.43k | json_area2 = NULL; |
770 | | |
771 | | /* wrong lock for write mode during recovery attempt */ |
772 | 4.43k | if (r == -EAGAIN) |
773 | 2.21k | goto err; |
774 | | |
775 | | /* |
776 | | * Even if status is failed, the second header includes salt. |
777 | | */ |
778 | 2.21k | if (state_hdr1 == HDR_OK) { |
779 | 310 | hdr_from_disk(&hdr_disk1, &hdr_disk2, hdr, 0); |
780 | 310 | hdr->jobj = jobj_hdr1; |
781 | 310 | json_object_put(jobj_hdr2); |
782 | 1.90k | } else if (state_hdr2 == HDR_OK) { |
783 | 1.90k | hdr_from_disk(&hdr_disk2, &hdr_disk1, hdr, 1); |
784 | 1.90k | hdr->jobj = jobj_hdr2; |
785 | 1.90k | json_object_put(jobj_hdr1); |
786 | 1.90k | } |
787 | | |
788 | 2.21k | if (json_area_end1 > json_area_end2) |
789 | 310 | hdr->on_disk_json_end_offset = json_area_end1; |
790 | 1.90k | else |
791 | 1.90k | hdr->on_disk_json_end_offset = json_area_end2; |
792 | | |
793 | | /* |
794 | | * FIXME: should this fail? At least one header was read correctly. |
795 | | * r = (state_hdr1 == HDR_FAIL_IO || state_hdr2 == HDR_FAIL_IO) ? -EIO : -EINVAL; |
796 | | */ |
797 | 2.21k | return 0; |
798 | 6.19k | err: |
799 | 6.19k | log_dbg(cd, "LUKS2 header read failed (%d).", r); |
800 | | |
801 | 6.19k | free(json_area1); |
802 | 6.19k | free(json_area2); |
803 | 6.19k | json_object_put(jobj_hdr1); |
804 | 6.19k | json_object_put(jobj_hdr2); |
805 | 6.19k | hdr->jobj = NULL; |
806 | 6.19k | return r; |
807 | 4.43k | } |
808 | | |
809 | | int LUKS2_hdr_version_unlocked(struct crypt_device *cd, struct device *device) |
810 | 8.03k | { |
811 | 8.03k | struct { |
812 | 8.03k | char magic[LUKS2_MAGIC_L]; |
813 | 8.03k | uint16_t version; |
814 | 8.03k | } __attribute__ ((packed)) hdr; |
815 | 8.03k | int r = 0, devfd, flags = O_RDONLY; |
816 | | |
817 | 8.03k | assert(cd); |
818 | 8.03k | assert(device); |
819 | | |
820 | 8.03k | if (device_direct_io(device)) |
821 | 8.03k | flags |= O_DIRECT; |
822 | | |
823 | 8.03k | devfd = device_open(cd, device, flags); |
824 | 8.03k | if (devfd != -1 && (read_lseek_blockwise(devfd, device_block_size(cd, device), |
825 | 8.03k | device_alignment(device), &hdr, sizeof(hdr), 0) == sizeof(hdr)) && |
826 | 8.03k | !memcmp(hdr.magic, LUKS2_MAGIC_1ST, LUKS2_MAGIC_L)) |
827 | 2.98k | r = (int)be16_to_cpu(hdr.version); |
828 | | |
829 | 8.03k | return r; |
830 | 8.03k | } |