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