Blame SOURCES/cryptsetup-2.0.6-reshuffle-config-and-keyslots-areas-validation-code.patch

7cdc99
diff -rupN cryptsetup-2.0.3.old/lib/luks2/luks2_json_metadata.c cryptsetup-2.0.3/lib/luks2/luks2_json_metadata.c
7cdc99
--- cryptsetup-2.0.3.old/lib/luks2/luks2_json_metadata.c	2019-03-28 11:32:18.850058719 +0100
7cdc99
+++ cryptsetup-2.0.3/lib/luks2/luks2_json_metadata.c	2019-03-28 11:33:07.610800041 +0100
7cdc99
@@ -643,7 +643,7 @@ static int hdr_validate_areas(json_objec
7cdc99
 	struct interval *intervals;
7cdc99
 	json_object *jobj_keyslots, *jobj_offset, *jobj_length, *jobj_segments, *jobj_area;
7cdc99
 	int length, ret, i = 0;
7cdc99
-	uint64_t first_offset;
7cdc99
+	uint64_t first_offset, keyslots_size, keyslots_area_sum = 0;
7cdc99
 
7cdc99
 	if (!json_object_object_get_ex(hdr_jobj, "keyslots", &jobj_keyslots))
7cdc99
 		return 1;
7cdc99
@@ -652,6 +652,9 @@ static int hdr_validate_areas(json_objec
7cdc99
 	if (!json_object_object_get_ex(hdr_jobj, "segments", &jobj_segments))
7cdc99
 		return 1;
7cdc99
 
7cdc99
+	/* config is already validated */
7cdc99
+	keyslots_size = LUKS2_keyslots_size(hdr_jobj);
7cdc99
+
7cdc99
 	length = json_object_object_length(jobj_keyslots);
7cdc99
 
7cdc99
 	/* Empty section */
7cdc99
@@ -687,6 +690,8 @@ static int hdr_validate_areas(json_objec
7cdc99
 			return 1;
7cdc99
 		}
7cdc99
 
7cdc99
+		keyslots_area_sum += intervals[i].length;
7cdc99
+
7cdc99
 		i++;
7cdc99
 	}
7cdc99
 
7cdc99
@@ -694,6 +699,13 @@ static int hdr_validate_areas(json_objec
7cdc99
 		free(intervals);
7cdc99
 		return 1;
7cdc99
 	}
7cdc99
+ 
7cdc99
+	if (keyslots_area_sum > keyslots_size) {
7cdc99
+		log_dbg("Sum of all keyslot area sizes (%" PRIu64 ") is greater than value in config section %"
7cdc99
+			PRIu64, keyslots_area_sum, keyslots_size);
7cdc99
+		free(intervals);
7cdc99
+		return 1;
7cdc99
+	}
7cdc99
 
7cdc99
 	first_offset = get_first_data_offset(jobj_segments, NULL);
7cdc99
 
7cdc99
@@ -739,45 +751,11 @@ static int hdr_validate_digests(json_obj
7cdc99
 	return 0;
7cdc99
 }
7cdc99
 
7cdc99
-/* requires keyslots and segments sections being already validated */
7cdc99
-static int validate_keyslots_size(json_object *hdr_jobj, uint64_t metadata_size, uint64_t keyslots_size)
7cdc99
-{
7cdc99
-	json_object *jobj_keyslots, *jobj, *jobj1;
7cdc99
-	uint64_t segment_offset, keyslots_area_sum = 0;
7cdc99
-
7cdc99
-	json_object_object_get_ex(hdr_jobj, "segments", &jobj);
7cdc99
-	segment_offset = get_first_data_offset(jobj, "crypt");
7cdc99
-	if (segment_offset &&
7cdc99
-	    (segment_offset < keyslots_size ||
7cdc99
-	     (segment_offset - keyslots_size) < (2 * metadata_size))) {
7cdc99
-		log_dbg("keyslots_size is too large %" PRIu64 " (bytes). Data offset: %" PRIu64
7cdc99
-			", keyslots offset: %" PRIu64, keyslots_size, segment_offset, 2 * metadata_size);
7cdc99
-		return 1;
7cdc99
-	}
7cdc99
-
7cdc99
-	json_object_object_get_ex(hdr_jobj, "keyslots", &jobj_keyslots);
7cdc99
-
7cdc99
-	json_object_object_foreach(jobj_keyslots, key, val) {
7cdc99
-		UNUSED(key);
7cdc99
-		json_object_object_get_ex(val, "area", &jobj);
7cdc99
-		json_object_object_get_ex(jobj, "size", &jobj1);
7cdc99
-		keyslots_area_sum += json_object_get_uint64(jobj1);
7cdc99
-	}
7cdc99
-
7cdc99
-	if (keyslots_area_sum > keyslots_size) {
7cdc99
-		log_dbg("Sum of all keyslot area sizes (%" PRIu64 ") is greater than value in config section %"
7cdc99
-			PRIu64, keyslots_area_sum, keyslots_size);
7cdc99
-		return 1;
7cdc99
-	}
7cdc99
-
7cdc99
-	return 0;
7cdc99
-}
7cdc99
-
7cdc99
 static int hdr_validate_config(json_object *hdr_jobj)
7cdc99
 {
7cdc99
 	json_object *jobj_config, *jobj, *jobj1;
7cdc99
 	int i;
7cdc99
-	uint64_t json_size, keyslots_size;
7cdc99
+	uint64_t keyslots_size, metadata_size, segment_offset;
7cdc99
 
7cdc99
 	if (!json_object_object_get_ex(hdr_jobj, "config", &jobj_config)) {
7cdc99
 		log_dbg("Missing config section.");
7cdc99
@@ -785,15 +763,19 @@ static int hdr_validate_config(json_obje
7cdc99
 	}
7cdc99
 
7cdc99
 	if (!(jobj = json_contains(jobj_config, "section", "Config", "json_size", json_type_string)) ||
7cdc99
-	    !json_str_to_uint64(jobj, &json_size))
7cdc99
+	    !json_str_to_uint64(jobj, &metadata_size))
7cdc99
 		return 1;
7cdc99
 
7cdc99
+	/* single metadata instance is assembled from json area size plus
7cdc99
+	 * binary header size */
7cdc99
+	metadata_size += LUKS2_HDR_BIN_LEN;
7cdc99
+
7cdc99
 	if (!(jobj = json_contains(jobj_config, "section", "Config", "keyslots_size", json_type_string)) ||
7cdc99
 	    !json_str_to_uint64(jobj, &keyslots_size))
7cdc99
 		return 1;
7cdc99
 
7cdc99
-	if (LUKS2_check_metadata_area_size(json_size + LUKS2_HDR_BIN_LEN)) {
7cdc99
-		log_dbg("Unsupported LUKS2 header size (%" PRIu64 ").", json_size + LUKS2_HDR_BIN_LEN);
7cdc99
+	if (LUKS2_check_metadata_area_size(metadata_size)) {
7cdc99
+		log_dbg("Unsupported LUKS2 header size (%" PRIu64 ").", metadata_size);
7cdc99
 		return 1;
7cdc99
 	}
7cdc99
 
7cdc99
@@ -802,8 +784,19 @@ static int hdr_validate_config(json_obje
7cdc99
 		return 1;
7cdc99
 	}
7cdc99
 
7cdc99
-	if (validate_keyslots_size(hdr_jobj, json_size + LUKS2_HDR_BIN_LEN, keyslots_size))
7cdc99
-		return 1;
7cdc99
+	/*
7cdc99
+	 * validate keyslots_size fits in between (2 * metadata_size) and first
7cdc99
+	 * segment_offset (except detached header)
7cdc99
+	 */
7cdc99
+	json_object_object_get_ex(hdr_jobj, "segments", &jobj);
7cdc99
+	segment_offset = get_first_data_offset(jobj, "crypt");
7cdc99
+	if (segment_offset &&
7cdc99
+	    (segment_offset < keyslots_size ||
7cdc99
+	     (segment_offset - keyslots_size) < (2 * metadata_size))) {
7cdc99
+		log_dbg("keyslots_size is too large %" PRIu64 " (bytes). Data offset: %" PRIu64
7cdc99
+			", keyslots offset: %" PRIu64, keyslots_size, segment_offset, 2 * metadata_size);
7cdc99
+ 		return 1;
7cdc99
+	}
7cdc99
 
7cdc99
 	/* Flags array is optional */
7cdc99
 	if (json_object_object_get_ex(jobj_config, "flags", &jobj)) {
7cdc99
@@ -845,8 +838,8 @@ int LUKS2_hdr_validate(json_object *hdr_
7cdc99
 		{ hdr_validate_digests  },
7cdc99
 		{ hdr_validate_segments },
7cdc99
 		{ hdr_validate_keyslots },
7cdc99
-		{ hdr_validate_areas    },
7cdc99
 		{ hdr_validate_config   },
7cdc99
+		{ hdr_validate_areas    },
7cdc99
 		{ NULL }
7cdc99
 	};
7cdc99
 	int i;