Blame SOURCES/cryptsetup-2.0.6-LUKS2-metadata-variation-fixes.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-04-03 18:55:44.392182454 +0200
7cdc99
+++ cryptsetup-2.0.3/lib/luks2/luks2_json_metadata.c	2019-04-03 18:56:22.567106063 +0200
7cdc99
@@ -429,6 +429,7 @@ int LUKS2_token_validate(json_object *hd
7cdc99
 {
7cdc99
 	json_object *jarr, *jobj_keyslots;
7cdc99
 
7cdc99
+	/* keyslots are not yet validated, but we need to know token doesn't reference missing keyslot */
7cdc99
 	if (!json_object_object_get_ex(hdr_jobj, "keyslots", &jobj_keyslots))
7cdc99
 		return 1;
7cdc99
 
7cdc99
@@ -505,12 +506,57 @@ static int hdr_validate_tokens(json_obje
7cdc99
 	return 0;
7cdc99
 }
7cdc99
 
7cdc99
-static int hdr_validate_segments(json_object *hdr_jobj)
7cdc99
+static int hdr_validate_crypt_segment(json_object *jobj, const char *key, json_object *jobj_digests,
7cdc99
+	uint64_t offset, uint64_t size)
7cdc99
 {
7cdc99
-	json_object *jobj, *jobj_digests, *jobj_offset, *jobj_ivoffset,
7cdc99
-		    *jobj_length, *jobj_sector_size, *jobj_type, *jobj_integrity;
7cdc99
+	json_object *jobj_ivoffset, *jobj_sector_size, *jobj_integrity;
7cdc99
 	uint32_t sector_size;
7cdc99
-	uint64_t ivoffset, offset, length;
7cdc99
+	uint64_t ivoffset;
7cdc99
+
7cdc99
+	if (!(jobj_ivoffset = json_contains(jobj, key, "Segment", "iv_tweak", json_type_string)) ||
7cdc99
+	    !json_contains(jobj, key, "Segment", "encryption", json_type_string) ||
7cdc99
+	    !(jobj_sector_size = json_contains(jobj, key, "Segment", "sector_size", json_type_int)))
7cdc99
+		return 1;
7cdc99
+
7cdc99
+	/* integrity */
7cdc99
+	if (json_object_object_get_ex(jobj, "integrity", &jobj_integrity)) {
7cdc99
+		if (!json_contains(jobj, key, "Segment", "integrity", json_type_object) ||
7cdc99
+		    !json_contains(jobj_integrity, key, "Segment integrity", "type", json_type_string) ||
7cdc99
+		    !json_contains(jobj_integrity, key, "Segment integrity", "journal_encryption", json_type_string) ||
7cdc99
+		    !json_contains(jobj_integrity, key, "Segment integrity", "journal_integrity", json_type_string))
7cdc99
+			return 1;
7cdc99
+	}
7cdc99
+
7cdc99
+	/* enforce uint32_t type */
7cdc99
+	if (!validate_json_uint32(jobj_sector_size)) {
7cdc99
+		log_dbg("Illegal field \"sector_size\":%s.",
7cdc99
+			json_object_get_string(jobj_sector_size));
7cdc99
+		return 1;
7cdc99
+	}
7cdc99
+
7cdc99
+	sector_size = json_object_get_uint32(jobj_sector_size);
7cdc99
+	if (!sector_size || sector_size % SECTOR_SIZE) {
7cdc99
+		log_dbg("Illegal sector size: %" PRIu32, sector_size);
7cdc99
+		return 1;
7cdc99
+	}
7cdc99
+
7cdc99
+	if (!numbered("iv_tweak", json_object_get_string(jobj_ivoffset)) ||
7cdc99
+	    !json_str_to_uint64(jobj_ivoffset, &ivoffset))
7cdc99
+		return 1;
7cdc99
+
7cdc99
+	if (size % sector_size) {
7cdc99
+		log_dbg("Size field has to be aligned to sector size: %" PRIu32, sector_size);
7cdc99
+		return 1;
7cdc99
+	}
7cdc99
+
7cdc99
+	return !segment_has_digest(key, jobj_digests);
7cdc99
+}
7cdc99
+
7cdc99
+static int hdr_validate_segments(json_object *hdr_jobj)
7cdc99
+{
7cdc99
+	json_object *jobj, *jobj_digests, *jobj_offset, *jobj_size, *jobj_type, *jobj_flags;
7cdc99
+	int i;
7cdc99
+	uint64_t offset, size;
7cdc99
 
7cdc99
 	if (!json_object_object_get_ex(hdr_jobj, "segments", &jobj)) {
7cdc99
 		log_dbg("Missing segments section.");
7cdc99
@@ -530,70 +576,46 @@ static int hdr_validate_segments(json_ob
7cdc99
 		if (!numbered("Segment", key))
7cdc99
 			return 1;
7cdc99
 
7cdc99
-		if (!json_contains(val, key, "Segment", "type", json_type_string) ||
7cdc99
+		/* those fields are mandatory for all segment types */
7cdc99
+		if (!(jobj_type =   json_contains(val, key, "Segment", "type",   json_type_string)) ||
7cdc99
 		    !(jobj_offset = json_contains(val, key, "Segment", "offset", json_type_string)) ||
7cdc99
-		    !(jobj_ivoffset = json_contains(val, key, "Segment", "iv_tweak", json_type_string)) ||
7cdc99
-		    !(jobj_length = json_contains(val, key, "Segment", "size", json_type_string)) ||
7cdc99
-		    !json_contains(val, key, "Segment", "encryption", json_type_string) ||
7cdc99
-		    !(jobj_sector_size = json_contains(val, key, "Segment", "sector_size", json_type_int)))
7cdc99
-			return 1;
7cdc99
-
7cdc99
-		/* integrity */
7cdc99
-		if (json_object_object_get_ex(val, "integrity", &jobj_integrity)) {
7cdc99
-			if (!json_contains(val, key, "Segment", "integrity", json_type_object) ||
7cdc99
-			    !json_contains(jobj_integrity, key, "Segment integrity", "type", json_type_string) ||
7cdc99
-			    !json_contains(jobj_integrity, key, "Segment integrity", "journal_encryption", json_type_string) ||
7cdc99
-			    !json_contains(jobj_integrity, key, "Segment integrity", "journal_integrity", json_type_string))
7cdc99
-				return 1;
7cdc99
-		}
7cdc99
-
7cdc99
-		/* enforce uint32_t type */
7cdc99
-		if (!validate_json_uint32(jobj_sector_size)) {
7cdc99
-			log_dbg("Illegal field \"sector_size\":%s.",
7cdc99
-				json_object_get_string(jobj_sector_size));
7cdc99
-			return 1;
7cdc99
-		}
7cdc99
-
7cdc99
-		sector_size = json_object_get_uint32(jobj_sector_size);
7cdc99
-		if (!sector_size || sector_size % 512) {
7cdc99
-			log_dbg("Illegal sector size: %" PRIu32, sector_size);
7cdc99
+		    !(jobj_size =   json_contains(val, key, "Segment", "size",   json_type_string)))
7cdc99
 			return 1;
7cdc99
-		}
7cdc99
 
7cdc99
 		if (!numbered("offset", json_object_get_string(jobj_offset)) ||
7cdc99
-		    !numbered("iv_tweak", json_object_get_string(jobj_ivoffset)))
7cdc99
+		    !json_str_to_uint64(jobj_offset, &offset))
7cdc99
 			return 1;
7cdc99
 
7cdc99
-		/* rule out values > UINT64_MAX */
7cdc99
-		if (!json_str_to_uint64(jobj_offset, &offset) ||
7cdc99
-		    !json_str_to_uint64(jobj_ivoffset, &ivoffset))
7cdc99
-			return 1;
7cdc99
+		/* size "dynamic" means whole device starting at 'offset' */
7cdc99
+		if (strcmp(json_object_get_string(jobj_size), "dynamic")) {
7cdc99
+			if (!numbered("size", json_object_get_string(jobj_size)) ||
7cdc99
+			    !json_str_to_uint64(jobj_size, &size) || !size)
7cdc99
+				return 1;
7cdc99
+		} else
7cdc99
+			size = 0;
7cdc99
 
7cdc99
-		if (offset % sector_size) {
7cdc99
-			log_dbg("Offset field has to be aligned to sector size: %" PRIu32, sector_size);
7cdc99
+		/* all device-mapper devices are aligned to 512 sector size */
7cdc99
+		if (offset % SECTOR_SIZE) {
7cdc99
+			log_dbg("Offset field has to be aligned to sector size: %" PRIu32, SECTOR_SIZE);
7cdc99
 			return 1;
7cdc99
 		}
7cdc99
-
7cdc99
-		if (ivoffset % sector_size) {
7cdc99
-			log_dbg("IV offset field has to be aligned to sector size: %" PRIu32, sector_size);
7cdc99
+		if (size % SECTOR_SIZE) {
7cdc99
+			log_dbg("Size field has to be aligned to sector size: %" PRIu32, SECTOR_SIZE);
7cdc99
 			return 1;
7cdc99
 		}
7cdc99
 
7cdc99
-		/* length "dynamic" means whole device starting at 'offset' */
7cdc99
-		if (strcmp(json_object_get_string(jobj_length), "dynamic")) {
7cdc99
-			if (!numbered("size", json_object_get_string(jobj_length)) ||
7cdc99
-			    !json_str_to_uint64(jobj_length, &length))
7cdc99
+		/* flags array is optional and must contain strings */
7cdc99
+		if (json_object_object_get_ex(val, "flags", NULL)) {
7cdc99
+			if (!(jobj_flags = json_contains(val, key, "Segment", "flags", json_type_array)))
7cdc99
 				return 1;
7cdc99
-
7cdc99
-			if (length % sector_size) {
7cdc99
-				log_dbg("Length field has to be aligned to sector size: %" PRIu32, sector_size);
7cdc99
-				return 1;
7cdc99
-			}
7cdc99
+			for (i = 0; i < (int) json_object_array_length(jobj_flags); i++)
7cdc99
+				if (!json_object_is_type(json_object_array_get_idx(jobj_flags, i), json_type_string))
7cdc99
+					return 1;
7cdc99
 		}
7cdc99
 
7cdc99
-		json_object_object_get_ex(val, "type", &jobj_type);
7cdc99
+		/* crypt */
7cdc99
 		if (!strcmp(json_object_get_string(jobj_type), "crypt") &&
7cdc99
-		    !segment_has_digest(key, jobj_digests))
7cdc99
+		    hdr_validate_crypt_segment(val, key, jobj_digests, offset, size))
7cdc99
 			return 1;
7cdc99
 	}
7cdc99
 
7cdc99
@@ -610,6 +632,7 @@ static int hdr_validate_areas(json_objec
7cdc99
 	if (!json_object_object_get_ex(hdr_jobj, "keyslots", &jobj_keyslots))
7cdc99
 		return 1;
7cdc99
 
7cdc99
+	/* segments are already validated */
7cdc99
 	if (!json_object_object_get_ex(hdr_jobj, "segments", &jobj_segments))
7cdc99
 		return 1;
7cdc99
 
7cdc99
@@ -674,11 +697,11 @@ static int hdr_validate_digests(json_obj
7cdc99
 		return 1;
7cdc99
 	}
7cdc99
 
7cdc99
-	/* keyslots should already be validated */
7cdc99
+	/* keyslots are not yet validated, but we need to know digest doesn't reference missing keyslot */
7cdc99
 	if (!json_object_object_get_ex(hdr_jobj, "keyslots", &jobj_keyslots))
7cdc99
 		return 1;
7cdc99
 
7cdc99
-	/* segments are not validated atm, but we need to know digest doesn't reference missing segment */
7cdc99
+	/* segments are not yet validated, but we need to know digest doesn't reference missing segment */
7cdc99
 	if (!json_object_object_get_ex(hdr_jobj, "segments", &jobj_segments))
7cdc99
 		return 1;
7cdc99
 
7cdc99
@@ -813,10 +836,10 @@ int LUKS2_hdr_validate(json_object *hdr_
7cdc99
 	struct {
7cdc99
 		int (*validate)(json_object *);
7cdc99
 	} checks[] = {
7cdc99
-		{ hdr_validate_keyslots },
7cdc99
 		{ hdr_validate_tokens   },
7cdc99
 		{ hdr_validate_digests  },
7cdc99
 		{ hdr_validate_segments },
7cdc99
+		{ hdr_validate_keyslots },
7cdc99
 		{ hdr_validate_areas    },
7cdc99
 		{ hdr_validate_config   },
7cdc99
 		{ NULL }