Add segments validation for reencryption.

Effective segments during LUKS2 reencryption must
match key characteristics of backup segment
(cipher, sector_size, segment type).
This commit is contained in:
Ondrej Kozina
2022-01-06 14:49:52 +01:00
committed by Milan Broz
parent 7420f879e0
commit b61ec23e48
3 changed files with 79 additions and 1 deletions

View File

@@ -263,6 +263,7 @@ uint64_t json_segments_get_minimal_offset(json_object *jobj_segments, unsigned b
json_object *json_segment_create_linear(uint64_t offset, const uint64_t *length, unsigned reencryption);
json_object *json_segment_create_crypt(uint64_t offset, uint64_t iv_offset, const uint64_t *length, const char *cipher, uint32_t sector_size, unsigned reencryption);
int json_segments_segment_in_reencrypt(json_object *jobj_segments);
bool json_segment_cmp(json_object *jobj_segment_1, json_object *jobj_segment_2);
bool json_segment_contains_flag(json_object *jobj_segment, const char *flag_str, size_t len);
int LUKS2_assembly_multisegment_dmd(struct crypt_device *cd,

View File

@@ -607,6 +607,63 @@ static int reqs_reencrypt_online(uint32_t reqs)
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;
@@ -733,7 +790,7 @@ static int hdr_validate_segments(struct crypt_device *cd, json_object *hdr_jobj)
}
}
return 0;
return validate_reencrypt_segments(cd, hdr_jobj, jobj_segments, first_backup, count);
}
static uint64_t LUKS2_metadata_size_jobj(json_object *jobj)

View File

@@ -410,3 +410,23 @@ json_object *LUKS2_get_segment_by_flag(struct luks2_hdr *hdr, const char *flag)
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;
}