diff -rupN cryptsetup-2.3.3.old/lib/luks2/luks2_internal.h cryptsetup-2.3.3/lib/luks2/luks2_internal.h --- cryptsetup-2.3.3.old/lib/luks2/luks2_internal.h 2022-01-17 16:14:07.530136302 +0100 +++ cryptsetup-2.3.3/lib/luks2/luks2_internal.h 2022-01-17 16:15:29.134422136 +0100 @@ -207,5 +207,6 @@ static inline const char *crypt_reencryp } bool json_segment_contains_flag(json_object *jobj_segment, const char *flag_str, size_t len); +bool json_segment_cmp(json_object *jobj_segment_1, json_object *jobj_segment_2); #endif diff -rupN cryptsetup-2.3.3.old/lib/luks2/luks2_json_metadata.c cryptsetup-2.3.3/lib/luks2/luks2_json_metadata.c --- cryptsetup-2.3.3.old/lib/luks2/luks2_json_metadata.c 2022-01-17 16:14:07.530136302 +0100 +++ cryptsetup-2.3.3/lib/luks2/luks2_json_metadata.c 2022-01-17 16:16:34.382650680 +0100 @@ -606,6 +606,63 @@ static int reqs_reencrypt_online(uint32_ return reqs & CRYPT_REQUIREMENT_ONLINE_REENCRYPT; } +/* + * Config section requirements object must be valid. + * Also general segments section must be validated first. + */ +static int validate_reencrypt_segments(struct crypt_device *cd, json_object *hdr_jobj, json_object *jobj_segments, int first_backup, int segments_count) +{ + json_object *jobj, *jobj_backup_previous = NULL, *jobj_backup_final = NULL; + uint32_t reqs; + int i, r; + struct luks2_hdr dummy = { + .jobj = hdr_jobj + }; + + r = LUKS2_config_get_requirements(cd, &dummy, &reqs); + if (r) + return 1; + + if (reqs_reencrypt_online(reqs)) { + for (i = first_backup; i < segments_count; i++) { + jobj = json_segments_get_segment(jobj_segments, i); + if (!jobj) + return 1; + if (json_segment_contains_flag(jobj, "backup-final", 0)) + jobj_backup_final = jobj; + else if (json_segment_contains_flag(jobj, "backup-previous", 0)) + jobj_backup_previous = jobj; + } + + if (!jobj_backup_final || !jobj_backup_previous) { + log_dbg(cd, "Backup segment is missing."); + return 1; + } + + for (i = 0; i < first_backup; i++) { + jobj = json_segments_get_segment(jobj_segments, i); + if (!jobj) + return 1; + + if (json_segment_contains_flag(jobj, "in-reencryption", 0)) { + if (!json_segment_cmp(jobj, jobj_backup_final)) { + log_dbg(cd, "Segment in reencryption does not match backup final segment."); + return 1; + } + continue; + } + + if (!json_segment_cmp(jobj, jobj_backup_final) && + !json_segment_cmp(jobj, jobj_backup_previous)) { + log_dbg(cd, "Segment does not match neither backup final or backup previous segment."); + return 1; + } + } + } + + return 0; +} + static int hdr_validate_segments(struct crypt_device *cd, json_object *hdr_jobj) { json_object *jobj_segments, *jobj_digests, *jobj_offset, *jobj_size, *jobj_type, *jobj_flags, *jobj; @@ -732,7 +789,7 @@ static int hdr_validate_segments(struct } } - return 0; + return validate_reencrypt_segments(cd, hdr_jobj, jobj_segments, first_backup, count); } uint64_t LUKS2_metadata_size(json_object *jobj) diff -rupN cryptsetup-2.3.3.old/lib/luks2/luks2_segment.c cryptsetup-2.3.3/lib/luks2/luks2_segment.c --- cryptsetup-2.3.3.old/lib/luks2/luks2_segment.c 2022-01-17 16:14:07.531136305 +0100 +++ cryptsetup-2.3.3/lib/luks2/luks2_segment.c 2022-01-17 16:14:43.952263876 +0100 @@ -410,3 +410,23 @@ json_object *LUKS2_get_segment_by_flag(s return jobj_segment; } + +/* compares key characteristics of both segments */ +bool json_segment_cmp(json_object *jobj_segment_1, json_object *jobj_segment_2) +{ + const char *type = json_segment_type(jobj_segment_1); + const char *type2 = json_segment_type(jobj_segment_2); + + if (!type || !type2) + return false; + + if (strcmp(type, type2)) + return false; + + if (!strcmp(type, "crypt")) + return (json_segment_get_sector_size(jobj_segment_1) == json_segment_get_sector_size(jobj_segment_2) && + !strcmp(json_segment_get_cipher(jobj_segment_1), + json_segment_get_cipher(jobj_segment_2))); + + return true; +}