Blob Blame History Raw
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;
+}