/src/cryptsetup/lib/luks2/luks2_json_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-2025 Red Hat, Inc. All rights reserved. |
6 | | * Copyright (C) 2015-2025 Milan Broz |
7 | | * Copyright (C) 2015-2025 Ondrej Kozina |
8 | | */ |
9 | | |
10 | | #include "luks2_internal.h" |
11 | | #include "luks2/hw_opal/hw_opal.h" |
12 | | #include "../integrity/integrity.h" |
13 | | #include <ctype.h> |
14 | | #include <uuid/uuid.h> |
15 | | |
16 | | struct interval { |
17 | | uint64_t offset; |
18 | | uint64_t length; |
19 | | }; |
20 | | |
21 | | void hexprint_base64(struct crypt_device *cd, json_object *jobj, |
22 | | const char *sep, const char *line_sep) |
23 | 0 | { |
24 | 0 | char *buf = NULL; |
25 | 0 | size_t buf_len; |
26 | 0 | unsigned int i; |
27 | |
|
28 | 0 | if (crypt_base64_decode(&buf, &buf_len, json_object_get_string(jobj), |
29 | 0 | json_object_get_string_len(jobj))) |
30 | 0 | return; |
31 | | |
32 | 0 | for (i = 0; i < buf_len; i++) { |
33 | 0 | if (i && !(i % 16)) |
34 | 0 | log_std(cd, "\n\t%s", line_sep); |
35 | 0 | log_std(cd, "%02hhx%s", buf[i], sep); |
36 | 0 | } |
37 | 0 | log_std(cd, "\n"); |
38 | 0 | free(buf); |
39 | 0 | } |
40 | | |
41 | | void JSON_DBG(struct crypt_device *cd, json_object *jobj, const char *desc) |
42 | 0 | { |
43 | 0 | if (desc) |
44 | 0 | crypt_log(cd, CRYPT_LOG_DEBUG_JSON, desc); |
45 | 0 | crypt_log(cd, CRYPT_LOG_DEBUG_JSON, json_object_to_json_string_ext(jobj, |
46 | 0 | JSON_C_TO_STRING_PRETTY | JSON_C_TO_STRING_NOSLASHESCAPE)); |
47 | 0 | } |
48 | | |
49 | | /* |
50 | | * JSON array helpers |
51 | | */ |
52 | | json_object *LUKS2_array_jobj(json_object *array, const char *num) |
53 | 1.66k | { |
54 | 1.66k | json_object *jobj1; |
55 | 1.66k | int i; |
56 | | |
57 | 4.95k | for (i = 0; i < (int) json_object_array_length(array); i++) { |
58 | 3.29k | jobj1 = json_object_array_get_idx(array, i); |
59 | 3.29k | if (!strcmp(num, json_object_get_string(jobj1))) |
60 | 1 | return jobj1; |
61 | 3.29k | } |
62 | | |
63 | 1.66k | return NULL; |
64 | 1.66k | } |
65 | | |
66 | | json_object *LUKS2_array_remove(json_object *array, const char *num) |
67 | 0 | { |
68 | 0 | json_object *jobj1, *jobj_removing = NULL, *array_new; |
69 | 0 | int i; |
70 | |
|
71 | 0 | jobj_removing = LUKS2_array_jobj(array, num); |
72 | 0 | if (!jobj_removing) |
73 | 0 | return NULL; |
74 | | |
75 | | /* Create new array without jobj_removing. */ |
76 | 0 | array_new = json_object_new_array(); |
77 | 0 | if (!array_new) |
78 | 0 | return NULL; |
79 | | |
80 | 0 | for (i = 0; i < (int) json_object_array_length(array); i++) { |
81 | 0 | jobj1 = json_object_array_get_idx(array, i); |
82 | 0 | if (jobj1 != jobj_removing) |
83 | 0 | json_object_array_add(array_new, json_object_get(jobj1)); |
84 | 0 | } |
85 | |
|
86 | 0 | return array_new; |
87 | 0 | } |
88 | | |
89 | | /* |
90 | | * JSON struct access helpers |
91 | | */ |
92 | | json_object *LUKS2_get_keyslot_jobj(struct luks2_hdr *hdr, int keyslot) |
93 | 0 | { |
94 | 0 | json_object *jobj1, *jobj2; |
95 | 0 | char keyslot_name[16]; |
96 | |
|
97 | 0 | if (!hdr || keyslot < 0) |
98 | 0 | return NULL; |
99 | | |
100 | 0 | if (snprintf(keyslot_name, sizeof(keyslot_name), "%u", keyslot) < 1) |
101 | 0 | return NULL; |
102 | | |
103 | 0 | if (!json_object_object_get_ex(hdr->jobj, "keyslots", &jobj1)) |
104 | 0 | return NULL; |
105 | | |
106 | 0 | if (!json_object_object_get_ex(jobj1, keyslot_name, &jobj2)) |
107 | 0 | return NULL; |
108 | | |
109 | 0 | return jobj2; |
110 | 0 | } |
111 | | |
112 | | json_object *LUKS2_get_tokens_jobj(struct luks2_hdr *hdr) |
113 | 0 | { |
114 | 0 | json_object *jobj_tokens; |
115 | |
|
116 | 0 | if (!hdr || !json_object_object_get_ex(hdr->jobj, "tokens", &jobj_tokens)) |
117 | 0 | return NULL; |
118 | | |
119 | 0 | return jobj_tokens; |
120 | 0 | } |
121 | | |
122 | | json_object *LUKS2_get_token_jobj(struct luks2_hdr *hdr, int token) |
123 | 0 | { |
124 | 0 | json_object *jobj1, *jobj2; |
125 | 0 | char token_name[16]; |
126 | |
|
127 | 0 | if (!hdr || token < 0) |
128 | 0 | return NULL; |
129 | | |
130 | 0 | jobj1 = LUKS2_get_tokens_jobj(hdr); |
131 | 0 | if (!jobj1) |
132 | 0 | return NULL; |
133 | | |
134 | 0 | if (snprintf(token_name, sizeof(token_name), "%u", token) < 1) |
135 | 0 | return NULL; |
136 | | |
137 | 0 | json_object_object_get_ex(jobj1, token_name, &jobj2); |
138 | 0 | return jobj2; |
139 | 0 | } |
140 | | |
141 | | json_object *LUKS2_get_digest_jobj(struct luks2_hdr *hdr, int digest) |
142 | 0 | { |
143 | 0 | json_object *jobj1, *jobj2; |
144 | 0 | char digest_name[16]; |
145 | |
|
146 | 0 | if (!hdr || digest < 0) |
147 | 0 | return NULL; |
148 | | |
149 | 0 | if (snprintf(digest_name, sizeof(digest_name), "%u", digest) < 1) |
150 | 0 | return NULL; |
151 | | |
152 | 0 | if (!json_object_object_get_ex(hdr->jobj, "digests", &jobj1)) |
153 | 0 | return NULL; |
154 | | |
155 | 0 | json_object_object_get_ex(jobj1, digest_name, &jobj2); |
156 | 0 | return jobj2; |
157 | 0 | } |
158 | | |
159 | | static json_object *json_get_segments_jobj(json_object *hdr_jobj) |
160 | 10.7k | { |
161 | 10.7k | json_object *jobj_segments; |
162 | | |
163 | 10.7k | if (!hdr_jobj || !json_object_object_get_ex(hdr_jobj, "segments", &jobj_segments)) |
164 | 0 | return NULL; |
165 | | |
166 | 10.7k | return jobj_segments; |
167 | 10.7k | } |
168 | | |
169 | | json_object *LUKS2_get_segment_jobj(struct luks2_hdr *hdr, int segment) |
170 | 1.83k | { |
171 | 1.83k | if (!hdr) |
172 | 0 | return NULL; |
173 | | |
174 | 1.83k | if (segment == CRYPT_DEFAULT_SEGMENT) |
175 | 1.83k | segment = LUKS2_get_default_segment(hdr); |
176 | | |
177 | 1.83k | return json_segments_get_segment(json_get_segments_jobj(hdr->jobj), segment); |
178 | 1.83k | } |
179 | | |
180 | | json_object *LUKS2_get_segments_jobj(struct luks2_hdr *hdr) |
181 | 3.66k | { |
182 | 3.66k | return hdr ? json_get_segments_jobj(hdr->jobj) : NULL; |
183 | 3.66k | } |
184 | | |
185 | | int LUKS2_segments_count(struct luks2_hdr *hdr) |
186 | 1.83k | { |
187 | 1.83k | if (!hdr) |
188 | 0 | return -EINVAL; |
189 | | |
190 | 1.83k | return json_segments_count(LUKS2_get_segments_jobj(hdr)); |
191 | 1.83k | } |
192 | | |
193 | | int LUKS2_get_default_segment(struct luks2_hdr *hdr) |
194 | 1.83k | { |
195 | 1.83k | int s = LUKS2_get_segment_id_by_flag(hdr, "backup-final"); |
196 | 1.83k | if (s >= 0) |
197 | 1 | return s; |
198 | | |
199 | 1.83k | if (LUKS2_segments_count(hdr) >= 1) |
200 | 1.83k | return 0; |
201 | | |
202 | 0 | return -EINVAL; |
203 | 1.83k | } |
204 | | |
205 | | /* |
206 | | * json_type_int needs to be validated first. |
207 | | * See validate_json_uint32() |
208 | | */ |
209 | | uint32_t crypt_jobj_get_uint32(json_object *jobj) |
210 | 12 | { |
211 | 12 | return json_object_get_int64(jobj); |
212 | 12 | } |
213 | | |
214 | | /* jobj has to be json_type_string and numbered */ |
215 | | static bool json_str_to_uint64(json_object *jobj, uint64_t *value) |
216 | 59.9k | { |
217 | 59.9k | char *endptr; |
218 | 59.9k | unsigned long long tmp; |
219 | | |
220 | 59.9k | errno = 0; |
221 | 59.9k | tmp = strtoull(json_object_get_string(jobj), &endptr, 10); |
222 | 59.9k | if (*endptr || errno) { |
223 | 26 | *value = 0; |
224 | 26 | return false; |
225 | 26 | } |
226 | | |
227 | 59.9k | *value = tmp; |
228 | 59.9k | return true; |
229 | 59.9k | } |
230 | | |
231 | | uint64_t crypt_jobj_get_uint64(json_object *jobj) |
232 | 21.5k | { |
233 | 21.5k | uint64_t r; |
234 | 21.5k | json_str_to_uint64(jobj, &r); |
235 | 21.5k | return r; |
236 | 21.5k | } |
237 | | |
238 | | json_object *crypt_jobj_new_uint64(uint64_t value) |
239 | 0 | { |
240 | | /* 18446744073709551615 */ |
241 | 0 | char num[21]; |
242 | 0 | int r; |
243 | 0 | json_object *jobj; |
244 | |
|
245 | 0 | r = snprintf(num, sizeof(num), "%" PRIu64, value); |
246 | 0 | if (r < 0 || (size_t)r >= sizeof(num)) |
247 | 0 | return NULL; |
248 | | |
249 | 0 | jobj = json_object_new_string(num); |
250 | 0 | return jobj; |
251 | 0 | } |
252 | | |
253 | | /* |
254 | | * Validate helpers |
255 | | */ |
256 | | static bool numbered(struct crypt_device *cd, const char *name, const char *key) |
257 | 18.1k | { |
258 | 18.1k | int i; |
259 | | |
260 | 88.1k | for (i = 0; key[i]; i++) |
261 | 70.1k | if (!isdigit(key[i])) { |
262 | 46 | log_dbg(cd, "%s \"%s\" is not in numbered form.", name, key); |
263 | 46 | return false; |
264 | 46 | } |
265 | 18.0k | return true; |
266 | 18.1k | } |
267 | | |
268 | | json_object *json_contains(struct crypt_device *cd, json_object *jobj, const char *name, |
269 | | const char *section, const char *key, json_type type) |
270 | 84.1k | { |
271 | 84.1k | json_object *sobj; |
272 | | |
273 | 84.1k | if (!json_object_object_get_ex(jobj, key, &sobj) || |
274 | 81.2k | !json_object_is_type(sobj, type)) { |
275 | 2.97k | log_dbg(cd, "%s \"%s\" is missing \"%s\" (%s) specification.", |
276 | 2.97k | section, name, key, json_type_to_name(type)); |
277 | 2.97k | return NULL; |
278 | 2.97k | } |
279 | | |
280 | 81.1k | return sobj; |
281 | 84.1k | } |
282 | | |
283 | | json_object *json_contains_string(struct crypt_device *cd, json_object *jobj, |
284 | | const char *name, const char *section, const char *key) |
285 | 28.9k | { |
286 | 28.9k | json_object *sobj = json_contains(cd, jobj, name, section, key, json_type_string); |
287 | | |
288 | 28.9k | if (!sobj) |
289 | 58 | return NULL; |
290 | | |
291 | 28.8k | if (strlen(json_object_get_string(sobj)) < 1) |
292 | 10 | return NULL; |
293 | | |
294 | 28.8k | return sobj; |
295 | 28.8k | } |
296 | | |
297 | | bool validate_json_uint32(json_object *jobj) |
298 | 129 | { |
299 | 129 | int64_t tmp; |
300 | | |
301 | 129 | errno = 0; |
302 | 129 | tmp = json_object_get_int64(jobj); |
303 | | |
304 | 129 | return (errno || tmp < 0 || tmp > UINT32_MAX) ? false : true; |
305 | 129 | } |
306 | | |
307 | | static bool validate_keyslots_array(struct crypt_device *cd, json_object *jarr, json_object *jobj_keys) |
308 | 32 | { |
309 | 32 | json_object *jobj; |
310 | 32 | int i = 0, length = (int) json_object_array_length(jarr); |
311 | | |
312 | 72 | while (i < length) { |
313 | 50 | jobj = json_object_array_get_idx(jarr, i); |
314 | 50 | if (!json_object_is_type(jobj, json_type_string)) { |
315 | 0 | log_dbg(cd, "Illegal value type in keyslots array at index %d.", i); |
316 | 0 | return false; |
317 | 0 | } |
318 | | |
319 | 50 | if (!json_contains(cd, jobj_keys, "", "Keyslots section", |
320 | 50 | json_object_get_string(jobj), json_type_object)) |
321 | 10 | return false; |
322 | | |
323 | 40 | i++; |
324 | 40 | } |
325 | | |
326 | 22 | return true; |
327 | 32 | } |
328 | | |
329 | | static bool validate_segments_array(struct crypt_device *cd, json_object *jarr, json_object *jobj_segments) |
330 | 16 | { |
331 | 16 | json_object *jobj; |
332 | 16 | int i = 0, length = (int) json_object_array_length(jarr); |
333 | | |
334 | 70 | while (i < length) { |
335 | 58 | jobj = json_object_array_get_idx(jarr, i); |
336 | 58 | if (!json_object_is_type(jobj, json_type_string)) { |
337 | 0 | log_dbg(cd, "Illegal value type in segments array at index %d.", i); |
338 | 0 | return false; |
339 | 0 | } |
340 | | |
341 | 58 | if (!json_contains(cd, jobj_segments, "", "Segments section", |
342 | 58 | json_object_get_string(jobj), json_type_object)) |
343 | 4 | return false; |
344 | | |
345 | 54 | i++; |
346 | 54 | } |
347 | | |
348 | 12 | return true; |
349 | 16 | } |
350 | | |
351 | | static bool segment_has_digest(const char *segment_name, json_object *jobj_digests) |
352 | 2 | { |
353 | 2 | json_object *jobj_segments; |
354 | | |
355 | 2 | json_object_object_foreach(jobj_digests, key, val) { |
356 | 0 | UNUSED(key); |
357 | 0 | json_object_object_get_ex(val, "segments", &jobj_segments); |
358 | 0 | if (LUKS2_array_jobj(jobj_segments, segment_name)) |
359 | 0 | return true; |
360 | 0 | } |
361 | | |
362 | 2 | return false; |
363 | 2 | } |
364 | | |
365 | | |
366 | | static bool validate_intervals(struct crypt_device *cd, |
367 | | int length, const struct interval *ix, |
368 | | uint64_t metadata_size, uint64_t keyslots_area_end) |
369 | 13 | { |
370 | 13 | int j, i = 0; |
371 | | |
372 | 26 | while (i < length) { |
373 | | /* Offset cannot be inside primary or secondary JSON area */ |
374 | 13 | if (ix[i].offset < 2 * metadata_size) { |
375 | 0 | log_dbg(cd, "Illegal area offset: %" PRIu64 ".", ix[i].offset); |
376 | 0 | return false; |
377 | 0 | } |
378 | | |
379 | 13 | if (!ix[i].length) { |
380 | 0 | log_dbg(cd, "Area length must be greater than zero."); |
381 | 0 | return false; |
382 | 0 | } |
383 | | |
384 | 13 | if (ix[i].offset > (UINT64_MAX - ix[i].length)) { |
385 | 0 | log_dbg(cd, "Interval offset+length overflow."); |
386 | 0 | return false; |
387 | 0 | } |
388 | | |
389 | 13 | if ((ix[i].offset + ix[i].length) > keyslots_area_end) { |
390 | 0 | log_dbg(cd, "Area [%" PRIu64 ", %" PRIu64 "] overflows binary keyslots area (ends at offset: %" PRIu64 ").", |
391 | 0 | ix[i].offset, ix[i].offset + ix[i].length, keyslots_area_end); |
392 | 0 | return false; |
393 | 0 | } |
394 | | |
395 | 26 | for (j = 0; j < length; j++) { |
396 | 13 | if (i == j) |
397 | 13 | continue; |
398 | | |
399 | 0 | if (ix[j].offset > (UINT64_MAX - ix[j].length)) { |
400 | 0 | log_dbg(cd, "Interval offset+length overflow."); |
401 | 0 | return false; |
402 | 0 | } |
403 | | |
404 | 0 | if ((ix[i].offset >= ix[j].offset) && (ix[i].offset < (ix[j].offset + ix[j].length))) { |
405 | 0 | log_dbg(cd, "Overlapping areas [%" PRIu64 ",%" PRIu64 "] and [%" PRIu64 ",%" PRIu64 "].", |
406 | 0 | ix[i].offset, ix[i].offset + ix[i].length, |
407 | 0 | ix[j].offset, ix[j].offset + ix[j].length); |
408 | 0 | return false; |
409 | 0 | } |
410 | 0 | } |
411 | | |
412 | 13 | i++; |
413 | 13 | } |
414 | | |
415 | 13 | return true; |
416 | 13 | } |
417 | | |
418 | | static int LUKS2_keyslot_validate(struct crypt_device *cd, json_object *hdr_keyslot, const char *key) |
419 | 123 | { |
420 | 123 | json_object *jobj_key_size; |
421 | | |
422 | 123 | if (!json_contains_string(cd, hdr_keyslot, key, "Keyslot", "type")) |
423 | 2 | return 1; |
424 | 121 | if (!(jobj_key_size = json_contains(cd, hdr_keyslot, key, "Keyslot", "key_size", json_type_int))) |
425 | 6 | return 1; |
426 | | |
427 | | /* enforce uint32_t type */ |
428 | 115 | if (!validate_json_uint32(jobj_key_size)) { |
429 | 28 | log_dbg(cd, "Illegal field \"key_size\":%s.", |
430 | 28 | json_object_get_string(jobj_key_size)); |
431 | 28 | return 1; |
432 | 28 | } |
433 | | |
434 | 87 | return 0; |
435 | 115 | } |
436 | | |
437 | | int LUKS2_token_validate(struct crypt_device *cd, |
438 | | json_object *hdr_jobj, json_object *jobj_token, const char *key) |
439 | 24 | { |
440 | 24 | json_object *jarr, *jobj_keyslots; |
441 | | |
442 | | /* keyslots are not yet validated, but we need to know token doesn't reference missing keyslot */ |
443 | 24 | if (!json_object_object_get_ex(hdr_jobj, "keyslots", &jobj_keyslots)) |
444 | 2 | return 1; |
445 | | |
446 | 22 | if (!json_contains_string(cd, jobj_token, key, "Token", "type")) |
447 | 2 | return 1; |
448 | | |
449 | 20 | jarr = json_contains(cd, jobj_token, key, "Token", "keyslots", json_type_array); |
450 | 20 | if (!jarr) |
451 | 6 | return 1; |
452 | | |
453 | 14 | if (!validate_keyslots_array(cd, jarr, jobj_keyslots)) |
454 | 8 | return 1; |
455 | | |
456 | 6 | return 0; |
457 | 14 | } |
458 | | |
459 | | static int hdr_validate_json_size(struct crypt_device *cd, json_object *hdr_jobj, uint64_t hdr_json_size) |
460 | 5.25k | { |
461 | 5.25k | json_object *jobj, *jobj1; |
462 | 5.25k | const char *json; |
463 | 5.25k | uint64_t json_area_size, json_size; |
464 | | |
465 | 5.25k | json_object_object_get_ex(hdr_jobj, "config", &jobj); |
466 | 5.25k | json_object_object_get_ex(jobj, "json_size", &jobj1); |
467 | | |
468 | 5.25k | json = crypt_jobj_to_string_on_disk(hdr_jobj); |
469 | 5.25k | if (!json) |
470 | 0 | return 1; |
471 | | |
472 | 5.25k | json_area_size = crypt_jobj_get_uint64(jobj1); |
473 | 5.25k | json_size = (uint64_t)strlen(json); |
474 | | |
475 | 5.25k | if (hdr_json_size != json_area_size) { |
476 | 12 | log_dbg(cd, "JSON area size does not match value in binary header."); |
477 | 12 | return 1; |
478 | 12 | } |
479 | | |
480 | 5.24k | if (json_size > json_area_size) { |
481 | 6 | log_dbg(cd, "JSON does not fit in the designated area."); |
482 | 6 | return 1; |
483 | 6 | } |
484 | | |
485 | 5.23k | return 0; |
486 | 5.24k | } |
487 | | |
488 | | int LUKS2_check_json_size(struct crypt_device *cd, const struct luks2_hdr *hdr) |
489 | 0 | { |
490 | 0 | return hdr_validate_json_size(cd, hdr->jobj, hdr->hdr_size - LUKS2_HDR_BIN_LEN); |
491 | 0 | } |
492 | | |
493 | | static int hdr_validate_keyslots(struct crypt_device *cd, json_object *hdr_jobj) |
494 | 5.39k | { |
495 | 5.39k | json_object *jobj; |
496 | | |
497 | 5.39k | if (!(jobj = json_contains(cd, hdr_jobj, "", "JSON area", "keyslots", json_type_object))) |
498 | 0 | return 1; |
499 | | |
500 | 5.39k | json_object_object_foreach(jobj, key, val) { |
501 | 129 | if (!numbered(cd, "Keyslot", key)) |
502 | 6 | return 1; |
503 | 123 | if (LUKS2_keyslot_validate(cd, val, key)) |
504 | 36 | return 1; |
505 | 123 | } |
506 | | |
507 | 5.35k | return 0; |
508 | 5.39k | } |
509 | | |
510 | | static int hdr_validate_tokens(struct crypt_device *cd, json_object *hdr_jobj) |
511 | 6.05k | { |
512 | 6.05k | json_object *jobj; |
513 | | |
514 | 6.05k | if (!(jobj = json_contains(cd, hdr_jobj, "", "JSON area", "tokens", json_type_object))) |
515 | 436 | return 1; |
516 | | |
517 | 5.61k | json_object_object_foreach(jobj, key, val) { |
518 | 30 | if (!numbered(cd, "Token", key)) |
519 | 6 | return 1; |
520 | 24 | if (LUKS2_token_validate(cd, hdr_jobj, val, key)) |
521 | 18 | return 1; |
522 | 24 | } |
523 | | |
524 | 5.59k | return 0; |
525 | 5.61k | } |
526 | | |
527 | | static int hdr_validate_crypt_segment(struct crypt_device *cd, json_object *jobj, |
528 | | const char *key, json_object *jobj_digests, |
529 | | uint64_t size) |
530 | 34 | { |
531 | 34 | int r; |
532 | 34 | json_object *jobj_ivoffset, *jobj_sector_size, *jobj_integrity; |
533 | 34 | uint32_t sector_size; |
534 | 34 | uint64_t ivoffset; |
535 | | |
536 | 34 | if (!(jobj_ivoffset = json_contains_string(cd, jobj, key, "Segment", "iv_tweak")) || |
537 | 26 | !json_contains_string(cd, jobj, key, "Segment", "encryption") || |
538 | 24 | !(jobj_sector_size = json_contains(cd, jobj, key, "Segment", "sector_size", json_type_int))) |
539 | 14 | return 1; |
540 | | |
541 | | /* integrity */ |
542 | 20 | if (json_object_object_get_ex(jobj, "integrity", &jobj_integrity)) { |
543 | 8 | if (!json_contains(cd, jobj, key, "Segment", "integrity", json_type_object) || |
544 | 8 | !json_contains_string(cd, jobj_integrity, key, "Segment integrity", "type") || |
545 | 6 | !json_contains_string(cd, jobj_integrity, key, "Segment integrity", "journal_encryption") || |
546 | 4 | !json_contains_string(cd, jobj_integrity, key, "Segment integrity", "journal_integrity")) |
547 | 6 | return 1; |
548 | 8 | } |
549 | | |
550 | | /* enforce uint32_t type */ |
551 | 14 | if (!validate_json_uint32(jobj_sector_size)) { |
552 | 2 | log_dbg(cd, "Illegal field \"sector_size\":%s.", |
553 | 2 | json_object_get_string(jobj_sector_size)); |
554 | 2 | return 1; |
555 | 2 | } |
556 | | |
557 | 12 | sector_size = crypt_jobj_get_uint32(jobj_sector_size); |
558 | 12 | if (!sector_size || MISALIGNED_512(sector_size)) { |
559 | 4 | log_dbg(cd, "Illegal sector size: %" PRIu32, sector_size); |
560 | 4 | return 1; |
561 | 4 | } |
562 | | |
563 | 8 | if (!numbered(cd, "iv_tweak", json_object_get_string(jobj_ivoffset)) || |
564 | 4 | !json_str_to_uint64(jobj_ivoffset, &ivoffset)) { |
565 | 4 | log_dbg(cd, "Illegal iv_tweak value."); |
566 | 4 | return 1; |
567 | 4 | } |
568 | | |
569 | 4 | if (size % sector_size) { |
570 | 2 | log_dbg(cd, "Size field has to be aligned to sector size: %" PRIu32, sector_size); |
571 | 2 | return 1; |
572 | 2 | } |
573 | | |
574 | 2 | r = segment_has_digest(key, jobj_digests); |
575 | | |
576 | 2 | if (!r) |
577 | 2 | log_dbg(cd, "Crypt segment %s not assigned to key digest.", key); |
578 | | |
579 | 2 | return !r; |
580 | 4 | } |
581 | | |
582 | | static bool validate_segment_intervals(struct crypt_device *cd, |
583 | | int length, const struct interval *ix) |
584 | 5.41k | { |
585 | 5.41k | int j, i = 0; |
586 | | |
587 | 10.9k | while (i < length) { |
588 | 5.49k | if (ix[i].length == UINT64_MAX && (i != (length - 1))) { |
589 | 0 | log_dbg(cd, "Only last regular segment is allowed to have 'dynamic' size."); |
590 | 0 | return false; |
591 | 0 | } |
592 | | |
593 | 11.2k | for (j = 0; j < length; j++) { |
594 | 5.79k | if (i == j) |
595 | 5.49k | continue; |
596 | | |
597 | 300 | if (ix[j].length != UINT64_MAX && ix[j].offset > (UINT64_MAX - ix[j].length)) { |
598 | 0 | log_dbg(cd, "Interval offset+length overflow."); |
599 | 0 | return false; |
600 | 0 | } |
601 | | |
602 | 300 | if ((ix[i].offset >= ix[j].offset) && (ix[j].length == UINT64_MAX || (ix[i].offset < (ix[j].offset + ix[j].length)))) { |
603 | 2 | log_dbg(cd, "Overlapping segments [%" PRIu64 ",%" PRIu64 "]%s and [%" PRIu64 ",%" PRIu64 "]%s.", |
604 | 2 | ix[i].offset, ix[i].offset + ix[i].length, ix[i].length == UINT64_MAX ? "(dynamic)" : "", |
605 | 2 | ix[j].offset, ix[j].offset + ix[j].length, ix[j].length == UINT64_MAX ? "(dynamic)" : ""); |
606 | 2 | return false; |
607 | 2 | } |
608 | 300 | } |
609 | | |
610 | 5.49k | i++; |
611 | 5.49k | } |
612 | | |
613 | 5.41k | return true; |
614 | 5.41k | } |
615 | | |
616 | | static int reqs_unknown(uint32_t reqs) |
617 | 256 | { |
618 | 256 | return reqs & CRYPT_REQUIREMENT_UNKNOWN; |
619 | 256 | } |
620 | | |
621 | | static int reqs_reencrypt(uint32_t reqs) |
622 | 0 | { |
623 | 0 | return reqs & CRYPT_REQUIREMENT_OFFLINE_REENCRYPT; |
624 | 0 | } |
625 | | |
626 | | static int reqs_reencrypt_online(uint32_t reqs) |
627 | 5.40k | { |
628 | 5.40k | return reqs & CRYPT_REQUIREMENT_ONLINE_REENCRYPT; |
629 | 5.40k | } |
630 | | |
631 | | static int reqs_opal(uint32_t reqs) |
632 | 0 | { |
633 | 0 | return reqs & CRYPT_REQUIREMENT_OPAL; |
634 | 0 | } |
635 | | |
636 | | static int reqs_inline_hw_tags(uint32_t reqs) |
637 | 0 | { |
638 | 0 | return reqs & CRYPT_REQUIREMENT_INLINE_HW_TAGS; |
639 | 0 | } |
640 | | |
641 | | /* |
642 | | * Config section requirements object must be valid. |
643 | | * Also general segments section must be validated first. |
644 | | */ |
645 | | static int validate_reencrypt_segments(struct crypt_device *cd, json_object *hdr_jobj, json_object *jobj_segments, int first_backup, int segments_count) |
646 | 5.40k | { |
647 | 5.40k | json_object *jobj, *jobj_backup_previous = NULL, *jobj_backup_final = NULL; |
648 | 5.40k | uint32_t reqs; |
649 | 5.40k | int i; |
650 | 5.40k | struct luks2_hdr dummy = { |
651 | 5.40k | .jobj = hdr_jobj |
652 | 5.40k | }; |
653 | | |
654 | 5.40k | LUKS2_config_get_requirements(cd, &dummy, &reqs); |
655 | | |
656 | 5.40k | if (reqs_reencrypt_online(reqs)) { |
657 | 22 | for (i = first_backup; i < segments_count; i++) { |
658 | 12 | jobj = json_segments_get_segment(jobj_segments, i); |
659 | 12 | if (!jobj) |
660 | 0 | return 1; |
661 | 12 | if (json_segment_contains_flag(jobj, "backup-final", 0)) |
662 | 2 | jobj_backup_final = jobj; |
663 | 10 | else if (json_segment_contains_flag(jobj, "backup-previous", 0)) |
664 | 4 | jobj_backup_previous = jobj; |
665 | 12 | } |
666 | | |
667 | 10 | if (!jobj_backup_final || !jobj_backup_previous) { |
668 | 8 | log_dbg(cd, "Backup segment is missing."); |
669 | 8 | return 1; |
670 | 8 | } |
671 | | |
672 | 2 | for (i = 0; i < first_backup; i++) { |
673 | 2 | jobj = json_segments_get_segment(jobj_segments, i); |
674 | 2 | if (!jobj) |
675 | 0 | return 1; |
676 | | |
677 | 2 | if (json_segment_contains_flag(jobj, "in-reencryption", 0)) { |
678 | 0 | if (!json_segment_cmp(jobj, jobj_backup_final)) { |
679 | 0 | log_dbg(cd, "Segment in reencryption does not match backup final segment."); |
680 | 0 | return 1; |
681 | 0 | } |
682 | 0 | continue; |
683 | 0 | } |
684 | | |
685 | 2 | if (!json_segment_cmp(jobj, jobj_backup_final) && |
686 | 2 | !json_segment_cmp(jobj, jobj_backup_previous)) { |
687 | 2 | log_dbg(cd, "Segment does not match neither backup final or backup previous segment."); |
688 | 2 | return 1; |
689 | 2 | } |
690 | 2 | } |
691 | 2 | } |
692 | | |
693 | 5.39k | return 0; |
694 | 5.40k | } |
695 | | |
696 | | static int hdr_validate_segments(struct crypt_device *cd, json_object *hdr_jobj) |
697 | 5.56k | { |
698 | 5.56k | json_object *jobj_segments, *jobj_digests, *jobj_offset, *jobj_size, *jobj_type, *jobj_flags, *jobj; |
699 | 5.56k | uint64_t offset, size, opal_segment_size; |
700 | 5.56k | int i, r, count, first_backup = -1; |
701 | 5.56k | struct interval *intervals = NULL; |
702 | | |
703 | 5.56k | if (!(jobj_segments = json_contains(cd, hdr_jobj, "", "JSON area", "segments", json_type_object))) |
704 | 0 | return 1; |
705 | | |
706 | 5.56k | count = json_object_object_length(jobj_segments); |
707 | 5.56k | if (count < 1) { |
708 | 4 | log_dbg(cd, "Empty segments section."); |
709 | 4 | return 1; |
710 | 4 | } |
711 | | |
712 | | /* digests should already be validated */ |
713 | 5.55k | if (!json_object_object_get_ex(hdr_jobj, "digests", &jobj_digests)) |
714 | 0 | return 1; |
715 | | |
716 | 5.98k | json_object_object_foreach(jobj_segments, key, val) { |
717 | 5.98k | if (!numbered(cd, "Segment", key)) |
718 | 8 | return 1; |
719 | | |
720 | | /* those fields are mandatory for all segment types */ |
721 | 5.97k | if (!(jobj_type = json_contains_string(cd, val, key, "Segment", "type")) || |
722 | 5.96k | !(jobj_offset = json_contains_string(cd, val, key, "Segment", "offset")) || |
723 | 5.95k | !(jobj_size = json_contains_string(cd, val, key, "Segment", "size"))) |
724 | 24 | return 1; |
725 | | |
726 | 5.94k | if (!numbered(cd, "offset", json_object_get_string(jobj_offset))) |
727 | 4 | return 1; |
728 | | |
729 | 5.94k | if (!json_str_to_uint64(jobj_offset, &offset)) { |
730 | 0 | log_dbg(cd, "Illegal segment offset value."); |
731 | 0 | return 1; |
732 | 0 | } |
733 | | |
734 | | /* size "dynamic" means whole device starting at 'offset' */ |
735 | 5.94k | if (strcmp(json_object_get_string(jobj_size), "dynamic")) { |
736 | 5.94k | if (!numbered(cd, "size", json_object_get_string(jobj_size))) |
737 | 8 | return 1; |
738 | 5.93k | if (!json_str_to_uint64(jobj_size, &size) || !size) { |
739 | 8 | log_dbg(cd, "Illegal segment size value."); |
740 | 8 | return 1; |
741 | 8 | } |
742 | 5.93k | } else |
743 | 2 | size = 0; |
744 | | |
745 | | /* all device-mapper devices are aligned to 512 sector size */ |
746 | 5.92k | if (MISALIGNED_512(offset)) { |
747 | 8 | log_dbg(cd, "Offset field has to be aligned to sector size: %" PRIu32, SECTOR_SIZE); |
748 | 8 | return 1; |
749 | 8 | } |
750 | 5.92k | if (MISALIGNED_512(size)) { |
751 | 8 | log_dbg(cd, "Size field has to be aligned to sector size: %" PRIu32, SECTOR_SIZE); |
752 | 8 | return 1; |
753 | 8 | } |
754 | | |
755 | | /* flags array is optional and must contain strings */ |
756 | 5.91k | if (json_object_object_get_ex(val, "flags", NULL)) { |
757 | 5.36k | if (!(jobj_flags = json_contains(cd, val, key, "Segment", "flags", json_type_array))) |
758 | 0 | return 1; |
759 | 17.1k | for (i = 0; i < (int) json_object_array_length(jobj_flags); i++) |
760 | 11.8k | if (!json_object_is_type(json_object_array_get_idx(jobj_flags, i), json_type_string)) |
761 | 2 | return 1; |
762 | 5.36k | } |
763 | | |
764 | 5.91k | i = atoi(key); |
765 | 5.91k | if (json_segment_is_backup(val)) { |
766 | 294 | if (first_backup < 0 || i < first_backup) |
767 | 198 | first_backup = i; |
768 | 5.61k | } else { |
769 | 5.61k | if ((first_backup >= 0) && i >= first_backup) { |
770 | 2 | log_dbg(cd, "Regular segment at %d is behind backup segment at %d", i, first_backup); |
771 | 2 | return 1; |
772 | 2 | } |
773 | 5.61k | } |
774 | | |
775 | | /* crypt */ |
776 | 5.90k | if (!strcmp(json_object_get_string(jobj_type), "crypt") && |
777 | 34 | hdr_validate_crypt_segment(cd, val, key, jobj_digests, size)) |
778 | 34 | return 1; |
779 | | |
780 | | /* opal */ |
781 | 5.87k | if (!strncmp(json_object_get_string(jobj_type), "hw-opal", 7)) { |
782 | 2 | if (!size) { |
783 | 0 | log_dbg(cd, "segment type %s does not support dynamic size.", |
784 | 0 | json_object_get_string(jobj_type)); |
785 | 0 | return 1; |
786 | 0 | } |
787 | 2 | if (!json_contains(cd, val, key, "Segment", "opal_segment_number", json_type_int) || |
788 | 0 | !json_contains(cd, val, key, "Segment", "opal_key_size", json_type_int) || |
789 | 0 | !(jobj_size = json_contains_string(cd, val, key, "Segment", "opal_segment_size"))) |
790 | 2 | return 1; |
791 | 0 | if (!numbered(cd, "opal_segment_size", json_object_get_string(jobj_size))) |
792 | 0 | return 1; |
793 | 0 | if (!json_str_to_uint64(jobj_size, &opal_segment_size) || !opal_segment_size) { |
794 | 0 | log_dbg(cd, "Illegal OPAL segment size value."); |
795 | 0 | return 1; |
796 | 0 | } |
797 | 0 | if (size > opal_segment_size) { |
798 | 0 | log_dbg(cd, "segment size overflows OPAL locking range size."); |
799 | 0 | return 1; |
800 | 0 | } |
801 | 0 | if (!strcmp(json_object_get_string(jobj_type), "hw-opal-crypt") && |
802 | 0 | hdr_validate_crypt_segment(cd, val, key, jobj_digests, size)) |
803 | 0 | return 1; |
804 | 0 | } |
805 | 5.87k | } |
806 | | |
807 | 5.44k | if (first_backup == 0) { |
808 | 2 | log_dbg(cd, "No regular segment."); |
809 | 2 | return 1; |
810 | 2 | } |
811 | | |
812 | | /* avoid needlessly large allocation when first backup segment is invalid */ |
813 | 5.44k | if (first_backup >= count) { |
814 | 16 | log_dbg(cd, "Gap between last regular segment and backup segment at key %d.", first_backup); |
815 | 16 | return 1; |
816 | 16 | } |
817 | | |
818 | 5.43k | if (first_backup < 0) |
819 | 5.39k | first_backup = count; |
820 | | |
821 | 5.43k | if ((size_t)first_backup < SIZE_MAX / sizeof(*intervals)) |
822 | 5.43k | intervals = malloc(first_backup * sizeof(*intervals)); |
823 | | |
824 | 5.43k | if (!intervals) { |
825 | 0 | log_dbg(cd, "Not enough memory."); |
826 | 0 | return 1; |
827 | 0 | } |
828 | | |
829 | 10.9k | for (i = 0; i < first_backup; i++) { |
830 | 5.51k | jobj = json_segments_get_segment(jobj_segments, i); |
831 | 5.51k | if (!jobj) { |
832 | 18 | log_dbg(cd, "Gap at key %d in segments object.", i); |
833 | 18 | free(intervals); |
834 | 18 | return 1; |
835 | 18 | } |
836 | 5.49k | intervals[i].offset = json_segment_get_offset(jobj, 0); |
837 | 5.49k | intervals[i].length = json_segment_get_size(jobj, 0) ?: UINT64_MAX; |
838 | 5.49k | } |
839 | | |
840 | 5.41k | r = !validate_segment_intervals(cd, first_backup, intervals); |
841 | 5.41k | free(intervals); |
842 | | |
843 | 5.41k | if (r) |
844 | 2 | return 1; |
845 | | |
846 | 5.48k | for (; i < count; i++) { |
847 | 79 | if (!json_segments_get_segment(jobj_segments, i)) { |
848 | 6 | log_dbg(cd, "Gap at key %d in segments object.", i); |
849 | 6 | return 1; |
850 | 6 | } |
851 | 79 | } |
852 | | |
853 | 5.40k | return validate_reencrypt_segments(cd, hdr_jobj, jobj_segments, first_backup, count); |
854 | 5.41k | } |
855 | | |
856 | | static uint64_t LUKS2_metadata_size_jobj(json_object *jobj) |
857 | 10.5k | { |
858 | 10.5k | json_object *jobj1, *jobj2; |
859 | 10.5k | uint64_t json_size; |
860 | | |
861 | 10.5k | json_object_object_get_ex(jobj, "config", &jobj1); |
862 | 10.5k | json_object_object_get_ex(jobj1, "json_size", &jobj2); |
863 | 10.5k | json_str_to_uint64(jobj2, &json_size); |
864 | | |
865 | 10.5k | return json_size + LUKS2_HDR_BIN_LEN; |
866 | 10.5k | } |
867 | | |
868 | | uint64_t LUKS2_metadata_size(struct luks2_hdr *hdr) |
869 | 0 | { |
870 | 0 | return LUKS2_metadata_size_jobj(hdr->jobj); |
871 | 0 | } |
872 | | |
873 | | static int hdr_validate_areas(struct crypt_device *cd, json_object *hdr_jobj) |
874 | 5.27k | { |
875 | 5.27k | struct interval *intervals; |
876 | 5.27k | json_object *jobj_keyslots, *jobj_offset, *jobj_length, *jobj_segments, *jobj_area; |
877 | 5.27k | int length, ret, i = 0; |
878 | 5.27k | uint64_t metadata_size; |
879 | | |
880 | 5.27k | if (!json_object_object_get_ex(hdr_jobj, "keyslots", &jobj_keyslots)) |
881 | 0 | return 1; |
882 | | |
883 | | /* segments are already validated */ |
884 | 5.27k | if (!json_object_object_get_ex(hdr_jobj, "segments", &jobj_segments)) |
885 | 0 | return 1; |
886 | | |
887 | | /* config is already validated */ |
888 | 5.27k | metadata_size = LUKS2_metadata_size_jobj(hdr_jobj); |
889 | | |
890 | 5.27k | length = json_object_object_length(jobj_keyslots); |
891 | | |
892 | | /* Empty section */ |
893 | 5.27k | if (length == 0) |
894 | 5.24k | return 0; |
895 | | |
896 | 31 | if (length < 0) { |
897 | 0 | log_dbg(cd, "Invalid keyslot areas specification."); |
898 | 0 | return 1; |
899 | 0 | } |
900 | | |
901 | 31 | intervals = malloc(length * sizeof(*intervals)); |
902 | 31 | if (!intervals) { |
903 | 0 | log_dbg(cd, "Not enough memory."); |
904 | 0 | return -ENOMEM; |
905 | 0 | } |
906 | | |
907 | 31 | json_object_object_foreach(jobj_keyslots, key, val) { |
908 | | |
909 | 31 | if (!(jobj_area = json_contains(cd, val, key, "Keyslot", "area", json_type_object)) || |
910 | 29 | !json_contains_string(cd, jobj_area, key, "Keyslot area", "type") || |
911 | 27 | !(jobj_offset = json_contains_string(cd, jobj_area, key, "Keyslot", "offset")) || |
912 | 25 | !(jobj_length = json_contains_string(cd, jobj_area, key, "Keyslot", "size")) || |
913 | 23 | !numbered(cd, "offset", json_object_get_string(jobj_offset)) || |
914 | 19 | !numbered(cd, "size", json_object_get_string(jobj_length))) { |
915 | 14 | free(intervals); |
916 | 14 | return 1; |
917 | 14 | } |
918 | | |
919 | | /* rule out values > UINT64_MAX */ |
920 | 17 | if (!json_str_to_uint64(jobj_offset, &intervals[i].offset) || |
921 | 17 | !json_str_to_uint64(jobj_length, &intervals[i].length)) { |
922 | 4 | log_dbg(cd, "Illegal keyslot area values."); |
923 | 4 | free(intervals); |
924 | 4 | return 1; |
925 | 4 | } |
926 | | |
927 | 13 | i++; |
928 | 13 | } |
929 | | |
930 | 13 | if (length != i) { |
931 | 0 | free(intervals); |
932 | 0 | return 1; |
933 | 0 | } |
934 | | |
935 | 13 | ret = validate_intervals(cd, length, intervals, metadata_size, LUKS2_hdr_and_areas_size_jobj(hdr_jobj)) ? 0 : 1; |
936 | | |
937 | 13 | free(intervals); |
938 | | |
939 | 13 | return ret; |
940 | 13 | } |
941 | | |
942 | | static int hdr_validate_digests(struct crypt_device *cd, json_object *hdr_jobj) |
943 | 5.59k | { |
944 | 5.59k | json_object *jarr_keys, *jarr_segs, *jobj, *jobj_keyslots, *jobj_segments; |
945 | | |
946 | 5.59k | if (!(jobj = json_contains(cd, hdr_jobj, "", "JSON area", "digests", json_type_object))) |
947 | 8 | return 1; |
948 | | |
949 | | /* keyslots are not yet validated, but we need to know digest doesn't reference missing keyslot */ |
950 | 5.58k | if (!(jobj_keyslots = json_contains(cd, hdr_jobj, "", "JSON area", "keyslots", json_type_object))) |
951 | 2 | return 1; |
952 | | |
953 | | /* segments are not yet validated, but we need to know digest doesn't reference missing segment */ |
954 | 5.58k | if (!(jobj_segments = json_contains(cd, hdr_jobj, "", "JSON area", "segments", json_type_object))) |
955 | 2 | return 1; |
956 | | |
957 | 5.58k | json_object_object_foreach(jobj, key, val) { |
958 | 34 | if (!numbered(cd, "Digest", key)) |
959 | 4 | return 1; |
960 | | |
961 | 30 | if (!json_contains_string(cd, val, key, "Digest", "type") || |
962 | 26 | !(jarr_keys = json_contains(cd, val, key, "Digest", "keyslots", json_type_array)) || |
963 | 20 | !(jarr_segs = json_contains(cd, val, key, "Digest", "segments", json_type_array))) |
964 | 12 | return 1; |
965 | | |
966 | 18 | if (!validate_keyslots_array(cd, jarr_keys, jobj_keyslots)) |
967 | 2 | return 1; |
968 | 16 | if (!validate_segments_array(cd, jarr_segs, jobj_segments)) |
969 | 4 | return 1; |
970 | 16 | } |
971 | | |
972 | 5.56k | return 0; |
973 | 5.58k | } |
974 | | |
975 | | /* requirements being validated in stand-alone routine */ |
976 | | static int hdr_validate_config(struct crypt_device *cd, json_object *hdr_jobj) |
977 | 5.35k | { |
978 | 5.35k | json_object *jobj_config, *jobj; |
979 | 5.35k | int i; |
980 | 5.35k | uint64_t keyslots_size, metadata_size, segment_offset; |
981 | | |
982 | 5.35k | if (!(jobj_config = json_contains(cd, hdr_jobj, "", "JSON area", "config", json_type_object))) |
983 | 0 | return 1; |
984 | | |
985 | 5.35k | if (!(jobj = json_contains_string(cd, jobj_config, "section", "Config", "json_size"))) |
986 | 12 | return 1; |
987 | 5.34k | if (!json_str_to_uint64(jobj, &metadata_size)) { |
988 | 6 | log_dbg(cd, "Illegal config json_size value."); |
989 | 6 | return 1; |
990 | 6 | } |
991 | | |
992 | | /* single metadata instance is assembled from json area size plus |
993 | | * binary header size */ |
994 | 5.33k | metadata_size += LUKS2_HDR_BIN_LEN; |
995 | | |
996 | 5.33k | if (!(jobj = json_contains_string(cd, jobj_config, "section", "Config", "keyslots_size"))) |
997 | 2 | return 1; |
998 | 5.33k | if(!json_str_to_uint64(jobj, &keyslots_size)) { |
999 | 8 | log_dbg(cd, "Illegal config keyslot_size value."); |
1000 | 8 | return 1; |
1001 | 8 | } |
1002 | | |
1003 | 5.32k | if (LUKS2_check_metadata_area_size(metadata_size)) { |
1004 | 32 | log_dbg(cd, "Unsupported LUKS2 header size (%" PRIu64 ").", metadata_size); |
1005 | 32 | return 1; |
1006 | 32 | } |
1007 | | |
1008 | 5.29k | if (LUKS2_check_keyslots_area_size(keyslots_size)) { |
1009 | 4 | log_dbg(cd, "Unsupported LUKS2 keyslots size (%" PRIu64 ").", keyslots_size); |
1010 | 4 | return 1; |
1011 | 4 | } |
1012 | | |
1013 | | /* |
1014 | | * validate keyslots_size fits in between (2 * metadata_size) and first |
1015 | | * segment_offset (except detached header) |
1016 | | */ |
1017 | 5.28k | segment_offset = json_segments_get_minimal_offset(json_get_segments_jobj(hdr_jobj), 0); |
1018 | 5.28k | if (segment_offset && |
1019 | 2.94k | (segment_offset < keyslots_size || |
1020 | 2.93k | (segment_offset - keyslots_size) < (2 * metadata_size))) { |
1021 | 12 | log_dbg(cd, "keyslots_size is too large %" PRIu64 " (bytes). Data offset: %" PRIu64 |
1022 | 12 | ", keyslots offset: %" PRIu64, keyslots_size, segment_offset, 2 * metadata_size); |
1023 | 12 | return 1; |
1024 | 12 | } |
1025 | | |
1026 | | /* Flags array is optional */ |
1027 | 5.27k | if (json_object_object_get_ex(jobj_config, "flags", &jobj)) { |
1028 | 412 | if (!json_contains(cd, jobj_config, "section", "Config", "flags", json_type_array)) |
1029 | 0 | return 1; |
1030 | | |
1031 | | /* All array members must be strings */ |
1032 | 3.46k | for (i = 0; i < (int) json_object_array_length(jobj); i++) |
1033 | 3.05k | if (!json_object_is_type(json_object_array_get_idx(jobj, i), json_type_string)) |
1034 | 2 | return 1; |
1035 | 412 | } |
1036 | | |
1037 | 5.27k | return 0; |
1038 | 5.27k | } |
1039 | | |
1040 | | static bool reencrypt_candidate_flag(const char *flag) |
1041 | 4.20k | { |
1042 | 4.20k | const char *ptr; |
1043 | | |
1044 | 4.20k | assert(flag); |
1045 | | |
1046 | 4.20k | if (!strcmp(flag, "online-reencrypt")) |
1047 | 224 | return true; |
1048 | | |
1049 | 3.97k | if (strncmp(flag, "online-reencrypt-v", 18)) |
1050 | 2.92k | return false; |
1051 | | |
1052 | 1.05k | ptr = flag + 18; |
1053 | 1.05k | if (!*ptr) |
1054 | 200 | return false; |
1055 | | |
1056 | 1.89k | while (*ptr) { |
1057 | 1.29k | if (!isdigit(*ptr)) |
1058 | 260 | return false; |
1059 | 1.03k | ptr++; |
1060 | 1.03k | } |
1061 | | |
1062 | 596 | return true; |
1063 | 856 | } |
1064 | | |
1065 | | static int hdr_validate_requirements(struct crypt_device *cd, json_object *hdr_jobj) |
1066 | 8.57k | { |
1067 | 8.57k | int i; |
1068 | 8.57k | json_object *jobj_config, *jobj, *jobj1; |
1069 | 8.57k | unsigned online_reencrypt_flag = 0; |
1070 | | |
1071 | 8.57k | if (!(jobj_config = json_contains(cd, hdr_jobj, "", "JSON area", "config", json_type_object))) |
1072 | 2.41k | return 1; |
1073 | | |
1074 | | /* Requirements object is optional */ |
1075 | 6.16k | if (json_object_object_get_ex(jobj_config, "requirements", &jobj)) { |
1076 | 727 | if (!json_contains(cd, jobj_config, "section", "Config", "requirements", json_type_object)) |
1077 | 8 | return 1; |
1078 | | |
1079 | | /* Mandatory array is optional */ |
1080 | 719 | if (json_object_object_get_ex(jobj, "mandatory", &jobj1)) { |
1081 | 652 | if (!json_contains(cd, jobj, "section", "Requirements", "mandatory", json_type_array)) |
1082 | 8 | return 1; |
1083 | | |
1084 | | /* All array members must be strings */ |
1085 | 4.84k | for (i = 0; i < (int) json_object_array_length(jobj1); i++) { |
1086 | 4.24k | if (!json_object_is_type(json_object_array_get_idx(jobj1, i), json_type_string)) |
1087 | 40 | return 1; |
1088 | | |
1089 | 4.20k | if (reencrypt_candidate_flag(json_object_get_string(json_object_array_get_idx(jobj1, i)))) |
1090 | 820 | online_reencrypt_flag++; |
1091 | | |
1092 | 4.20k | } |
1093 | 644 | } |
1094 | 719 | } |
1095 | | |
1096 | 6.10k | if (online_reencrypt_flag > 1) { |
1097 | 52 | log_dbg(cd, "Multiple online reencryption requirement flags detected."); |
1098 | 52 | return 1; |
1099 | 52 | } |
1100 | | |
1101 | 6.05k | return 0; |
1102 | 6.10k | } |
1103 | | |
1104 | | int LUKS2_hdr_validate(struct crypt_device *cd, json_object *hdr_jobj, uint64_t json_size) |
1105 | 8.57k | { |
1106 | 8.57k | struct { |
1107 | 8.57k | int (*validate)(struct crypt_device *, json_object *); |
1108 | 8.57k | } checks[] = { |
1109 | 8.57k | { hdr_validate_requirements }, |
1110 | 8.57k | { hdr_validate_tokens }, |
1111 | 8.57k | { hdr_validate_digests }, |
1112 | 8.57k | { hdr_validate_segments }, |
1113 | 8.57k | { hdr_validate_keyslots }, |
1114 | 8.57k | { hdr_validate_config }, |
1115 | 8.57k | { hdr_validate_areas }, |
1116 | 8.57k | { NULL } |
1117 | 8.57k | }; |
1118 | 8.57k | int i; |
1119 | | |
1120 | 8.57k | if (!hdr_jobj) |
1121 | 0 | return 1; |
1122 | | |
1123 | 47.0k | for (i = 0; checks[i].validate; i++) |
1124 | 41.8k | if (checks[i].validate && checks[i].validate(cd, hdr_jobj)) |
1125 | 3.31k | return 1; |
1126 | | |
1127 | 5.25k | if (hdr_validate_json_size(cd, hdr_jobj, json_size)) |
1128 | 18 | return 1; |
1129 | | |
1130 | | /* validate keyslot implementations */ |
1131 | 5.23k | if (LUKS2_keyslots_validate(cd, hdr_jobj)) |
1132 | 0 | return 1; |
1133 | | |
1134 | 5.23k | return 0; |
1135 | 5.23k | } |
1136 | | |
1137 | | static bool hdr_json_free(json_object **jobj) |
1138 | 5.50k | { |
1139 | 5.50k | assert(jobj); |
1140 | | |
1141 | 5.50k | if (json_object_put(*jobj)) |
1142 | 3.66k | *jobj = NULL; |
1143 | | |
1144 | 5.50k | return (*jobj == NULL); |
1145 | 5.50k | } |
1146 | | |
1147 | | static int hdr_update_copy_for_rollback(struct crypt_device *cd, struct luks2_hdr *hdr) |
1148 | 1.83k | { |
1149 | 1.83k | json_object **jobj_copy; |
1150 | | |
1151 | 1.83k | assert(hdr); |
1152 | 1.83k | assert(hdr->jobj); |
1153 | | |
1154 | 1.83k | jobj_copy = (json_object **)&hdr->jobj_rollback; |
1155 | | |
1156 | 1.83k | if (!hdr_json_free(jobj_copy)) { |
1157 | 0 | log_dbg(cd, "LUKS2 rollback metadata copy still in use"); |
1158 | 0 | return -EINVAL; |
1159 | 0 | } |
1160 | | |
1161 | 1.83k | return json_object_copy(hdr->jobj, jobj_copy) ? -ENOMEM : 0; |
1162 | 1.83k | } |
1163 | | |
1164 | | /* FIXME: should we expose do_recovery parameter explicitly? */ |
1165 | | int LUKS2_hdr_read(struct crypt_device *cd, struct luks2_hdr *hdr, int repair) |
1166 | 7.98k | { |
1167 | 7.98k | int r; |
1168 | | |
1169 | 7.98k | r = device_read_lock(cd, crypt_metadata_device(cd)); |
1170 | 7.98k | if (r) { |
1171 | 0 | log_err(cd, _("Failed to acquire read lock on device %s."), |
1172 | 0 | device_path(crypt_metadata_device(cd))); |
1173 | 0 | return r; |
1174 | 0 | } |
1175 | | |
1176 | 7.98k | r = LUKS2_disk_hdr_read(cd, hdr, crypt_metadata_device(cd), 1, !repair); |
1177 | 7.98k | if (r == -EAGAIN) { |
1178 | | /* unlikely: auto-recovery is required and failed due to read lock being held */ |
1179 | 1.83k | device_read_unlock(cd, crypt_metadata_device(cd)); |
1180 | | |
1181 | | /* Do not use LUKS2_device_write lock. Recovery. */ |
1182 | 1.83k | r = device_write_lock(cd, crypt_metadata_device(cd)); |
1183 | 1.83k | if (r < 0) { |
1184 | 0 | log_err(cd, _("Failed to acquire write lock on device %s."), |
1185 | 0 | device_path(crypt_metadata_device(cd))); |
1186 | 0 | return r; |
1187 | 0 | } |
1188 | | |
1189 | 1.83k | r = LUKS2_disk_hdr_read(cd, hdr, crypt_metadata_device(cd), 1, !repair); |
1190 | | |
1191 | 1.83k | device_write_unlock(cd, crypt_metadata_device(cd)); |
1192 | 1.83k | } else |
1193 | 6.15k | device_read_unlock(cd, crypt_metadata_device(cd)); |
1194 | | |
1195 | 7.98k | if (!r && (r = hdr_update_copy_for_rollback(cd, hdr))) |
1196 | 0 | log_dbg(cd, "Failed to update rollback LUKS2 metadata."); |
1197 | | |
1198 | 7.98k | return r; |
1199 | 7.98k | } |
1200 | | |
1201 | | static int hdr_cleanup_and_validate(struct crypt_device *cd, struct luks2_hdr *hdr) |
1202 | 0 | { |
1203 | 0 | LUKS2_digests_erase_unused(cd, hdr); |
1204 | |
|
1205 | 0 | return LUKS2_hdr_validate(cd, hdr->jobj, hdr->hdr_size - LUKS2_HDR_BIN_LEN); |
1206 | 0 | } |
1207 | | |
1208 | | int LUKS2_hdr_write_force(struct crypt_device *cd, struct luks2_hdr *hdr) |
1209 | 0 | { |
1210 | 0 | int r; |
1211 | |
|
1212 | 0 | if (hdr_cleanup_and_validate(cd, hdr)) |
1213 | 0 | return -EINVAL; |
1214 | | |
1215 | 0 | r = LUKS2_disk_hdr_write(cd, hdr, crypt_metadata_device(cd), false); |
1216 | |
|
1217 | 0 | if (!r && (r = hdr_update_copy_for_rollback(cd, hdr))) |
1218 | 0 | log_dbg(cd, "Failed to update rollback LUKS2 metadata."); |
1219 | |
|
1220 | 0 | return r; |
1221 | 0 | } |
1222 | | |
1223 | | int LUKS2_hdr_write(struct crypt_device *cd, struct luks2_hdr *hdr) |
1224 | 0 | { |
1225 | 0 | int r; |
1226 | |
|
1227 | 0 | if (hdr_cleanup_and_validate(cd, hdr)) |
1228 | 0 | return -EINVAL; |
1229 | | |
1230 | 0 | r = LUKS2_disk_hdr_write(cd, hdr, crypt_metadata_device(cd), true); |
1231 | |
|
1232 | 0 | if (!r && (r = hdr_update_copy_for_rollback(cd, hdr))) |
1233 | 0 | log_dbg(cd, "Failed to update rollback LUKS2 metadata."); |
1234 | |
|
1235 | 0 | return r; |
1236 | 0 | } |
1237 | | |
1238 | | int LUKS2_hdr_rollback(struct crypt_device *cd, struct luks2_hdr *hdr) |
1239 | 0 | { |
1240 | 0 | json_object **jobj_copy; |
1241 | |
|
1242 | 0 | assert(hdr->jobj_rollback); |
1243 | |
|
1244 | 0 | log_dbg(cd, "Rolling back in-memory LUKS2 json metadata."); |
1245 | |
|
1246 | 0 | jobj_copy = (json_object **)&hdr->jobj; |
1247 | |
|
1248 | 0 | if (!hdr_json_free(jobj_copy)) { |
1249 | 0 | log_dbg(cd, "LUKS2 header still in use"); |
1250 | 0 | return -EINVAL; |
1251 | 0 | } |
1252 | | |
1253 | 0 | return json_object_copy(hdr->jobj_rollback, jobj_copy) ? -ENOMEM : 0; |
1254 | 0 | } |
1255 | | |
1256 | | int LUKS2_hdr_uuid(struct crypt_device *cd, struct luks2_hdr *hdr, const char *uuid) |
1257 | 0 | { |
1258 | 0 | uuid_t partitionUuid; |
1259 | |
|
1260 | 0 | if (uuid && uuid_parse(uuid, partitionUuid) == -1) { |
1261 | 0 | log_err(cd, _("Wrong LUKS UUID format provided.")); |
1262 | 0 | return -EINVAL; |
1263 | 0 | } |
1264 | 0 | if (!uuid) |
1265 | 0 | uuid_generate(partitionUuid); |
1266 | |
|
1267 | 0 | uuid_unparse(partitionUuid, hdr->uuid); |
1268 | |
|
1269 | 0 | return LUKS2_hdr_write(cd, hdr); |
1270 | 0 | } |
1271 | | |
1272 | | int LUKS2_hdr_labels(struct crypt_device *cd, struct luks2_hdr *hdr, |
1273 | | const char *label, const char *subsystem, int commit) |
1274 | 0 | { |
1275 | 0 | if ((label && strlen(label) >= LUKS2_LABEL_L) || |
1276 | 0 | (subsystem && strlen(subsystem) >= LUKS2_LABEL_L)) { |
1277 | 0 | log_err(cd, _("Label is too long.")); |
1278 | 0 | return -EINVAL; |
1279 | 0 | } |
1280 | | |
1281 | 0 | memset(hdr->label, 0, LUKS2_LABEL_L); |
1282 | 0 | if (label) |
1283 | 0 | strncpy(hdr->label, label, LUKS2_LABEL_L-1); |
1284 | |
|
1285 | 0 | memset(hdr->subsystem, 0, LUKS2_LABEL_L); |
1286 | 0 | if (subsystem) |
1287 | 0 | strncpy(hdr->subsystem, subsystem, LUKS2_LABEL_L-1); |
1288 | |
|
1289 | 0 | return commit ? LUKS2_hdr_write(cd, hdr) : 0; |
1290 | 0 | } |
1291 | | |
1292 | | void LUKS2_hdr_free(struct crypt_device *cd, struct luks2_hdr *hdr) |
1293 | 1.83k | { |
1294 | 1.83k | json_object **jobj; |
1295 | | |
1296 | 1.83k | assert(hdr); |
1297 | | |
1298 | 1.83k | jobj = (json_object **)&hdr->jobj; |
1299 | | |
1300 | 1.83k | if (!hdr_json_free(jobj)) |
1301 | 0 | log_dbg(cd, "LUKS2 header still in use"); |
1302 | | |
1303 | 1.83k | jobj = (json_object **)&hdr->jobj_rollback; |
1304 | | |
1305 | 1.83k | if (!hdr_json_free(jobj)) |
1306 | 0 | log_dbg(cd, "LUKS2 rollback metadata copy still in use"); |
1307 | 1.83k | } |
1308 | | |
1309 | | static uint64_t LUKS2_keyslots_size_jobj(json_object *jobj) |
1310 | 5.25k | { |
1311 | 5.25k | json_object *jobj1, *jobj2; |
1312 | 5.25k | uint64_t keyslots_size; |
1313 | | |
1314 | 5.25k | json_object_object_get_ex(jobj, "config", &jobj1); |
1315 | 5.25k | json_object_object_get_ex(jobj1, "keyslots_size", &jobj2); |
1316 | 5.25k | json_str_to_uint64(jobj2, &keyslots_size); |
1317 | | |
1318 | 5.25k | return keyslots_size; |
1319 | 5.25k | } |
1320 | | |
1321 | | uint64_t LUKS2_keyslots_size(struct luks2_hdr *hdr) |
1322 | 0 | { |
1323 | 0 | return LUKS2_keyslots_size_jobj(hdr->jobj); |
1324 | 0 | } |
1325 | | |
1326 | | uint64_t LUKS2_hdr_and_areas_size_jobj(json_object *jobj) |
1327 | 5.25k | { |
1328 | 5.25k | return 2 * LUKS2_metadata_size_jobj(jobj) + LUKS2_keyslots_size_jobj(jobj); |
1329 | 5.25k | } |
1330 | | |
1331 | | uint64_t LUKS2_hdr_and_areas_size(struct luks2_hdr *hdr) |
1332 | 0 | { |
1333 | 0 | return LUKS2_hdr_and_areas_size_jobj(hdr->jobj); |
1334 | 0 | } |
1335 | | |
1336 | | int LUKS2_hdr_backup(struct crypt_device *cd, struct luks2_hdr *hdr, |
1337 | | const char *backup_file) |
1338 | 0 | { |
1339 | 0 | struct device *device = crypt_metadata_device(cd); |
1340 | 0 | int fd, devfd, r = 0; |
1341 | 0 | ssize_t hdr_size; |
1342 | 0 | ssize_t ret, buffer_size; |
1343 | 0 | char *buffer = NULL; |
1344 | |
|
1345 | 0 | hdr_size = LUKS2_hdr_and_areas_size(hdr); |
1346 | 0 | buffer_size = size_round_up(hdr_size, crypt_getpagesize()); |
1347 | |
|
1348 | 0 | buffer = malloc(buffer_size); |
1349 | 0 | if (!buffer) |
1350 | 0 | return -ENOMEM; |
1351 | | |
1352 | 0 | log_dbg(cd, "Storing backup of header (%zu bytes).", hdr_size); |
1353 | 0 | log_dbg(cd, "Output backup file size: %zu bytes.", buffer_size); |
1354 | |
|
1355 | 0 | r = device_read_lock(cd, device); |
1356 | 0 | if (r) { |
1357 | 0 | log_err(cd, _("Failed to acquire read lock on device %s."), |
1358 | 0 | device_path(crypt_metadata_device(cd))); |
1359 | 0 | goto out; |
1360 | 0 | } |
1361 | | |
1362 | 0 | devfd = device_open_locked(cd, device, O_RDONLY); |
1363 | 0 | if (devfd < 0) { |
1364 | 0 | device_read_unlock(cd, device); |
1365 | 0 | log_err(cd, _("Device %s is not a valid LUKS device."), device_path(device)); |
1366 | 0 | r = (devfd == -1) ? -EINVAL : devfd; |
1367 | 0 | goto out; |
1368 | 0 | } |
1369 | | |
1370 | 0 | if (read_lseek_blockwise(devfd, device_block_size(cd, device), |
1371 | 0 | device_alignment(device), buffer, hdr_size, 0) < hdr_size) { |
1372 | 0 | device_read_unlock(cd, device); |
1373 | 0 | r = -EIO; |
1374 | 0 | goto out; |
1375 | 0 | } |
1376 | | |
1377 | 0 | device_read_unlock(cd, device); |
1378 | |
|
1379 | 0 | fd = open(backup_file, O_CREAT|O_EXCL|O_WRONLY, S_IRUSR); |
1380 | 0 | if (fd == -1) { |
1381 | 0 | if (errno == EEXIST) |
1382 | 0 | log_err(cd, _("Requested header backup file %s already exists."), backup_file); |
1383 | 0 | else |
1384 | 0 | log_err(cd, _("Cannot create header backup file %s."), backup_file); |
1385 | 0 | r = -EINVAL; |
1386 | 0 | goto out; |
1387 | 0 | } |
1388 | 0 | ret = write_buffer(fd, buffer, buffer_size); |
1389 | 0 | close(fd); |
1390 | 0 | if (ret < buffer_size) { |
1391 | 0 | log_err(cd, _("Cannot write header backup file %s."), backup_file); |
1392 | 0 | r = -EIO; |
1393 | 0 | } else |
1394 | 0 | r = 0; |
1395 | 0 | out: |
1396 | 0 | crypt_safe_memzero(buffer, buffer_size); |
1397 | 0 | free(buffer); |
1398 | 0 | return r; |
1399 | 0 | } |
1400 | | |
1401 | | int LUKS2_hdr_restore(struct crypt_device *cd, struct luks2_hdr *hdr, |
1402 | | const char *backup_file) |
1403 | 0 | { |
1404 | 0 | struct device *backup_device, *device = crypt_metadata_device(cd); |
1405 | 0 | int r, fd, devfd = -1, diff_uuid = 0; |
1406 | 0 | ssize_t ret, buffer_size = 0; |
1407 | 0 | char *buffer = NULL, msg[1024]; |
1408 | 0 | struct luks2_hdr hdr_file = {}, tmp_hdr = {}; |
1409 | 0 | uint32_t reqs = 0; |
1410 | |
|
1411 | 0 | r = device_alloc(cd, &backup_device, backup_file); |
1412 | 0 | if (r < 0) |
1413 | 0 | return r; |
1414 | | |
1415 | 0 | r = device_read_lock(cd, backup_device); |
1416 | 0 | if (r) { |
1417 | 0 | log_err(cd, _("Failed to acquire read lock on device %s."), |
1418 | 0 | device_path(backup_device)); |
1419 | 0 | device_free(cd, backup_device); |
1420 | 0 | return r; |
1421 | 0 | } |
1422 | | |
1423 | 0 | r = LUKS2_disk_hdr_read(cd, &hdr_file, backup_device, 0, 0); |
1424 | 0 | device_read_unlock(cd, backup_device); |
1425 | 0 | device_free(cd, backup_device); |
1426 | |
|
1427 | 0 | if (r < 0) { |
1428 | 0 | log_err(cd, _("Backup file does not contain valid LUKS header.")); |
1429 | 0 | goto out; |
1430 | 0 | } |
1431 | | |
1432 | | /* do not allow header restore from backup with unmet requirements */ |
1433 | 0 | if (LUKS2_unmet_requirements(cd, &hdr_file, |
1434 | 0 | CRYPT_REQUIREMENT_ONLINE_REENCRYPT | CRYPT_REQUIREMENT_INLINE_HW_TAGS, 1)) { |
1435 | 0 | log_err(cd, _("Forbidden LUKS2 requirements detected in backup %s."), |
1436 | 0 | backup_file); |
1437 | 0 | r = -ETXTBSY; |
1438 | 0 | goto out; |
1439 | 0 | } |
1440 | | |
1441 | 0 | buffer_size = LUKS2_hdr_and_areas_size(&hdr_file); |
1442 | 0 | buffer = malloc(buffer_size); |
1443 | 0 | if (!buffer) { |
1444 | 0 | r = -ENOMEM; |
1445 | 0 | goto out; |
1446 | 0 | } |
1447 | | |
1448 | 0 | fd = open(backup_file, O_RDONLY); |
1449 | 0 | if (fd == -1) { |
1450 | 0 | log_err(cd, _("Cannot open header backup file %s."), backup_file); |
1451 | 0 | r = -EINVAL; |
1452 | 0 | goto out; |
1453 | 0 | } |
1454 | | |
1455 | 0 | ret = read_buffer(fd, buffer, buffer_size); |
1456 | 0 | close(fd); |
1457 | 0 | if (ret < buffer_size) { |
1458 | 0 | log_err(cd, _("Cannot read header backup file %s."), backup_file); |
1459 | 0 | r = -EIO; |
1460 | 0 | goto out; |
1461 | 0 | } |
1462 | | |
1463 | 0 | r = LUKS2_hdr_read(cd, &tmp_hdr, 0); |
1464 | 0 | if (r == 0) { |
1465 | 0 | log_dbg(cd, "Device %s already contains LUKS2 header, checking UUID and requirements.", device_path(device)); |
1466 | 0 | LUKS2_config_get_requirements(cd, &tmp_hdr, &reqs); |
1467 | |
|
1468 | 0 | if (memcmp(tmp_hdr.uuid, hdr_file.uuid, LUKS2_UUID_L)) |
1469 | 0 | diff_uuid = 1; |
1470 | |
|
1471 | 0 | if (!reqs_reencrypt(reqs)) { |
1472 | 0 | log_dbg(cd, "Checking LUKS2 header size and offsets."); |
1473 | 0 | if (LUKS2_get_data_offset(&tmp_hdr) != LUKS2_get_data_offset(&hdr_file)) { |
1474 | 0 | log_err(cd, _("Data offset differ on device and backup, restore failed.")); |
1475 | 0 | r = -EINVAL; |
1476 | 0 | goto out; |
1477 | 0 | } |
1478 | | /* FIXME: what could go wrong? Erase if we're fine with consequences */ |
1479 | 0 | if (buffer_size != (ssize_t) LUKS2_hdr_and_areas_size(&tmp_hdr)) { |
1480 | 0 | log_err(cd, _("Binary header with keyslot areas size differ on device and backup, restore failed.")); |
1481 | 0 | r = -EINVAL; |
1482 | 0 | goto out; |
1483 | 0 | } |
1484 | 0 | } |
1485 | 0 | } |
1486 | | |
1487 | 0 | r = snprintf(msg, sizeof(msg), _("Device %s %s%s%s%s"), device_path(device), |
1488 | 0 | r ? _("does not contain LUKS2 header. Replacing header can destroy data on that device.") : |
1489 | 0 | _("already contains LUKS2 header. Replacing header will destroy existing keyslots."), |
1490 | 0 | diff_uuid ? _("\nWARNING: real device header has different UUID than backup!") : "", |
1491 | 0 | reqs_unknown(reqs) ? _("\nWARNING: unknown LUKS2 requirements detected in real device header!" |
1492 | 0 | "\nReplacing header with backup may corrupt the data on that device!") : "", |
1493 | 0 | reqs_reencrypt(reqs) ? _("\nWARNING: Unfinished offline reencryption detected on the device!" |
1494 | 0 | "\nReplacing header with backup may corrupt data.") : ""); |
1495 | 0 | if (r < 0 || (size_t) r >= sizeof(msg)) { |
1496 | 0 | r = -ENOMEM; |
1497 | 0 | goto out; |
1498 | 0 | } |
1499 | | |
1500 | 0 | if (!crypt_confirm(cd, msg)) { |
1501 | 0 | r = -EINVAL; |
1502 | 0 | goto out; |
1503 | 0 | } |
1504 | | |
1505 | 0 | log_dbg(cd, "Storing backup of header (%zu bytes) to device %s.", buffer_size, device_path(device)); |
1506 | | |
1507 | | /* Do not use LUKS2_device_write lock for checking sequence id on restore */ |
1508 | 0 | r = device_write_lock(cd, device); |
1509 | 0 | if (r < 0) { |
1510 | 0 | log_err(cd, _("Failed to acquire write lock on device %s."), |
1511 | 0 | device_path(device)); |
1512 | 0 | goto out; |
1513 | 0 | } |
1514 | | |
1515 | 0 | devfd = device_open_locked(cd, device, O_RDWR); |
1516 | 0 | if (devfd < 0) { |
1517 | 0 | if (errno == EACCES) |
1518 | 0 | log_err(cd, _("Cannot write to device %s, permission denied."), |
1519 | 0 | device_path(device)); |
1520 | 0 | else |
1521 | 0 | log_err(cd, _("Cannot open device %s."), device_path(device)); |
1522 | 0 | device_write_unlock(cd, device); |
1523 | 0 | r = -EINVAL; |
1524 | 0 | goto out; |
1525 | 0 | } |
1526 | | |
1527 | 0 | if (write_lseek_blockwise(devfd, device_block_size(cd, device), |
1528 | 0 | device_alignment(device), buffer, buffer_size, 0) < buffer_size) |
1529 | 0 | r = -EIO; |
1530 | 0 | else |
1531 | 0 | r = 0; |
1532 | |
|
1533 | 0 | device_write_unlock(cd, device); |
1534 | 0 | out: |
1535 | 0 | LUKS2_hdr_free(cd, hdr); |
1536 | 0 | LUKS2_hdr_free(cd, &hdr_file); |
1537 | 0 | LUKS2_hdr_free(cd, &tmp_hdr); |
1538 | 0 | crypt_safe_memzero(&hdr_file, sizeof(hdr_file)); |
1539 | 0 | crypt_safe_memzero(&tmp_hdr, sizeof(tmp_hdr)); |
1540 | 0 | crypt_safe_memzero(buffer, buffer_size); |
1541 | 0 | free(buffer); |
1542 | 0 | device_sync(cd, device); |
1543 | 0 | return r; |
1544 | 0 | } |
1545 | | |
1546 | | /* |
1547 | | * Persistent config flags |
1548 | | */ |
1549 | | static const struct { |
1550 | | uint64_t flag; |
1551 | | const char *description; |
1552 | | } persistent_flags[] = { |
1553 | | { CRYPT_ACTIVATE_ALLOW_DISCARDS, "allow-discards" }, |
1554 | | { CRYPT_ACTIVATE_SAME_CPU_CRYPT, "same-cpu-crypt" }, |
1555 | | { CRYPT_ACTIVATE_SUBMIT_FROM_CRYPT_CPUS, "submit-from-crypt-cpus" }, |
1556 | | { CRYPT_ACTIVATE_NO_JOURNAL, "no-journal" }, |
1557 | | { CRYPT_ACTIVATE_NO_READ_WORKQUEUE, "no-read-workqueue" }, |
1558 | | { CRYPT_ACTIVATE_NO_WRITE_WORKQUEUE, "no-write-workqueue" }, |
1559 | | { CRYPT_ACTIVATE_HIGH_PRIORITY, "high_priority" }, |
1560 | | { 0, NULL } |
1561 | | }; |
1562 | | |
1563 | | int LUKS2_config_get_flags(struct crypt_device *cd, struct luks2_hdr *hdr, uint32_t *flags) |
1564 | 0 | { |
1565 | 0 | json_object *jobj1, *jobj_config, *jobj_flags; |
1566 | 0 | int i, j, found; |
1567 | |
|
1568 | 0 | if (!hdr || !flags) |
1569 | 0 | return -EINVAL; |
1570 | | |
1571 | 0 | *flags = 0; |
1572 | |
|
1573 | 0 | if (!json_object_object_get_ex(hdr->jobj, "config", &jobj_config)) |
1574 | 0 | return 0; |
1575 | | |
1576 | 0 | if (!json_object_object_get_ex(jobj_config, "flags", &jobj_flags)) |
1577 | 0 | return 0; |
1578 | | |
1579 | 0 | for (i = 0; i < (int) json_object_array_length(jobj_flags); i++) { |
1580 | 0 | jobj1 = json_object_array_get_idx(jobj_flags, i); |
1581 | 0 | found = 0; |
1582 | 0 | for (j = 0; persistent_flags[j].description && !found; j++) |
1583 | 0 | if (!strcmp(persistent_flags[j].description, |
1584 | 0 | json_object_get_string(jobj1))) { |
1585 | 0 | *flags |= persistent_flags[j].flag; |
1586 | 0 | log_dbg(cd, "Using persistent flag %s.", |
1587 | 0 | json_object_get_string(jobj1)); |
1588 | 0 | found = 1; |
1589 | 0 | } |
1590 | 0 | if (!found) |
1591 | 0 | log_verbose(cd, _("Ignored unknown flag %s."), |
1592 | 0 | json_object_get_string(jobj1)); |
1593 | 0 | } |
1594 | |
|
1595 | 0 | return 0; |
1596 | 0 | } |
1597 | | |
1598 | | int LUKS2_config_set_flags(struct crypt_device *cd, struct luks2_hdr *hdr, uint32_t flags) |
1599 | 0 | { |
1600 | 0 | json_object *jobj_config, *jobj_flags; |
1601 | 0 | int i; |
1602 | |
|
1603 | 0 | if (!json_object_object_get_ex(hdr->jobj, "config", &jobj_config)) |
1604 | 0 | return 0; |
1605 | | |
1606 | 0 | jobj_flags = json_object_new_array(); |
1607 | 0 | if (!jobj_flags) |
1608 | 0 | return -ENOMEM; |
1609 | | |
1610 | 0 | for (i = 0; persistent_flags[i].description; i++) { |
1611 | 0 | if (flags & persistent_flags[i].flag) { |
1612 | 0 | log_dbg(cd, "Setting persistent flag: %s.", persistent_flags[i].description); |
1613 | 0 | json_object_array_add(jobj_flags, |
1614 | 0 | json_object_new_string(persistent_flags[i].description)); |
1615 | 0 | } |
1616 | 0 | } |
1617 | | |
1618 | | /* Replace or add new flags array */ |
1619 | 0 | json_object_object_add(jobj_config, "flags", jobj_flags); |
1620 | |
|
1621 | 0 | return LUKS2_hdr_write(cd, hdr); |
1622 | 0 | } |
1623 | | |
1624 | | /* |
1625 | | * json format example (mandatory array must not be ignored, |
1626 | | * all other future fields may be added later) |
1627 | | * |
1628 | | * "requirements": { |
1629 | | * mandatory : [], |
1630 | | * optional0 : [], |
1631 | | * optional1 : "lala" |
1632 | | * } |
1633 | | */ |
1634 | | |
1635 | | /* LUKS2 library requirements */ |
1636 | | struct requirement_flag { |
1637 | | uint32_t flag; |
1638 | | uint8_t version; |
1639 | | const char *description; |
1640 | | }; |
1641 | | |
1642 | | static const struct requirement_flag unknown_requirement_flag = { CRYPT_REQUIREMENT_UNKNOWN, 0, NULL }; |
1643 | | |
1644 | | static const struct requirement_flag requirements_flags[] = { |
1645 | | { CRYPT_REQUIREMENT_OFFLINE_REENCRYPT,1, "offline-reencrypt" }, |
1646 | | { CRYPT_REQUIREMENT_ONLINE_REENCRYPT, 2, "online-reencrypt-v2" }, |
1647 | | { CRYPT_REQUIREMENT_ONLINE_REENCRYPT, 3, "online-reencrypt-v3" }, |
1648 | | { CRYPT_REQUIREMENT_ONLINE_REENCRYPT, 1, "online-reencrypt" }, |
1649 | | { CRYPT_REQUIREMENT_INLINE_HW_TAGS, 1, "inline-hw-tags" }, |
1650 | | { CRYPT_REQUIREMENT_OPAL, 1, "opal" }, |
1651 | | { 0, 0, NULL } |
1652 | | }; |
1653 | | |
1654 | | static const struct requirement_flag *get_requirement_by_name(const char *requirement) |
1655 | 256 | { |
1656 | 256 | int i; |
1657 | | |
1658 | 1.23k | for (i = 0; requirements_flags[i].description; i++) |
1659 | 1.07k | if (!strcmp(requirement, requirements_flags[i].description)) |
1660 | 96 | return requirements_flags + i; |
1661 | | |
1662 | 160 | return &unknown_requirement_flag; |
1663 | 256 | } |
1664 | | |
1665 | | static json_object *mandatory_requirements_jobj(struct luks2_hdr *hdr) |
1666 | 10.6k | { |
1667 | 10.6k | json_object *jobj_config, *jobj_requirements, *jobj_mandatory; |
1668 | | |
1669 | 10.6k | assert(hdr); |
1670 | | |
1671 | 10.6k | if (!json_object_object_get_ex(hdr->jobj, "config", &jobj_config)) |
1672 | 0 | return NULL; |
1673 | | |
1674 | 10.6k | if (!json_object_object_get_ex(jobj_config, "requirements", &jobj_requirements)) |
1675 | 10.4k | return NULL; |
1676 | | |
1677 | 148 | if (!json_object_object_get_ex(jobj_requirements, "mandatory", &jobj_mandatory)) |
1678 | 38 | return NULL; |
1679 | | |
1680 | 110 | return jobj_mandatory; |
1681 | 148 | } |
1682 | | |
1683 | | bool LUKS2_reencrypt_requirement_candidate(struct luks2_hdr *hdr) |
1684 | 0 | { |
1685 | 0 | json_object *jobj_mandatory; |
1686 | 0 | int i, len; |
1687 | |
|
1688 | 0 | assert(hdr); |
1689 | |
|
1690 | 0 | jobj_mandatory = mandatory_requirements_jobj(hdr); |
1691 | 0 | if (!jobj_mandatory) |
1692 | 0 | return false; |
1693 | | |
1694 | 0 | len = (int) json_object_array_length(jobj_mandatory); |
1695 | 0 | if (len <= 0) |
1696 | 0 | return false; |
1697 | | |
1698 | 0 | for (i = 0; i < len; i++) { |
1699 | 0 | if (reencrypt_candidate_flag(json_object_get_string(json_object_array_get_idx(jobj_mandatory, i)))) |
1700 | 0 | return true; |
1701 | 0 | } |
1702 | | |
1703 | 0 | return false; |
1704 | 0 | } |
1705 | | |
1706 | | int LUKS2_config_get_reencrypt_version(struct luks2_hdr *hdr, uint8_t *version) |
1707 | 0 | { |
1708 | 0 | json_object *jobj_mandatory, *jobj; |
1709 | 0 | int i, len; |
1710 | 0 | const struct requirement_flag *req; |
1711 | |
|
1712 | 0 | assert(hdr); |
1713 | 0 | assert(version); |
1714 | |
|
1715 | 0 | jobj_mandatory = mandatory_requirements_jobj(hdr); |
1716 | 0 | if (!jobj_mandatory) |
1717 | 0 | return -ENOENT; |
1718 | | |
1719 | 0 | len = (int) json_object_array_length(jobj_mandatory); |
1720 | 0 | if (len <= 0) |
1721 | 0 | return -ENOENT; |
1722 | | |
1723 | 0 | for (i = 0; i < len; i++) { |
1724 | 0 | jobj = json_object_array_get_idx(jobj_mandatory, i); |
1725 | | |
1726 | | /* search for requirements prefixed with "online-reencrypt" */ |
1727 | 0 | if (strncmp(json_object_get_string(jobj), "online-reencrypt", 16)) |
1728 | 0 | continue; |
1729 | | |
1730 | | /* check current library is aware of the requirement */ |
1731 | 0 | req = get_requirement_by_name(json_object_get_string(jobj)); |
1732 | 0 | if (req->flag == CRYPT_REQUIREMENT_UNKNOWN) |
1733 | 0 | continue; |
1734 | | |
1735 | 0 | *version = req->version; |
1736 | |
|
1737 | 0 | return 0; |
1738 | 0 | } |
1739 | | |
1740 | 0 | return -ENOENT; |
1741 | 0 | } |
1742 | | |
1743 | | static const struct requirement_flag *stored_requirement_name_by_id(struct luks2_hdr *hdr, uint32_t req_id) |
1744 | 0 | { |
1745 | 0 | json_object *jobj_mandatory, *jobj; |
1746 | 0 | int i, len; |
1747 | 0 | const struct requirement_flag *req; |
1748 | |
|
1749 | 0 | assert(hdr); |
1750 | |
|
1751 | 0 | jobj_mandatory = mandatory_requirements_jobj(hdr); |
1752 | 0 | if (!jobj_mandatory) |
1753 | 0 | return NULL; |
1754 | | |
1755 | 0 | len = (int) json_object_array_length(jobj_mandatory); |
1756 | 0 | if (len <= 0) |
1757 | 0 | return NULL; |
1758 | | |
1759 | 0 | for (i = 0; i < len; i++) { |
1760 | 0 | jobj = json_object_array_get_idx(jobj_mandatory, i); |
1761 | 0 | req = get_requirement_by_name(json_object_get_string(jobj)); |
1762 | 0 | if (req->flag == req_id) |
1763 | 0 | return req; |
1764 | 0 | } |
1765 | | |
1766 | 0 | return NULL; |
1767 | 0 | } |
1768 | | |
1769 | | /* |
1770 | | * returns count of requirements (past cryptsetup 2.0 release) |
1771 | | */ |
1772 | | void LUKS2_config_get_requirements(struct crypt_device *cd, struct luks2_hdr *hdr, uint32_t *reqs) |
1773 | 10.6k | { |
1774 | 10.6k | json_object *jobj_mandatory, *jobj; |
1775 | 10.6k | int i, len; |
1776 | 10.6k | const struct requirement_flag *req; |
1777 | | |
1778 | 10.6k | assert(hdr); |
1779 | 10.6k | assert(reqs); |
1780 | | |
1781 | 10.6k | *reqs = 0; |
1782 | | |
1783 | 10.6k | jobj_mandatory = mandatory_requirements_jobj(hdr); |
1784 | 10.6k | if (!jobj_mandatory) |
1785 | 10.5k | return; |
1786 | | |
1787 | 110 | len = (int) json_object_array_length(jobj_mandatory); |
1788 | 110 | if (len <= 0) |
1789 | 0 | return; |
1790 | | |
1791 | 110 | log_dbg(cd, "LUKS2 requirements detected:"); |
1792 | | |
1793 | 366 | for (i = 0; i < len; i++) { |
1794 | 256 | jobj = json_object_array_get_idx(jobj_mandatory, i); |
1795 | 256 | req = get_requirement_by_name(json_object_get_string(jobj)); |
1796 | 256 | log_dbg(cd, "%s - %sknown", json_object_get_string(jobj), |
1797 | 256 | reqs_unknown(req->flag) ? "un" : ""); |
1798 | 256 | *reqs |= req->flag; |
1799 | 256 | } |
1800 | 110 | } |
1801 | | |
1802 | | int LUKS2_config_set_requirements(struct crypt_device *cd, struct luks2_hdr *hdr, uint32_t reqs, bool commit) |
1803 | 0 | { |
1804 | 0 | json_object *jobj_config, *jobj_requirements, *jobj_mandatory, *jobj; |
1805 | 0 | int i, r = -EINVAL; |
1806 | 0 | const struct requirement_flag *req; |
1807 | 0 | uint64_t req_id; |
1808 | |
|
1809 | 0 | if (!hdr) |
1810 | 0 | return -EINVAL; |
1811 | | |
1812 | 0 | jobj_mandatory = json_object_new_array(); |
1813 | 0 | if (!jobj_mandatory) |
1814 | 0 | return -ENOMEM; |
1815 | | |
1816 | 0 | for (i = 0; requirements_flags[i].description; i++) { |
1817 | 0 | req_id = reqs & requirements_flags[i].flag; |
1818 | 0 | if (req_id) { |
1819 | | /* retain already stored version of requirement flag */ |
1820 | 0 | req = stored_requirement_name_by_id(hdr, req_id); |
1821 | 0 | if (req) |
1822 | 0 | jobj = json_object_new_string(req->description); |
1823 | 0 | else |
1824 | 0 | jobj = json_object_new_string(requirements_flags[i].description); |
1825 | 0 | if (!jobj) { |
1826 | 0 | r = -ENOMEM; |
1827 | 0 | goto err; |
1828 | 0 | } |
1829 | 0 | json_object_array_add(jobj_mandatory, jobj); |
1830 | | /* erase processed flag from input set */ |
1831 | 0 | reqs &= ~(requirements_flags[i].flag); |
1832 | 0 | } |
1833 | 0 | } |
1834 | | |
1835 | | /* any remaining bit in requirements is unknown therefore illegal */ |
1836 | 0 | if (reqs) { |
1837 | 0 | log_dbg(cd, "Illegal requirement flag(s) requested"); |
1838 | 0 | goto err; |
1839 | 0 | } |
1840 | | |
1841 | 0 | if (!json_object_object_get_ex(hdr->jobj, "config", &jobj_config)) |
1842 | 0 | goto err; |
1843 | | |
1844 | 0 | if (!json_object_object_get_ex(jobj_config, "requirements", &jobj_requirements)) { |
1845 | 0 | jobj_requirements = json_object_new_object(); |
1846 | 0 | if (!jobj_requirements) { |
1847 | 0 | r = -ENOMEM; |
1848 | 0 | goto err; |
1849 | 0 | } |
1850 | 0 | json_object_object_add(jobj_config, "requirements", jobj_requirements); |
1851 | 0 | } |
1852 | | |
1853 | 0 | if (json_object_array_length(jobj_mandatory) > 0) { |
1854 | | /* replace mandatory field with new values */ |
1855 | 0 | json_object_object_add(jobj_requirements, "mandatory", jobj_mandatory); |
1856 | 0 | } else { |
1857 | | /* new mandatory field was empty, delete old one */ |
1858 | 0 | json_object_object_del(jobj_requirements, "mandatory"); |
1859 | 0 | json_object_put(jobj_mandatory); |
1860 | 0 | } |
1861 | | |
1862 | | /* remove empty requirements object */ |
1863 | 0 | if (!json_object_object_length(jobj_requirements)) |
1864 | 0 | json_object_object_del(jobj_config, "requirements"); |
1865 | |
|
1866 | 0 | return commit ? LUKS2_hdr_write(cd, hdr) : 0; |
1867 | 0 | err: |
1868 | 0 | json_object_put(jobj_mandatory); |
1869 | 0 | return r; |
1870 | 0 | } |
1871 | | |
1872 | | static json_object *LUKS2_get_mandatory_requirements_filtered_jobj(struct luks2_hdr *hdr, |
1873 | | uint32_t filter_req_ids) |
1874 | 0 | { |
1875 | 0 | int i, len; |
1876 | 0 | const struct requirement_flag *req; |
1877 | 0 | json_object *jobj_mandatory, *jobj_mandatory_filtered, *jobj; |
1878 | |
|
1879 | 0 | jobj_mandatory_filtered = json_object_new_array(); |
1880 | 0 | if (!jobj_mandatory_filtered) |
1881 | 0 | return NULL; |
1882 | | |
1883 | 0 | jobj_mandatory = mandatory_requirements_jobj(hdr); |
1884 | 0 | if (!jobj_mandatory) |
1885 | 0 | return jobj_mandatory_filtered; |
1886 | | |
1887 | 0 | len = (int) json_object_array_length(jobj_mandatory); |
1888 | |
|
1889 | 0 | for (i = 0; i < len; i++) { |
1890 | 0 | jobj = json_object_array_get_idx(jobj_mandatory, i); |
1891 | 0 | req = get_requirement_by_name(json_object_get_string(jobj)); |
1892 | 0 | if (req->flag == CRYPT_REQUIREMENT_UNKNOWN || req->flag & filter_req_ids) |
1893 | 0 | continue; |
1894 | 0 | json_object_array_add(jobj_mandatory_filtered, |
1895 | 0 | json_object_new_string(req->description)); |
1896 | 0 | } |
1897 | |
|
1898 | 0 | return jobj_mandatory_filtered; |
1899 | 0 | } |
1900 | | |
1901 | | /* |
1902 | | * The function looks for specific version of requirement id. |
1903 | | * If it can't be fulfilled function fails. |
1904 | | */ |
1905 | | int LUKS2_config_set_requirement_version(struct crypt_device *cd, |
1906 | | struct luks2_hdr *hdr, |
1907 | | uint32_t req_id, |
1908 | | uint8_t req_version, |
1909 | | bool commit) |
1910 | 0 | { |
1911 | 0 | json_object *jobj_config, *jobj_requirements, *jobj_mandatory; |
1912 | 0 | const struct requirement_flag *req; |
1913 | 0 | int r = -EINVAL; |
1914 | |
|
1915 | 0 | if (!hdr || req_id == CRYPT_REQUIREMENT_UNKNOWN) |
1916 | 0 | return -EINVAL; |
1917 | | |
1918 | 0 | req = requirements_flags; |
1919 | |
|
1920 | 0 | while (req->description) { |
1921 | | /* we have a match */ |
1922 | 0 | if (req->flag == req_id && req->version == req_version) |
1923 | 0 | break; |
1924 | 0 | req++; |
1925 | 0 | } |
1926 | |
|
1927 | 0 | if (!req->description) |
1928 | 0 | return -EINVAL; |
1929 | | |
1930 | | /* |
1931 | | * Creates copy of mandatory requirements set without specific requirement |
1932 | | * (no matter the version) we want to set. |
1933 | | */ |
1934 | 0 | jobj_mandatory = LUKS2_get_mandatory_requirements_filtered_jobj(hdr, req_id); |
1935 | 0 | if (!jobj_mandatory) |
1936 | 0 | return -ENOMEM; |
1937 | | |
1938 | 0 | json_object_array_add(jobj_mandatory, json_object_new_string(req->description)); |
1939 | |
|
1940 | 0 | if (!json_object_object_get_ex(hdr->jobj, "config", &jobj_config)) |
1941 | 0 | goto err; |
1942 | | |
1943 | 0 | if (!json_object_object_get_ex(jobj_config, "requirements", &jobj_requirements)) { |
1944 | 0 | jobj_requirements = json_object_new_object(); |
1945 | 0 | if (!jobj_requirements) { |
1946 | 0 | r = -ENOMEM; |
1947 | 0 | goto err; |
1948 | 0 | } |
1949 | 0 | json_object_object_add(jobj_config, "requirements", jobj_requirements); |
1950 | 0 | } |
1951 | | |
1952 | 0 | json_object_object_add(jobj_requirements, "mandatory", jobj_mandatory); |
1953 | |
|
1954 | 0 | return commit ? LUKS2_hdr_write(cd, hdr) : 0; |
1955 | 0 | err: |
1956 | 0 | json_object_put(jobj_mandatory); |
1957 | 0 | return r; |
1958 | 0 | } |
1959 | | |
1960 | | /* |
1961 | | * Header dump |
1962 | | */ |
1963 | | static void hdr_dump_config(struct crypt_device *cd, json_object *hdr_jobj) |
1964 | 0 | { |
1965 | |
|
1966 | 0 | json_object *jobj1, *jobj_config, *jobj_flags, *jobj_requirements, *jobj_mandatory; |
1967 | 0 | int i = 0, flags = 0, reqs = 0; |
1968 | |
|
1969 | 0 | log_std(cd, "Flags: \t"); |
1970 | |
|
1971 | 0 | if (json_object_object_get_ex(hdr_jobj, "config", &jobj_config)) { |
1972 | 0 | if (json_object_object_get_ex(jobj_config, "flags", &jobj_flags)) |
1973 | 0 | flags = (int) json_object_array_length(jobj_flags); |
1974 | 0 | if (json_object_object_get_ex(jobj_config, "requirements", &jobj_requirements) && |
1975 | 0 | json_object_object_get_ex(jobj_requirements, "mandatory", &jobj_mandatory)) |
1976 | 0 | reqs = (int) json_object_array_length(jobj_mandatory); |
1977 | 0 | } |
1978 | |
|
1979 | 0 | for (i = 0; i < flags; i++) { |
1980 | 0 | jobj1 = json_object_array_get_idx(jobj_flags, i); |
1981 | 0 | log_std(cd, "%s ", json_object_get_string(jobj1)); |
1982 | 0 | } |
1983 | |
|
1984 | 0 | log_std(cd, "%s\n%s", flags > 0 ? "" : "(no flags)", reqs > 0 ? "" : "\n"); |
1985 | |
|
1986 | 0 | if (reqs > 0) { |
1987 | 0 | log_std(cd, "Requirements:\t"); |
1988 | 0 | for (i = 0; i < reqs; i++) { |
1989 | 0 | jobj1 = json_object_array_get_idx(jobj_mandatory, i); |
1990 | 0 | log_std(cd, "%s ", json_object_get_string(jobj1)); |
1991 | 0 | } |
1992 | 0 | log_std(cd, "\n\n"); |
1993 | 0 | } |
1994 | 0 | } |
1995 | | |
1996 | | static const char *get_priority_desc(json_object *jobj) |
1997 | 0 | { |
1998 | 0 | crypt_keyslot_priority priority; |
1999 | 0 | json_object *jobj_priority; |
2000 | 0 | const char *text; |
2001 | |
|
2002 | 0 | if (json_object_object_get_ex(jobj, "priority", &jobj_priority)) |
2003 | 0 | priority = (crypt_keyslot_priority)(int)json_object_get_int(jobj_priority); |
2004 | 0 | else |
2005 | 0 | priority = CRYPT_SLOT_PRIORITY_NORMAL; |
2006 | |
|
2007 | 0 | switch (priority) { |
2008 | 0 | case CRYPT_SLOT_PRIORITY_IGNORE: text = "ignored"; break; |
2009 | 0 | case CRYPT_SLOT_PRIORITY_PREFER: text = "preferred"; break; |
2010 | 0 | case CRYPT_SLOT_PRIORITY_NORMAL: text = "normal"; break; |
2011 | 0 | default: text = "invalid"; |
2012 | 0 | } |
2013 | | |
2014 | 0 | return text; |
2015 | 0 | } |
2016 | | |
2017 | | static void hdr_dump_keyslots(struct crypt_device *cd, json_object *hdr_jobj) |
2018 | 0 | { |
2019 | 0 | char slot[16]; |
2020 | 0 | json_object *keyslots_jobj, *digests_jobj, *jobj2, *jobj3, *val; |
2021 | 0 | const char *tmps; |
2022 | 0 | int i, j, r; |
2023 | |
|
2024 | 0 | log_std(cd, "Keyslots:\n"); |
2025 | 0 | json_object_object_get_ex(hdr_jobj, "keyslots", &keyslots_jobj); |
2026 | |
|
2027 | 0 | for (j = 0; j < LUKS2_KEYSLOTS_MAX; j++) { |
2028 | 0 | if (snprintf(slot, sizeof(slot), "%i", j) < 0) |
2029 | 0 | slot[0] = '\0'; |
2030 | 0 | json_object_object_get_ex(keyslots_jobj, slot, &val); |
2031 | 0 | if (!val) |
2032 | 0 | continue; |
2033 | | |
2034 | 0 | json_object_object_get_ex(val, "type", &jobj2); |
2035 | 0 | tmps = json_object_get_string(jobj2); |
2036 | |
|
2037 | 0 | r = LUKS2_keyslot_for_segment(crypt_get_hdr(cd, CRYPT_LUKS2), j, CRYPT_ONE_SEGMENT); |
2038 | 0 | log_std(cd, " %s: %s%s\n", slot, tmps, r == -ENOENT ? " (unbound)" : ""); |
2039 | |
|
2040 | 0 | if (json_object_object_get_ex(val, "key_size", &jobj2)) |
2041 | 0 | log_std(cd, "\tKey: %u bits\n", crypt_jobj_get_uint32(jobj2) * 8); |
2042 | |
|
2043 | 0 | log_std(cd, "\tPriority: %s\n", get_priority_desc(val)); |
2044 | |
|
2045 | 0 | LUKS2_keyslot_dump(cd, j); |
2046 | |
|
2047 | 0 | json_object_object_get_ex(hdr_jobj, "digests", &digests_jobj); |
2048 | 0 | json_object_object_foreach(digests_jobj, key2, val2) { |
2049 | 0 | json_object_object_get_ex(val2, "keyslots", &jobj2); |
2050 | 0 | for (i = 0; i < (int) json_object_array_length(jobj2); i++) { |
2051 | 0 | jobj3 = json_object_array_get_idx(jobj2, i); |
2052 | 0 | if (!strcmp(slot, json_object_get_string(jobj3))) { |
2053 | 0 | log_std(cd, "\tDigest ID: %s\n", key2); |
2054 | 0 | } |
2055 | 0 | } |
2056 | 0 | } |
2057 | 0 | } |
2058 | 0 | } |
2059 | | |
2060 | | static void hdr_dump_tokens(struct crypt_device *cd, json_object *hdr_jobj) |
2061 | 0 | { |
2062 | 0 | char token[16]; |
2063 | 0 | json_object *tokens_jobj, *jobj2, *jobj3, *val; |
2064 | 0 | const char *tmps; |
2065 | 0 | int i, j; |
2066 | |
|
2067 | 0 | log_std(cd, "Tokens:\n"); |
2068 | 0 | json_object_object_get_ex(hdr_jobj, "tokens", &tokens_jobj); |
2069 | |
|
2070 | 0 | for (j = 0; j < LUKS2_TOKENS_MAX; j++) { |
2071 | 0 | if (snprintf(token, sizeof(token), "%i", j) < 0) |
2072 | 0 | token[0] = '\0'; |
2073 | 0 | json_object_object_get_ex(tokens_jobj, token, &val); |
2074 | 0 | if (!val) |
2075 | 0 | continue; |
2076 | | |
2077 | 0 | json_object_object_get_ex(val, "type", &jobj2); |
2078 | 0 | tmps = json_object_get_string(jobj2); |
2079 | 0 | log_std(cd, " %s: %s\n", token, tmps); |
2080 | |
|
2081 | 0 | LUKS2_token_dump(cd, j); |
2082 | |
|
2083 | 0 | json_object_object_get_ex(val, "keyslots", &jobj2); |
2084 | 0 | for (i = 0; i < (int) json_object_array_length(jobj2); i++) { |
2085 | 0 | jobj3 = json_object_array_get_idx(jobj2, i); |
2086 | 0 | log_std(cd, "\tKeyslot: %s\n", json_object_get_string(jobj3)); |
2087 | 0 | } |
2088 | 0 | } |
2089 | 0 | } |
2090 | | |
2091 | | static void hdr_dump_segments(struct crypt_device *cd, json_object *hdr_jobj) |
2092 | 0 | { |
2093 | 0 | char segment[16]; |
2094 | 0 | json_object *jobj_segments, *jobj_segment, *jobj1, *jobj2; |
2095 | 0 | int i, j, flags; |
2096 | 0 | uint64_t value; |
2097 | |
|
2098 | 0 | log_std(cd, "Data segments:\n"); |
2099 | 0 | json_object_object_get_ex(hdr_jobj, "segments", &jobj_segments); |
2100 | |
|
2101 | 0 | for (i = 0; i < LUKS2_SEGMENT_MAX; i++) { |
2102 | 0 | if (snprintf(segment, sizeof(segment), "%i", i) < 0) |
2103 | 0 | segment[0] = '\0'; |
2104 | 0 | if (!json_object_object_get_ex(jobj_segments, segment, &jobj_segment)) |
2105 | 0 | continue; |
2106 | | |
2107 | 0 | json_object_object_get_ex(jobj_segment, "type", &jobj1); |
2108 | 0 | log_std(cd, " %s: %s\n", segment, json_object_get_string(jobj1)); |
2109 | |
|
2110 | 0 | json_object_object_get_ex(jobj_segment, "offset", &jobj1); |
2111 | 0 | json_str_to_uint64(jobj1, &value); |
2112 | 0 | log_std(cd, "\toffset: %" PRIu64 " [bytes]\n", value); |
2113 | |
|
2114 | 0 | json_object_object_get_ex(jobj_segment, "size", &jobj1); |
2115 | 0 | if (!(strcmp(json_object_get_string(jobj1), "dynamic"))) |
2116 | 0 | log_std(cd, "\tlength: (whole device)\n"); |
2117 | 0 | else { |
2118 | 0 | json_str_to_uint64(jobj1, &value); |
2119 | 0 | log_std(cd, "\tlength: %" PRIu64 " [bytes]\n", value); |
2120 | 0 | } |
2121 | |
|
2122 | 0 | if (json_object_object_get_ex(jobj_segment, "encryption", &jobj1)) |
2123 | 0 | log_std(cd, "\tcipher: %s\n", json_object_get_string(jobj1)); |
2124 | 0 | else |
2125 | 0 | log_std(cd, "\tcipher: (no SW encryption)\n"); |
2126 | |
|
2127 | 0 | if (json_object_object_get_ex(jobj_segment, "sector_size", &jobj1)) |
2128 | 0 | log_std(cd, "\tsector: %" PRIu32 " [bytes]\n", crypt_jobj_get_uint32(jobj1)); |
2129 | |
|
2130 | 0 | if (json_object_object_get_ex(jobj_segment, "integrity", &jobj1) && |
2131 | 0 | json_object_object_get_ex(jobj1, "type", &jobj2)) |
2132 | 0 | log_std(cd, "\tintegrity: %s\n", json_object_get_string(jobj2)); |
2133 | |
|
2134 | 0 | if (json_object_object_get_ex(jobj_segment, "integrity", &jobj1) && |
2135 | 0 | json_object_object_get_ex(jobj1, "key_size", &jobj2)) |
2136 | 0 | log_std(cd, "\tintegrity key size: %" PRIu32 " [bits]\n", crypt_jobj_get_uint32(jobj2) * 8); |
2137 | |
|
2138 | 0 | if (json_object_object_get_ex(jobj_segment, "flags", &jobj1) && |
2139 | 0 | (flags = (int)json_object_array_length(jobj1)) > 0) { |
2140 | 0 | jobj2 = json_object_array_get_idx(jobj1, 0); |
2141 | 0 | log_std(cd, "\tflags : %s", json_object_get_string(jobj2)); |
2142 | 0 | for (j = 1; j < flags; j++) { |
2143 | 0 | jobj2 = json_object_array_get_idx(jobj1, j); |
2144 | 0 | log_std(cd, ", %s", json_object_get_string(jobj2)); |
2145 | 0 | } |
2146 | 0 | log_std(cd, "\n"); |
2147 | 0 | } |
2148 | |
|
2149 | 0 | json_object_object_get_ex(jobj_segment, "type", &jobj1); |
2150 | 0 | if (!strncmp(json_object_get_string(jobj1), "hw-opal", 7)) { |
2151 | 0 | log_std(cd, "\tHW OPAL encryption:\n"); |
2152 | 0 | json_object_object_get_ex(jobj_segment, "opal_segment_number", &jobj1); |
2153 | 0 | log_std(cd, "\t\tOPAL segment number: %" PRIu32 "\n", crypt_jobj_get_uint32(jobj1)); |
2154 | 0 | json_object_object_get_ex(jobj_segment, "opal_key_size", &jobj1); |
2155 | 0 | log_std(cd, "\t\tOPAL key: %" PRIu32 " bits\n", crypt_jobj_get_uint32(jobj1) * 8); |
2156 | 0 | json_object_object_get_ex(jobj_segment, "opal_segment_size", &jobj1); |
2157 | 0 | json_str_to_uint64(jobj1, &value); |
2158 | 0 | log_std(cd, "\t\tOPAL segment length: %" PRIu64 " [bytes]\n", value); |
2159 | 0 | } |
2160 | |
|
2161 | 0 | log_std(cd, "\n"); |
2162 | 0 | } |
2163 | 0 | } |
2164 | | |
2165 | | static void hdr_dump_digests(struct crypt_device *cd, json_object *hdr_jobj) |
2166 | 0 | { |
2167 | 0 | char key[16]; |
2168 | 0 | json_object *jobj1, *jobj2, *val; |
2169 | 0 | const char *tmps; |
2170 | 0 | int i; |
2171 | |
|
2172 | 0 | log_std(cd, "Digests:\n"); |
2173 | 0 | json_object_object_get_ex(hdr_jobj, "digests", &jobj1); |
2174 | |
|
2175 | 0 | for (i = 0; i < LUKS2_DIGEST_MAX; i++) { |
2176 | 0 | if (snprintf(key, sizeof(key), "%i", i) < 0) |
2177 | 0 | key[0] = '\0'; |
2178 | 0 | json_object_object_get_ex(jobj1, key, &val); |
2179 | 0 | if (!val) |
2180 | 0 | continue; |
2181 | | |
2182 | 0 | json_object_object_get_ex(val, "type", &jobj2); |
2183 | 0 | tmps = json_object_get_string(jobj2); |
2184 | 0 | log_std(cd, " %s: %s\n", key, tmps); |
2185 | |
|
2186 | 0 | LUKS2_digest_dump(cd, i); |
2187 | 0 | } |
2188 | 0 | } |
2189 | | |
2190 | | int LUKS2_hdr_dump(struct crypt_device *cd, struct luks2_hdr *hdr) |
2191 | 0 | { |
2192 | 0 | if (!hdr->jobj) |
2193 | 0 | return -EINVAL; |
2194 | | |
2195 | 0 | JSON_DBG(cd, hdr->jobj, NULL); |
2196 | |
|
2197 | 0 | log_std(cd, "LUKS header information\n"); |
2198 | 0 | log_std(cd, "Version: \t%u\n", hdr->version); |
2199 | 0 | log_std(cd, "Epoch: \t%" PRIu64 "\n", hdr->seqid); |
2200 | 0 | log_std(cd, "Metadata area: \t%" PRIu64 " [bytes]\n", LUKS2_metadata_size(hdr)); |
2201 | 0 | log_std(cd, "Keyslots area: \t%" PRIu64 " [bytes]\n", LUKS2_keyslots_size(hdr)); |
2202 | 0 | log_std(cd, "UUID: \t%s\n", *hdr->uuid ? hdr->uuid : "(no UUID)"); |
2203 | 0 | log_std(cd, "Label: \t%s\n", *hdr->label ? hdr->label : "(no label)"); |
2204 | 0 | log_std(cd, "Subsystem: \t%s\n", *hdr->subsystem ? hdr->subsystem : "(no subsystem)"); |
2205 | |
|
2206 | 0 | hdr_dump_config(cd, hdr->jobj); |
2207 | 0 | hdr_dump_segments(cd, hdr->jobj); |
2208 | 0 | hdr_dump_keyslots(cd, hdr->jobj); |
2209 | 0 | hdr_dump_tokens(cd, hdr->jobj); |
2210 | 0 | hdr_dump_digests(cd, hdr->jobj); |
2211 | |
|
2212 | 0 | return 0; |
2213 | 0 | } |
2214 | | |
2215 | | int LUKS2_hdr_dump_json(struct crypt_device *cd, struct luks2_hdr *hdr, const char **json) |
2216 | 0 | { |
2217 | 0 | const char *json_buf; |
2218 | |
|
2219 | 0 | json_buf = json_object_to_json_string_ext(hdr->jobj, |
2220 | 0 | JSON_C_TO_STRING_PRETTY | JSON_C_TO_STRING_NOSLASHESCAPE); |
2221 | |
|
2222 | 0 | if (!json_buf) |
2223 | 0 | return -EINVAL; |
2224 | | |
2225 | 0 | if (json) |
2226 | 0 | *json = json_buf; |
2227 | 0 | else |
2228 | 0 | crypt_log(cd, CRYPT_LOG_NORMAL, json_buf); |
2229 | |
|
2230 | 0 | return 0; |
2231 | 0 | } |
2232 | | |
2233 | | int LUKS2_get_data_size(struct luks2_hdr *hdr, uint64_t *size, bool *dynamic) |
2234 | 0 | { |
2235 | 0 | int i, len, sector_size; |
2236 | 0 | json_object *jobj_segments, *jobj_segment, *jobj_size; |
2237 | 0 | uint64_t tmp = 0; |
2238 | |
|
2239 | 0 | if (!size || !json_object_object_get_ex(hdr->jobj, "segments", &jobj_segments)) |
2240 | 0 | return -EINVAL; |
2241 | | |
2242 | 0 | len = json_object_object_length(jobj_segments); |
2243 | |
|
2244 | 0 | for (i = 0; i < len; i++) { |
2245 | 0 | if (!(jobj_segment = json_segments_get_segment(jobj_segments, i))) |
2246 | 0 | return -EINVAL; |
2247 | | |
2248 | 0 | if (json_segment_is_backup(jobj_segment)) |
2249 | 0 | break; |
2250 | | |
2251 | 0 | json_object_object_get_ex(jobj_segment, "size", &jobj_size); |
2252 | 0 | if (!strcmp(json_object_get_string(jobj_size), "dynamic")) { |
2253 | 0 | sector_size = json_segment_get_sector_size(jobj_segment); |
2254 | | /* last dynamic segment must have at least one sector in size */ |
2255 | 0 | if (tmp) |
2256 | 0 | *size = tmp + (sector_size > 0 ? sector_size : SECTOR_SIZE); |
2257 | 0 | else |
2258 | 0 | *size = 0; |
2259 | 0 | if (dynamic) |
2260 | 0 | *dynamic = true; |
2261 | 0 | return 0; |
2262 | 0 | } |
2263 | | |
2264 | 0 | tmp += crypt_jobj_get_uint64(jobj_size); |
2265 | 0 | } |
2266 | | |
2267 | | /* impossible, real device size must not be zero */ |
2268 | 0 | if (!tmp) |
2269 | 0 | return -EINVAL; |
2270 | | |
2271 | 0 | *size = tmp; |
2272 | 0 | if (dynamic) |
2273 | 0 | *dynamic = false; |
2274 | 0 | return 0; |
2275 | 0 | } |
2276 | | |
2277 | | uint64_t LUKS2_get_data_offset(struct luks2_hdr *hdr) |
2278 | 0 | { |
2279 | 0 | crypt_reencrypt_info ri; |
2280 | 0 | json_object *jobj; |
2281 | |
|
2282 | 0 | ri = LUKS2_reencrypt_status(hdr); |
2283 | 0 | if (ri == CRYPT_REENCRYPT_CLEAN || ri == CRYPT_REENCRYPT_CRASH) { |
2284 | 0 | jobj = LUKS2_get_segment_by_flag(hdr, "backup-final"); |
2285 | 0 | if (jobj) |
2286 | 0 | return json_segment_get_offset(jobj, 1); |
2287 | 0 | } |
2288 | | |
2289 | 0 | return json_segments_get_minimal_offset(LUKS2_get_segments_jobj(hdr), 1); |
2290 | 0 | } |
2291 | | |
2292 | | const char *LUKS2_get_cipher(struct luks2_hdr *hdr, int segment) |
2293 | 0 | { |
2294 | 0 | json_object *jobj_segment; |
2295 | |
|
2296 | 0 | if (!hdr) |
2297 | 0 | return NULL; |
2298 | | |
2299 | 0 | if (segment == CRYPT_DEFAULT_SEGMENT) |
2300 | 0 | segment = LUKS2_get_default_segment(hdr); |
2301 | |
|
2302 | 0 | jobj_segment = json_segments_get_segment(json_get_segments_jobj(hdr->jobj), segment); |
2303 | 0 | if (!jobj_segment) |
2304 | 0 | return NULL; |
2305 | | |
2306 | | /* FIXME: default encryption (for other segment types) must be string here. */ |
2307 | 0 | return json_segment_get_cipher(jobj_segment) ?: "null"; |
2308 | 0 | } |
2309 | | |
2310 | | crypt_reencrypt_info LUKS2_reencrypt_status(struct luks2_hdr *hdr) |
2311 | 0 | { |
2312 | 0 | uint32_t reqs; |
2313 | |
|
2314 | 0 | LUKS2_config_get_requirements(NULL, hdr, &reqs); |
2315 | |
|
2316 | 0 | if (!reqs_reencrypt_online(reqs)) |
2317 | 0 | return CRYPT_REENCRYPT_NONE; |
2318 | | |
2319 | 0 | if (json_segments_segment_in_reencrypt(LUKS2_get_segments_jobj(hdr)) < 0) |
2320 | 0 | return CRYPT_REENCRYPT_CLEAN; |
2321 | | |
2322 | 0 | return CRYPT_REENCRYPT_CRASH; |
2323 | 0 | } |
2324 | | |
2325 | | const char *LUKS2_get_keyslot_cipher(struct luks2_hdr *hdr, int keyslot, size_t *key_size) |
2326 | 0 | { |
2327 | 0 | json_object *jobj_keyslot, *jobj_area, *jobj1; |
2328 | |
|
2329 | 0 | jobj_keyslot = LUKS2_get_keyslot_jobj(hdr, keyslot); |
2330 | 0 | if (!jobj_keyslot) |
2331 | 0 | return NULL; |
2332 | | |
2333 | 0 | if (!json_object_object_get_ex(jobj_keyslot, "area", &jobj_area)) |
2334 | 0 | return NULL; |
2335 | | |
2336 | | /* currently we only support raw length preserving area encryption */ |
2337 | 0 | json_object_object_get_ex(jobj_area, "type", &jobj1); |
2338 | 0 | if (strcmp(json_object_get_string(jobj1), "raw")) |
2339 | 0 | return NULL; |
2340 | | |
2341 | 0 | if (!json_object_object_get_ex(jobj_area, "key_size", &jobj1)) |
2342 | 0 | return NULL; |
2343 | 0 | *key_size = json_object_get_int(jobj1); |
2344 | |
|
2345 | 0 | if (!json_object_object_get_ex(jobj_area, "encryption", &jobj1)) |
2346 | 0 | return NULL; |
2347 | | |
2348 | 0 | return json_object_get_string(jobj1); |
2349 | 0 | } |
2350 | | |
2351 | | const char *LUKS2_get_integrity(struct luks2_hdr *hdr, int segment) |
2352 | 0 | { |
2353 | 0 | json_object *jobj1, *jobj2, *jobj3; |
2354 | |
|
2355 | 0 | jobj1 = LUKS2_get_segment_jobj(hdr, segment); |
2356 | 0 | if (!jobj1) |
2357 | 0 | return NULL; |
2358 | | |
2359 | 0 | if (!json_object_object_get_ex(jobj1, "integrity", &jobj2)) |
2360 | 0 | return NULL; |
2361 | | |
2362 | 0 | if (!json_object_object_get_ex(jobj2, "type", &jobj3)) |
2363 | 0 | return NULL; |
2364 | | |
2365 | 0 | return json_object_get_string(jobj3); |
2366 | 0 | } |
2367 | | |
2368 | | int LUKS2_get_integrity_key_size(struct luks2_hdr *hdr, int segment) |
2369 | 0 | { |
2370 | 0 | json_object *jobj1, *jobj2, *jobj3; |
2371 | |
|
2372 | 0 | jobj1 = LUKS2_get_segment_jobj(hdr, segment); |
2373 | 0 | if (!jobj1) |
2374 | 0 | return -1; |
2375 | | |
2376 | 0 | if (!json_object_object_get_ex(jobj1, "integrity", &jobj2)) |
2377 | 0 | return -1; |
2378 | | |
2379 | | /* The value is optional, do not fail if not present */ |
2380 | 0 | if (!json_object_object_get_ex(jobj2, "key_size", &jobj3)) |
2381 | 0 | return 0; |
2382 | | |
2383 | 0 | return json_object_get_int(jobj3); |
2384 | 0 | } |
2385 | | |
2386 | | /* FIXME: this only ensures that once we have journal encryption, it is not ignored. */ |
2387 | | /* implement segment count and type restrictions (crypt and only single crypt) */ |
2388 | | static int LUKS2_integrity_compatible(struct luks2_hdr *hdr) |
2389 | 0 | { |
2390 | 0 | json_object *jobj1, *jobj2, *jobj3, *jobj4; |
2391 | 0 | const char *str; |
2392 | |
|
2393 | 0 | if (!json_object_object_get_ex(hdr->jobj, "segments", &jobj1)) |
2394 | 0 | return 0; |
2395 | | |
2396 | 0 | if (!(jobj2 = LUKS2_get_segment_jobj(hdr, CRYPT_DEFAULT_SEGMENT))) |
2397 | 0 | return 0; |
2398 | | |
2399 | 0 | if (!json_object_object_get_ex(jobj2, "integrity", &jobj3)) |
2400 | 0 | return 0; |
2401 | | |
2402 | 0 | if (!json_object_object_get_ex(jobj3, "journal_encryption", &jobj4) || |
2403 | 0 | !(str = json_object_get_string(jobj4)) || |
2404 | 0 | strcmp(str, "none")) |
2405 | 0 | return 0; |
2406 | | |
2407 | 0 | if (!json_object_object_get_ex(jobj3, "journal_integrity", &jobj4) || |
2408 | 0 | !(str = json_object_get_string(jobj4)) || |
2409 | 0 | strcmp(str, "none")) |
2410 | 0 | return 0; |
2411 | | |
2412 | 0 | return 1; |
2413 | 0 | } |
2414 | | |
2415 | | static int LUKS2_keyslot_get_volume_key_size(struct luks2_hdr *hdr, const char *keyslot) |
2416 | 0 | { |
2417 | 0 | json_object *jobj1, *jobj2, *jobj3; |
2418 | |
|
2419 | 0 | if (!json_object_object_get_ex(hdr->jobj, "keyslots", &jobj1)) |
2420 | 0 | return -1; |
2421 | | |
2422 | 0 | if (!json_object_object_get_ex(jobj1, keyslot, &jobj2)) |
2423 | 0 | return -1; |
2424 | | |
2425 | 0 | if (!json_object_object_get_ex(jobj2, "key_size", &jobj3)) |
2426 | 0 | return -1; |
2427 | | |
2428 | 0 | return json_object_get_int(jobj3); |
2429 | 0 | } |
2430 | | |
2431 | | /* Key size used for encryption of keyslot */ |
2432 | | int LUKS2_get_keyslot_stored_key_size(struct luks2_hdr *hdr, int keyslot) |
2433 | 0 | { |
2434 | 0 | char keyslot_name[16]; |
2435 | |
|
2436 | 0 | if (snprintf(keyslot_name, sizeof(keyslot_name), "%u", keyslot) < 1) |
2437 | 0 | return -1; |
2438 | | |
2439 | 0 | return LUKS2_keyslot_get_volume_key_size(hdr, keyslot_name); |
2440 | 0 | } |
2441 | | |
2442 | | int LUKS2_get_volume_key_size(struct luks2_hdr *hdr, int segment) |
2443 | 0 | { |
2444 | 0 | json_object *jobj_digests, *jobj_digest_segments, *jobj_digest_keyslots, *jobj1; |
2445 | 0 | char buf[16]; |
2446 | |
|
2447 | 0 | if (segment == CRYPT_DEFAULT_SEGMENT) |
2448 | 0 | segment = LUKS2_get_default_segment(hdr); |
2449 | |
|
2450 | 0 | if (snprintf(buf, sizeof(buf), "%u", segment) < 1) |
2451 | 0 | return -1; |
2452 | | |
2453 | 0 | json_object_object_get_ex(hdr->jobj, "digests", &jobj_digests); |
2454 | |
|
2455 | 0 | json_object_object_foreach(jobj_digests, key, val) { |
2456 | 0 | UNUSED(key); |
2457 | 0 | json_object_object_get_ex(val, "segments", &jobj_digest_segments); |
2458 | 0 | json_object_object_get_ex(val, "keyslots", &jobj_digest_keyslots); |
2459 | |
|
2460 | 0 | if (!LUKS2_array_jobj(jobj_digest_segments, buf)) |
2461 | 0 | continue; |
2462 | 0 | if (json_object_array_length(jobj_digest_keyslots) <= 0) |
2463 | 0 | continue; |
2464 | | |
2465 | 0 | jobj1 = json_object_array_get_idx(jobj_digest_keyslots, 0); |
2466 | |
|
2467 | 0 | return LUKS2_keyslot_get_volume_key_size(hdr, json_object_get_string(jobj1)); |
2468 | 0 | } |
2469 | | |
2470 | 0 | return -1; |
2471 | 0 | } |
2472 | | |
2473 | | int LUKS2_get_old_volume_key_size(struct luks2_hdr *hdr) |
2474 | 0 | { |
2475 | 0 | int old_segment; |
2476 | |
|
2477 | 0 | assert(hdr); |
2478 | |
|
2479 | 0 | old_segment = LUKS2_reencrypt_segment_old(hdr); |
2480 | 0 | if (old_segment < 0) |
2481 | 0 | return old_segment; |
2482 | | |
2483 | 0 | return LUKS2_get_volume_key_size(hdr, old_segment); |
2484 | 0 | } |
2485 | | |
2486 | | uint32_t LUKS2_get_sector_size(struct luks2_hdr *hdr) |
2487 | 1.83k | { |
2488 | 1.83k | return json_segment_get_sector_size(LUKS2_get_segment_jobj(hdr, CRYPT_DEFAULT_SEGMENT)); |
2489 | 1.83k | } |
2490 | | |
2491 | | int LUKS2_assembly_multisegment_dmd(struct crypt_device *cd, |
2492 | | struct luks2_hdr *hdr, |
2493 | | struct volume_key *vks, |
2494 | | json_object *jobj_segments, |
2495 | | struct crypt_dm_active_device *dmd) |
2496 | 0 | { |
2497 | 0 | struct volume_key *vk; |
2498 | 0 | json_object *jobj; |
2499 | 0 | enum devcheck device_check; |
2500 | 0 | int r; |
2501 | 0 | unsigned s = 0; |
2502 | 0 | uint64_t data_offset, segment_size, segment_offset, segment_start = 0; |
2503 | 0 | struct dm_target *t = &dmd->segment; |
2504 | |
|
2505 | 0 | if (dmd->flags & CRYPT_ACTIVATE_SHARED) |
2506 | 0 | device_check = DEV_OK; |
2507 | 0 | else |
2508 | 0 | device_check = DEV_EXCL; |
2509 | |
|
2510 | 0 | data_offset = LUKS2_reencrypt_data_offset(hdr, true); |
2511 | |
|
2512 | 0 | r = device_block_adjust(cd, crypt_data_device(cd), device_check, |
2513 | 0 | data_offset, &dmd->size, &dmd->flags); |
2514 | 0 | if (r) |
2515 | 0 | return r; |
2516 | | |
2517 | 0 | r = dm_targets_allocate(&dmd->segment, json_segments_count(jobj_segments)); |
2518 | 0 | if (r) |
2519 | 0 | goto err; |
2520 | | |
2521 | 0 | r = -EINVAL; |
2522 | |
|
2523 | 0 | while (t) { |
2524 | 0 | jobj = json_segments_get_segment(jobj_segments, s); |
2525 | 0 | if (!jobj) { |
2526 | 0 | log_dbg(cd, "Internal error. Segment %u is null.", s); |
2527 | 0 | r = -EINVAL; |
2528 | 0 | goto err; |
2529 | 0 | } |
2530 | | |
2531 | 0 | segment_offset = json_segment_get_offset(jobj, 1); |
2532 | 0 | segment_size = json_segment_get_size(jobj, 1); |
2533 | | /* 'dynamic' length allowed in last segment only */ |
2534 | 0 | if (!segment_size && !t->next) |
2535 | 0 | segment_size = dmd->size - segment_start; |
2536 | 0 | if (!segment_size) { |
2537 | 0 | log_dbg(cd, "Internal error. Wrong segment size %u", s); |
2538 | 0 | r = -EINVAL; |
2539 | 0 | goto err; |
2540 | 0 | } |
2541 | | |
2542 | 0 | if (!strcmp(json_segment_type(jobj), "crypt")) { |
2543 | 0 | vk = crypt_volume_key_by_id(vks, LUKS2_digest_by_segment(hdr, s)); |
2544 | 0 | if (!vk) { |
2545 | 0 | log_err(cd, _("Missing key for dm-crypt segment %u"), s); |
2546 | 0 | r = -EINVAL; |
2547 | 0 | goto err; |
2548 | 0 | } |
2549 | | |
2550 | 0 | r = dm_crypt_target_set(t, segment_start, segment_size, |
2551 | 0 | crypt_data_device(cd), vk, |
2552 | 0 | json_segment_get_cipher(jobj), |
2553 | 0 | json_segment_get_iv_offset(jobj), |
2554 | 0 | segment_offset, "none", 0, 0, |
2555 | 0 | json_segment_get_sector_size(jobj)); |
2556 | 0 | if (r) { |
2557 | 0 | log_err(cd, _("Failed to set dm-crypt segment.")); |
2558 | 0 | goto err; |
2559 | 0 | } |
2560 | 0 | } else if (!strcmp(json_segment_type(jobj), "linear")) { |
2561 | 0 | r = dm_linear_target_set(t, segment_start, segment_size, crypt_data_device(cd), segment_offset); |
2562 | 0 | if (r) { |
2563 | 0 | log_err(cd, _("Failed to set dm-linear segment.")); |
2564 | 0 | goto err; |
2565 | 0 | } |
2566 | 0 | } else { |
2567 | 0 | r = -EINVAL; |
2568 | 0 | goto err; |
2569 | 0 | } |
2570 | | |
2571 | 0 | segment_start += segment_size; |
2572 | 0 | t = t->next; |
2573 | 0 | s++; |
2574 | 0 | } |
2575 | | |
2576 | 0 | return r; |
2577 | 0 | err: |
2578 | 0 | dm_targets_free(cd, dmd); |
2579 | 0 | return r; |
2580 | 0 | } |
2581 | | |
2582 | | /* FIXME: This shares almost all code with activate_multi_custom */ |
2583 | | static int _reload_custom_multi(struct crypt_device *cd, |
2584 | | const char *name, |
2585 | | struct volume_key *vks, |
2586 | | json_object *jobj_segments, |
2587 | | uint64_t device_size, |
2588 | | uint32_t flags) |
2589 | 0 | { |
2590 | 0 | int r; |
2591 | 0 | struct luks2_hdr *hdr = crypt_get_hdr(cd, CRYPT_LUKS2); |
2592 | 0 | struct crypt_dm_active_device dmd = { |
2593 | 0 | .uuid = crypt_get_uuid(cd), |
2594 | 0 | .size = device_size >> SECTOR_SHIFT |
2595 | 0 | }; |
2596 | | |
2597 | | /* do not allow activation when particular requirements detected */ |
2598 | 0 | if ((r = LUKS2_unmet_requirements(cd, hdr, CRYPT_REQUIREMENT_ONLINE_REENCRYPT, 0))) |
2599 | 0 | return r; |
2600 | | |
2601 | | /* Add persistent activation flags */ |
2602 | 0 | if (!(flags & CRYPT_ACTIVATE_IGNORE_PERSISTENT)) |
2603 | 0 | LUKS2_config_get_flags(cd, hdr, &dmd.flags); |
2604 | |
|
2605 | 0 | dmd.flags |= (flags | CRYPT_ACTIVATE_SHARED); |
2606 | |
|
2607 | 0 | r = LUKS2_assembly_multisegment_dmd(cd, hdr, vks, jobj_segments, &dmd); |
2608 | 0 | if (!r) |
2609 | 0 | r = dm_reload_device(cd, name, &dmd, 0, 0); |
2610 | |
|
2611 | 0 | dm_targets_free(cd, &dmd); |
2612 | 0 | return r; |
2613 | 0 | } |
2614 | | |
2615 | | int LUKS2_reload(struct crypt_device *cd, |
2616 | | const char *name, |
2617 | | struct volume_key *vks, |
2618 | | uint64_t device_size, |
2619 | | uint32_t flags) |
2620 | 0 | { |
2621 | 0 | if (crypt_get_integrity_tag_size(cd)) |
2622 | 0 | return -ENOTSUP; |
2623 | | |
2624 | 0 | return _reload_custom_multi(cd, name, vks, |
2625 | 0 | LUKS2_get_segments_jobj(crypt_get_hdr(cd, CRYPT_LUKS2)), device_size, flags); |
2626 | 0 | } |
2627 | | |
2628 | | int LUKS2_activate_multi(struct crypt_device *cd, |
2629 | | const char *name, |
2630 | | struct volume_key *vks, |
2631 | | uint64_t device_size, |
2632 | | uint32_t flags) |
2633 | 0 | { |
2634 | 0 | struct luks2_hdr *hdr = crypt_get_hdr(cd, CRYPT_LUKS2); |
2635 | 0 | json_object *jobj_segments = LUKS2_get_segments_jobj(hdr); |
2636 | 0 | int r; |
2637 | 0 | struct crypt_dm_active_device dmd = { |
2638 | 0 | .size = device_size, |
2639 | 0 | .uuid = crypt_get_uuid(cd) |
2640 | 0 | }; |
2641 | | |
2642 | | /* do not allow activation when particular requirements detected */ |
2643 | 0 | if ((r = LUKS2_unmet_requirements(cd, hdr, CRYPT_REQUIREMENT_ONLINE_REENCRYPT, 0))) |
2644 | 0 | return r; |
2645 | | |
2646 | | /* Add persistent activation flags */ |
2647 | 0 | if (!(flags & CRYPT_ACTIVATE_IGNORE_PERSISTENT)) |
2648 | 0 | LUKS2_config_get_flags(cd, hdr, &dmd.flags); |
2649 | |
|
2650 | 0 | dmd.flags |= flags; |
2651 | |
|
2652 | 0 | r = LUKS2_assembly_multisegment_dmd(cd, hdr, vks, jobj_segments, &dmd); |
2653 | 0 | if (!r) |
2654 | 0 | r = dm_create_device(cd, name, CRYPT_LUKS2, &dmd); |
2655 | |
|
2656 | 0 | dm_targets_free(cd, &dmd); |
2657 | 0 | return r; |
2658 | 0 | } |
2659 | | |
2660 | | int LUKS2_activate(struct crypt_device *cd, |
2661 | | const char *name, |
2662 | | struct volume_key *crypt_key, |
2663 | | struct volume_key *opal_key, |
2664 | | uint32_t flags) |
2665 | 0 | { |
2666 | 0 | int r; |
2667 | 0 | bool dynamic, read_lock, write_lock, opal_lock_on_error = false; |
2668 | 0 | uint32_t opal_segment_number, req_flags; |
2669 | 0 | uint64_t range_offset_sectors, range_length_sectors, device_length_bytes; |
2670 | 0 | struct luks2_hdr *hdr = crypt_get_hdr(cd, CRYPT_LUKS2); |
2671 | 0 | struct crypt_dm_active_device dmdi = {}, dmd = { |
2672 | 0 | .uuid = crypt_get_uuid(cd) |
2673 | 0 | }; |
2674 | 0 | struct crypt_lock_handle *opal_lh = NULL; |
2675 | | |
2676 | | /* do not allow activation when particular requirements detected */ |
2677 | 0 | if ((r = LUKS2_unmet_requirements(cd, hdr, |
2678 | 0 | CRYPT_REQUIREMENT_OPAL | CRYPT_REQUIREMENT_INLINE_HW_TAGS, 0))) |
2679 | 0 | return r; |
2680 | | |
2681 | | /* Check that cipher is in compatible format */ |
2682 | 0 | if (!crypt_get_cipher(cd)) { |
2683 | 0 | log_err(cd, _("No known cipher specification pattern detected in LUKS2 header.")); |
2684 | 0 | return -EINVAL; |
2685 | 0 | } |
2686 | | |
2687 | 0 | if ((r = LUKS2_get_data_size(hdr, &device_length_bytes, &dynamic))) |
2688 | 0 | return r; |
2689 | | |
2690 | 0 | if (dynamic && opal_key) { |
2691 | 0 | log_err(cd, _("OPAL device must have static device size.")); |
2692 | 0 | return -EINVAL; |
2693 | 0 | } |
2694 | | |
2695 | 0 | if (!dynamic) |
2696 | 0 | dmd.size = device_length_bytes / SECTOR_SIZE; |
2697 | |
|
2698 | 0 | if (opal_key) { |
2699 | 0 | r = crypt_opal_supported(cd, crypt_data_device(cd)); |
2700 | 0 | if (r < 0) |
2701 | 0 | return r; |
2702 | | |
2703 | 0 | r = LUKS2_get_opal_segment_number(hdr, CRYPT_DEFAULT_SEGMENT, &opal_segment_number); |
2704 | 0 | if (r < 0) |
2705 | 0 | return -EINVAL; |
2706 | | |
2707 | 0 | range_length_sectors = LUKS2_opal_segment_size(hdr, CRYPT_DEFAULT_SEGMENT, 1); |
2708 | |
|
2709 | 0 | if (crypt_get_integrity_tag_size(cd)) { |
2710 | 0 | if (dmd.size >= range_length_sectors) { |
2711 | 0 | log_err(cd, _("Encrypted OPAL device with integrity must be smaller than locking range.")); |
2712 | 0 | return -EINVAL; |
2713 | 0 | } |
2714 | 0 | } else { |
2715 | 0 | if (range_length_sectors != dmd.size) { |
2716 | 0 | log_err(cd, _("OPAL device must have same size as locking range.")); |
2717 | 0 | return -EINVAL; |
2718 | 0 | } |
2719 | 0 | } |
2720 | | |
2721 | 0 | range_offset_sectors = crypt_get_data_offset(cd) + crypt_dev_partition_offset(device_path(crypt_data_device(cd))); |
2722 | 0 | r = opal_exclusive_lock(cd, crypt_data_device(cd), &opal_lh); |
2723 | 0 | if (r < 0) { |
2724 | 0 | log_err(cd, _("Failed to acquire OPAL lock on device %s."), device_path(crypt_data_device(cd))); |
2725 | 0 | return -EINVAL; |
2726 | 0 | } |
2727 | | |
2728 | 0 | r = opal_range_check_attributes_and_get_lock_state(cd, crypt_data_device(cd), opal_segment_number, |
2729 | 0 | opal_key, &range_offset_sectors, &range_length_sectors, |
2730 | 0 | &read_lock, &write_lock); |
2731 | 0 | if (r < 0) |
2732 | 0 | goto out; |
2733 | | |
2734 | 0 | opal_lock_on_error = read_lock && write_lock; |
2735 | 0 | if (!opal_lock_on_error && !(flags & CRYPT_ACTIVATE_REFRESH)) |
2736 | 0 | log_std(cd, _("OPAL device is %s already unlocked.\n"), |
2737 | 0 | device_path(crypt_data_device(cd))); |
2738 | |
|
2739 | 0 | r = opal_unlock(cd, crypt_data_device(cd), opal_segment_number, opal_key); |
2740 | 0 | if (r < 0) |
2741 | 0 | goto out; |
2742 | 0 | } |
2743 | | |
2744 | 0 | if (LUKS2_segment_is_type(hdr, CRYPT_DEFAULT_SEGMENT, "crypt") || |
2745 | 0 | LUKS2_segment_is_type(hdr, CRYPT_DEFAULT_SEGMENT, "hw-opal-crypt")) { |
2746 | 0 | r = dm_crypt_target_set(&dmd.segment, 0, |
2747 | 0 | dmd.size, crypt_data_device(cd), |
2748 | 0 | crypt_key, crypt_get_cipher_spec(cd), |
2749 | 0 | crypt_get_iv_offset(cd), crypt_get_data_offset(cd), |
2750 | 0 | crypt_get_integrity(cd) ?: "none", |
2751 | 0 | crypt_get_integrity_key_size(cd, true), crypt_get_integrity_tag_size(cd), |
2752 | 0 | crypt_get_sector_size(cd)); |
2753 | 0 | } else |
2754 | 0 | r = dm_linear_target_set(&dmd.segment, 0, |
2755 | 0 | dmd.size, crypt_data_device(cd), |
2756 | 0 | crypt_get_data_offset(cd)); |
2757 | |
|
2758 | 0 | if (r < 0) |
2759 | 0 | goto out; |
2760 | | |
2761 | | /* Add persistent activation flags */ |
2762 | 0 | if (!(flags & CRYPT_ACTIVATE_IGNORE_PERSISTENT)) |
2763 | 0 | LUKS2_config_get_flags(cd, hdr, &dmd.flags); |
2764 | |
|
2765 | 0 | dmd.flags |= flags; |
2766 | |
|
2767 | 0 | if (crypt_persistent_flags_get(cd, CRYPT_FLAGS_REQUIREMENTS, &req_flags)) { |
2768 | 0 | r = -EINVAL; |
2769 | 0 | goto out; |
2770 | 0 | } |
2771 | | |
2772 | 0 | if (crypt_get_integrity_tag_size(cd) && |
2773 | 0 | !(req_flags & CRYPT_REQUIREMENT_INLINE_HW_TAGS)) { |
2774 | 0 | if (!LUKS2_integrity_compatible(hdr)) { |
2775 | 0 | log_err(cd, _("Unsupported device integrity configuration.")); |
2776 | 0 | r = -EINVAL; |
2777 | 0 | goto out; |
2778 | 0 | } |
2779 | | |
2780 | 0 | if (dmd.flags & CRYPT_ACTIVATE_ALLOW_DISCARDS) { |
2781 | 0 | log_err(cd, _("Discard/TRIM is not supported.")); |
2782 | 0 | r = -EINVAL; |
2783 | 0 | goto out; |
2784 | 0 | } |
2785 | | |
2786 | 0 | r = INTEGRITY_create_dmd_device(cd, NULL, NULL, NULL, NULL, &dmdi, dmd.flags, 0); |
2787 | 0 | if (r) |
2788 | 0 | goto out; |
2789 | | |
2790 | 0 | if (!dynamic && dmdi.size != dmd.size) { |
2791 | 0 | log_err(cd, _("Underlying dm-integrity device with unexpected provided data sectors.")); |
2792 | 0 | r = -EINVAL; |
2793 | 0 | goto out; |
2794 | 0 | } |
2795 | | |
2796 | 0 | dmdi.flags |= CRYPT_ACTIVATE_PRIVATE; |
2797 | 0 | dmdi.uuid = dmd.uuid; |
2798 | 0 | dmd.segment.u.crypt.offset = 0; |
2799 | 0 | if (dynamic) |
2800 | 0 | dmd.segment.size = dmdi.segment.size; |
2801 | |
|
2802 | 0 | r = create_or_reload_device_with_integrity(cd, name, |
2803 | 0 | opal_key ? CRYPT_LUKS2_HW_OPAL : CRYPT_LUKS2, |
2804 | 0 | &dmd, &dmdi); |
2805 | 0 | } else |
2806 | 0 | r = create_or_reload_device(cd, name, |
2807 | 0 | opal_key ? CRYPT_LUKS2_HW_OPAL : CRYPT_LUKS2, |
2808 | 0 | &dmd); |
2809 | | |
2810 | 0 | dm_targets_free(cd, &dmd); |
2811 | 0 | dm_targets_free(cd, &dmdi); |
2812 | 0 | out: |
2813 | 0 | if (r < 0 && opal_lock_on_error) |
2814 | 0 | opal_lock(cd, crypt_data_device(cd), opal_segment_number); |
2815 | |
|
2816 | 0 | opal_exclusive_unlock(cd, opal_lh); |
2817 | |
|
2818 | 0 | return r; |
2819 | 0 | } |
2820 | | |
2821 | | static bool is_reencryption_helper(const char *name) |
2822 | 0 | { |
2823 | 0 | size_t len; |
2824 | |
|
2825 | 0 | if (!name) |
2826 | 0 | return false; |
2827 | | |
2828 | 0 | len = strlen(name); |
2829 | 0 | return (len >= 9 && (!strncmp(name + len - 8, "-hotzone-", 9) || |
2830 | 0 | !strcmp(name + len - 8, "-overlay"))); |
2831 | |
|
2832 | 0 | } |
2833 | | |
2834 | | static bool contains_reencryption_helper(char **names) |
2835 | 0 | { |
2836 | 0 | while (*names) { |
2837 | 0 | if (is_reencryption_helper(*names++)) |
2838 | 0 | return true; |
2839 | 0 | } |
2840 | | |
2841 | 0 | return false; |
2842 | 0 | } |
2843 | | |
2844 | | int LUKS2_deactivate(struct crypt_device *cd, const char *name, struct luks2_hdr *hdr, struct crypt_dm_active_device *dmd, uint32_t flags) |
2845 | 0 | { |
2846 | 0 | bool dm_opal_uuid; |
2847 | 0 | int r, ret; |
2848 | 0 | struct dm_target *tgt; |
2849 | 0 | crypt_status_info ci; |
2850 | 0 | struct crypt_dm_active_device dmdc; |
2851 | 0 | uint32_t opal_segment_number; |
2852 | 0 | char **dep, deps_uuid_prefix[40], *deps[MAX_DM_DEPS+1] = { 0 }; |
2853 | 0 | char *iname = NULL; |
2854 | 0 | struct crypt_lock_handle *reencrypt_lock = NULL, *opal_lh = NULL; |
2855 | |
|
2856 | 0 | if (!dmd || !dmd->uuid || strncmp(CRYPT_LUKS2, dmd->uuid, sizeof(CRYPT_LUKS2)-1)) |
2857 | 0 | return -EINVAL; |
2858 | | |
2859 | | /* uuid mismatch with metadata (if available) */ |
2860 | 0 | if (hdr && dm_uuid_cmp(dmd->uuid, hdr->uuid)) |
2861 | 0 | return -EINVAL; |
2862 | | |
2863 | 0 | r = snprintf(deps_uuid_prefix, sizeof(deps_uuid_prefix), CRYPT_SUBDEV "-%.32s", dmd->uuid + 6); |
2864 | 0 | if (r < 0 || (size_t)r != (sizeof(deps_uuid_prefix) - 1)) |
2865 | 0 | return -EINVAL; |
2866 | | |
2867 | | /* check if active device has LUKS2-OPAL dm uuid prefix */ |
2868 | 0 | dm_opal_uuid = !dm_uuid_type_cmp(dmd->uuid, CRYPT_LUKS2_HW_OPAL); |
2869 | 0 | if (dm_opal_uuid && hdr && !LUKS2_segment_is_hw_opal(hdr, CRYPT_DEFAULT_SEGMENT)) |
2870 | 0 | return -EINVAL; |
2871 | | |
2872 | 0 | tgt = &dmd->segment; |
2873 | | |
2874 | | /* TODO: We have LUKS2 dependencies now */ |
2875 | 0 | if (tgt->type == DM_CRYPT && tgt->u.crypt.tag_size) |
2876 | 0 | iname = dm_get_active_iname(cd, name); |
2877 | |
|
2878 | 0 | r = dm_device_deps(cd, name, deps_uuid_prefix, deps, ARRAY_SIZE(deps)); |
2879 | 0 | if (r < 0) |
2880 | 0 | goto out; |
2881 | | |
2882 | 0 | if (contains_reencryption_helper(deps)) { |
2883 | 0 | r = LUKS2_reencrypt_lock_by_dm_uuid(cd, dmd->uuid, &reencrypt_lock); |
2884 | 0 | if (r) { |
2885 | 0 | if (r == -EBUSY) |
2886 | 0 | log_err(cd, _("Reencryption in-progress. Cannot deactivate device.")); |
2887 | 0 | else |
2888 | 0 | log_err(cd, _("Failed to get reencryption lock.")); |
2889 | 0 | goto out; |
2890 | 0 | } |
2891 | 0 | } |
2892 | | |
2893 | 0 | dep = deps; |
2894 | 0 | while (*dep) { |
2895 | 0 | if (is_reencryption_helper(*dep) && (dm_status_suspended(cd, *dep) > 0)) { |
2896 | 0 | if (dm_error_device(cd, *dep)) |
2897 | 0 | log_err(cd, _("Failed to replace suspended device %s with dm-error target."), *dep); |
2898 | 0 | } |
2899 | 0 | dep++; |
2900 | 0 | } |
2901 | |
|
2902 | 0 | r = dm_query_device(cd, name, DM_ACTIVE_CRYPT_KEY | DM_ACTIVE_CRYPT_KEYSIZE, &dmdc); |
2903 | 0 | if (r < 0) { |
2904 | 0 | memset(&dmdc, 0, sizeof(dmdc)); |
2905 | 0 | dmdc.segment.type = DM_UNKNOWN; |
2906 | 0 | } |
2907 | | |
2908 | | /* Remove top level device first */ |
2909 | 0 | r = dm_remove_device(cd, name, flags); |
2910 | 0 | if (!r) { |
2911 | 0 | tgt = &dmdc.segment; |
2912 | 0 | while (tgt) { |
2913 | 0 | if (tgt->type == DM_CRYPT) |
2914 | 0 | crypt_volume_key_drop_kernel_key(cd, tgt->u.crypt.vk); |
2915 | 0 | tgt = tgt->next; |
2916 | 0 | } |
2917 | 0 | } |
2918 | 0 | dm_targets_free(cd, &dmdc); |
2919 | | |
2920 | | /* TODO: We have LUKS2 dependencies now */ |
2921 | 0 | if (r >= 0 && iname) { |
2922 | 0 | log_dbg(cd, "Deactivating integrity device %s.", iname); |
2923 | 0 | r = dm_remove_device(cd, iname, 0); |
2924 | 0 | } |
2925 | |
|
2926 | 0 | if (!r) { |
2927 | 0 | ret = 0; |
2928 | 0 | dep = deps; |
2929 | 0 | while (*dep) { |
2930 | | /* |
2931 | | * FIXME: dm-integrity has now proper SUBDEV prefix so |
2932 | | * it would be deactivated here, but due to specific |
2933 | | * dm_remove_device(iname) above the iname device |
2934 | | * is no longer active. This will be fixed when |
2935 | | * we switch to SUBDEV deactivation after 2.8 release. |
2936 | | */ |
2937 | 0 | if (iname && !strcmp(*dep, iname)) { |
2938 | 0 | dep++; |
2939 | 0 | continue; |
2940 | 0 | } |
2941 | | |
2942 | 0 | log_dbg(cd, "Deactivating LUKS2 dependent device %s.", *dep); |
2943 | 0 | r = dm_query_device(cd, *dep, DM_ACTIVE_CRYPT_KEY | DM_ACTIVE_CRYPT_KEYSIZE, &dmdc); |
2944 | 0 | if (r < 0) { |
2945 | 0 | memset(&dmdc, 0, sizeof(dmdc)); |
2946 | 0 | dmdc.segment.type = DM_UNKNOWN; |
2947 | 0 | } |
2948 | |
|
2949 | 0 | r = dm_remove_device(cd, *dep, flags); |
2950 | 0 | if (r < 0) { |
2951 | 0 | ci = crypt_status(cd, *dep); |
2952 | 0 | if (ci == CRYPT_BUSY) |
2953 | 0 | log_err(cd, _("Device %s is still in use."), *dep); |
2954 | 0 | if (ci == CRYPT_INACTIVE) |
2955 | 0 | r = 0; |
2956 | 0 | } |
2957 | 0 | if (!r) { |
2958 | 0 | tgt = &dmdc.segment; |
2959 | 0 | while (tgt) { |
2960 | 0 | if (tgt->type == DM_CRYPT) |
2961 | 0 | crypt_volume_key_drop_kernel_key(cd, tgt->u.crypt.vk); |
2962 | 0 | tgt = tgt->next; |
2963 | 0 | } |
2964 | 0 | } |
2965 | 0 | dm_targets_free(cd, &dmdc); |
2966 | 0 | if (r && !ret) |
2967 | 0 | ret = r; |
2968 | 0 | dep++; |
2969 | 0 | } |
2970 | 0 | r = ret; |
2971 | 0 | } |
2972 | |
|
2973 | 0 | if (!r && dm_opal_uuid) { |
2974 | 0 | if (hdr) { |
2975 | 0 | if (LUKS2_get_opal_segment_number(hdr, CRYPT_DEFAULT_SEGMENT, &opal_segment_number)) { |
2976 | 0 | log_err(cd, _("Device %s was deactivated but hardware OPAL device cannot be locked."), |
2977 | 0 | name); |
2978 | 0 | r = -EINVAL; |
2979 | 0 | goto out; |
2980 | 0 | } |
2981 | 0 | } else { |
2982 | | /* Guess OPAL range number for LUKS2-OPAL device with missing header */ |
2983 | 0 | opal_segment_number = 1; |
2984 | 0 | ret = crypt_dev_get_partition_number(device_path(crypt_data_device(cd))); |
2985 | 0 | if (ret > 0) |
2986 | 0 | opal_segment_number = ret; |
2987 | 0 | } |
2988 | | |
2989 | 0 | if (crypt_data_device(cd)) { |
2990 | 0 | r = opal_exclusive_lock(cd, crypt_data_device(cd), &opal_lh); |
2991 | 0 | if (r < 0) { |
2992 | 0 | log_err(cd, _("Failed to acquire OPAL lock on device %s."), device_path(crypt_data_device(cd))); |
2993 | 0 | goto out; |
2994 | 0 | } |
2995 | 0 | } |
2996 | | |
2997 | 0 | if (!crypt_data_device(cd) || opal_lock(cd, crypt_data_device(cd), opal_segment_number)) |
2998 | 0 | log_err(cd, _("Device %s was deactivated but hardware OPAL device cannot be locked."), name); |
2999 | 0 | } |
3000 | 0 | out: |
3001 | 0 | opal_exclusive_unlock(cd, opal_lh); |
3002 | 0 | LUKS2_reencrypt_unlock(cd, reencrypt_lock); |
3003 | 0 | free(iname); |
3004 | 0 | dep = deps; |
3005 | 0 | while (*dep) |
3006 | 0 | free(*dep++); |
3007 | |
|
3008 | 0 | return r; |
3009 | 0 | } |
3010 | | |
3011 | | int LUKS2_unmet_requirements(struct crypt_device *cd, struct luks2_hdr *hdr, uint64_t reqs_mask, int quiet) |
3012 | 0 | { |
3013 | 0 | uint32_t reqs; |
3014 | |
|
3015 | 0 | LUKS2_config_get_requirements(cd, hdr, &reqs); |
3016 | | |
3017 | | /* do not mask unknown requirements check */ |
3018 | 0 | if (reqs_unknown(reqs)) { |
3019 | 0 | if (!quiet) |
3020 | 0 | log_err(cd, _("Unmet LUKS2 requirements detected.")); |
3021 | 0 | return -ETXTBSY; |
3022 | 0 | } |
3023 | | |
3024 | | /* mask out permitted requirements */ |
3025 | 0 | reqs &= ~reqs_mask; |
3026 | |
|
3027 | 0 | if (reqs_reencrypt(reqs) && !quiet) |
3028 | 0 | log_err(cd, _("Operation incompatible with device marked for legacy reencryption. Aborting.")); |
3029 | 0 | if (reqs_reencrypt_online(reqs) && !quiet) |
3030 | 0 | log_err(cd, _("Operation incompatible with device marked for LUKS2 reencryption. Aborting.")); |
3031 | 0 | if (reqs_opal(reqs) && !quiet) |
3032 | 0 | log_err(cd, _("Operation incompatible with device using OPAL. Aborting.")); |
3033 | 0 | if (reqs_inline_hw_tags(reqs) && !quiet) |
3034 | 0 | log_err(cd, _("Operation incompatible with device using inline HW tags. Aborting.")); |
3035 | | |
3036 | | /* any remaining unmasked requirement fails the check */ |
3037 | 0 | return reqs ? -EINVAL : 0; |
3038 | 0 | } |
3039 | | |
3040 | | /* |
3041 | | * NOTE: this routine is called on json object that failed validation. |
3042 | | * Proceed with caution :) |
3043 | | * |
3044 | | * known glitches so far: |
3045 | | * |
3046 | | * any version < 2.0.3: |
3047 | | * - luks2 keyslot pbkdf params change via crypt_keyslot_change_by_passphrase() |
3048 | | * could leave previous type parameters behind. Correct this by purging |
3049 | | * all params not needed by current type. |
3050 | | */ |
3051 | | void LUKS2_hdr_repair(struct crypt_device *cd, json_object *hdr_jobj) |
3052 | 1.66k | { |
3053 | 1.66k | json_object *jobj_keyslots; |
3054 | | |
3055 | 1.66k | if (!json_object_object_get_ex(hdr_jobj, "keyslots", &jobj_keyslots)) |
3056 | 1.29k | return; |
3057 | 368 | if (!json_object_is_type(jobj_keyslots, json_type_object)) |
3058 | 11 | return; |
3059 | | |
3060 | 357 | LUKS2_keyslots_repair(cd, jobj_keyslots); |
3061 | 357 | } |
3062 | | |
3063 | | void json_object_object_del_by_uint(json_object *jobj, unsigned key) |
3064 | 0 | { |
3065 | 0 | char key_name[16]; |
3066 | |
|
3067 | 0 | if (snprintf(key_name, sizeof(key_name), "%u", key) < 1) |
3068 | 0 | return; |
3069 | 0 | json_object_object_del(jobj, key_name); |
3070 | 0 | } |
3071 | | |
3072 | | int json_object_object_add_by_uint(json_object *jobj, unsigned key, json_object *jobj_val) |
3073 | 0 | { |
3074 | 0 | char key_name[16]; |
3075 | |
|
3076 | 0 | if (snprintf(key_name, sizeof(key_name), "%u", key) < 1) |
3077 | 0 | return -EINVAL; |
3078 | | |
3079 | 0 | #if HAVE_DECL_JSON_OBJECT_OBJECT_ADD_EX |
3080 | 0 | return json_object_object_add_ex(jobj, key_name, jobj_val, 0) ? -ENOMEM : 0; |
3081 | | #else |
3082 | | json_object_object_add(jobj, key_name, jobj_val); |
3083 | | return 0; |
3084 | | #endif |
3085 | 0 | } |
3086 | | |
3087 | | int json_object_object_add_by_uint_by_ref(json_object *jobj, unsigned key, json_object **jobj_val_ref) |
3088 | 0 | { |
3089 | 0 | int r; |
3090 | |
|
3091 | 0 | assert(jobj); |
3092 | 0 | assert(jobj_val_ref); |
3093 | |
|
3094 | 0 | r = json_object_object_add_by_uint(jobj, key, *jobj_val_ref); |
3095 | 0 | if (!r) |
3096 | 0 | *jobj_val_ref = NULL; |
3097 | |
|
3098 | 0 | return r; |
3099 | 0 | } |
3100 | | |
3101 | | /* jobj_dst must contain pointer initialized to NULL (see json-c json_object_deep_copy API) */ |
3102 | | int json_object_copy(json_object *jobj_src, json_object **jobj_dst) |
3103 | 1.83k | { |
3104 | 1.83k | if (!jobj_src || !jobj_dst || *jobj_dst) |
3105 | 0 | return -1; |
3106 | | |
3107 | 1.83k | #if HAVE_DECL_JSON_OBJECT_DEEP_COPY |
3108 | 1.83k | return json_object_deep_copy(jobj_src, jobj_dst, NULL); |
3109 | | #else |
3110 | | *jobj_dst = json_tokener_parse(json_object_get_string(jobj_src)); |
3111 | | return *jobj_dst ? 0 : -1; |
3112 | | #endif |
3113 | 1.83k | } |
3114 | | |
3115 | | int LUKS2_split_crypt_and_opal_keys(struct crypt_device *cd __attribute__((unused)), |
3116 | | struct luks2_hdr *hdr, |
3117 | | const struct volume_key *vk, |
3118 | | struct volume_key **ret_crypt_key, |
3119 | | struct volume_key **ret_opal_key) |
3120 | 0 | { |
3121 | 0 | int r; |
3122 | 0 | uint32_t opal_segment_number; |
3123 | 0 | size_t opal_user_key_size; |
3124 | 0 | json_object *jobj_segment; |
3125 | 0 | struct volume_key *opal_key, *crypt_key; |
3126 | |
|
3127 | 0 | assert(vk); |
3128 | 0 | assert(ret_crypt_key); |
3129 | 0 | assert(ret_opal_key); |
3130 | |
|
3131 | 0 | jobj_segment = LUKS2_get_segment_jobj(hdr, CRYPT_DEFAULT_SEGMENT); |
3132 | 0 | if (!jobj_segment) |
3133 | 0 | return -EINVAL; |
3134 | | |
3135 | 0 | r = json_segment_get_opal_segment_id(jobj_segment, &opal_segment_number); |
3136 | 0 | if (r < 0) |
3137 | 0 | return -EINVAL; |
3138 | | |
3139 | 0 | r = json_segment_get_opal_key_size(jobj_segment, &opal_user_key_size); |
3140 | 0 | if (r < 0) |
3141 | 0 | return -EINVAL; |
3142 | | |
3143 | 0 | if (crypt_volume_key_length(vk) < opal_user_key_size) |
3144 | 0 | return -EINVAL; |
3145 | | |
3146 | | /* OPAL SEGMENT only */ |
3147 | 0 | if (crypt_volume_key_length(vk) == opal_user_key_size) { |
3148 | 0 | *ret_crypt_key = NULL; |
3149 | 0 | *ret_opal_key = NULL; |
3150 | 0 | return 0; |
3151 | 0 | } |
3152 | | |
3153 | 0 | opal_key = crypt_alloc_volume_key(opal_user_key_size, crypt_volume_key_get_key(vk)); |
3154 | 0 | if (!opal_key) |
3155 | 0 | return -ENOMEM; |
3156 | | |
3157 | 0 | crypt_key = crypt_alloc_volume_key(crypt_volume_key_length(vk) - opal_user_key_size, |
3158 | 0 | crypt_volume_key_get_key(vk) + opal_user_key_size); |
3159 | 0 | if (!crypt_key) { |
3160 | 0 | crypt_free_volume_key(opal_key); |
3161 | 0 | return -ENOMEM; |
3162 | 0 | } |
3163 | | |
3164 | 0 | *ret_opal_key = opal_key; |
3165 | 0 | *ret_crypt_key = crypt_key; |
3166 | |
|
3167 | 0 | return 0; |
3168 | 0 | } |