CVE-2022-0476: Uncontrolled Resource Consumption (CWE-400)
value: Denial of Service in GitHub repository radareorg/radare2 prior to 5.6.4.
CWE description: The product does not properly control the allocation and maintenance of a limited resource, thereby enabling an actor to influence the amount of resources consumed, eventually leading to the exhaustion of available resources.
CVSS v3 base score: 5.5
Published: 2022-02-23T17:15Z
Repository: https://github.com/radareorg/radare2
Language: C
Files changed: libr/bin/format/mdmp/mdmp.c
Commit date: 2022-02-21 18:32:36 +0100
Commit message: Fix DoS in the minidump parser ##crash

* Reported by lazymio via huntr.dev
* Reproducer: mdmp-dos

Diff: diff --git a/libr/bin/format/mdmp/mdmp.c b/libr/bin/format/mdmp/mdmp.c
index ec802d5a7ac..4cfe6015dff 100644
--- a/libr/bin/format/mdmp/mdmp.c
+++ b/libr/bin/format/mdmp/mdmp.c
@@ -367,13 +367,19 @@ static bool r_bin_mdmp_init_hdr(struct r_bin_mdmp_obj *obj) {
 		"TimeDateStamp (mdmp_type)Flags", 0);
 
 	return true;
 }
 
-static void read_module(RBuffer *b, ut64 addr, struct minidump_module *module) {
+static struct minidump_module *read_module(RBuffer *b, ut64 addr) {
 	st64 o_addr = r_buf_seek (b, 0, R_BUF_CUR);
-	r_buf_seek (b, addr, R_BUF_SET);
+	if (r_buf_seek (b, addr, R_BUF_SET) == -1) {
+		return NULL;
+	}
+	struct minidump_module *module = R_NEW0 (struct minidump_module);
+	if (!module) {
+		return NULL;
+	}
 	module->base_of_image = r_buf_read_le64 (b);
 	module->size_of_image = r_buf_read_le32 (b);
 	module->check_sum = r_buf_read_le32 (b);
 	module->time_date_stamp = r_buf_read_le32 (b);
 	module->module_name_rva = r_buf_read_le32 (b);
@@ -395,10 +401,11 @@ static void read_module(RBuffer *b, ut64 addr, struct minidump_module *module) {
 	module->misc_record.data_size = r_buf_read_le32 (b);
 	module->misc_record.rva = r_buf_read_le32 (b);
 	module->reserved_0 = r_buf_read_le64 (b);
 	module->reserved_1 = r_buf_read_le64 (b);
 	r_buf_seek (b, o_addr, R_BUF_SET);
+	return module;
 }
 
 static void read_memory64_list(RBuffer *b, ut64 addr, struct minidump_memory64_list *memory64_list) {
 	st64 o_addr = r_buf_seek (b, 0, R_BUF_CUR);
 	r_buf_seek (b, addr, R_BUF_SET);
@@ -475,16 +482,15 @@ static bool r_bin_mdmp_init_directory_entry(struct r_bin_mdmp_obj *obj, struct m
 				"NumberOfModule (mdmp_module)Modules",
 				module_list.number_of_modules),
 			0);
 
 		offset = entry->location.rva + sizeof (module_list);
-		for (i = 0; i < module_list.number_of_modules; i++) {
-			struct minidump_module *module = R_NEW (struct minidump_module);
+		for (i = 0; i < module_list.number_of_modules && offset < obj->size; i++) {
+			struct minidump_module *module = read_module (obj->b, offset);
 			if (!module) {
-				break;
+				break;	
 			}
-			read_module (obj->b, offset, module);
 			r_list_append (obj->streams.modules, module);
 			offset += sizeof (*module);
 		}
 		break;
 	case MEMORY_LIST_STREAM:
@@ -501,11 +507,11 @@ static bool r_bin_mdmp_init_directory_entry(struct r_bin_mdmp_obj *obj, struct m
 				"(mdmp_memory_descriptor)MemoryRanges ",
 				memory_list.number_of_memory_ranges),
 			0);
 
 		offset = entry->location.rva + sizeof (memory_list);
-		for (i = 0; i < memory_list.number_of_memory_ranges; i++) {
+		for (i = 0; i < memory_list.number_of_memory_ranges && offset < obj->size; i++) {
 			struct minidump_memory_descriptor *desc = R_NEW (struct minidump_memory_descriptor);
 			if (!desc) {
 				break;
 			}
 			r = r_buf_read_at (obj->b, offset, (ut8 *)desc, sizeof (*desc));
@@ -584,11 +590,11 @@ static bool r_bin_mdmp_init_directory_entry(struct r_bin_mdmp_obj *obj, struct m
 				"(mdmp_thread_ex)Threads",
 				thread_ex_list.number_of_threads),
 			0);
 
 		offset = entry->location.rva + sizeof (thread_ex_list);
-		for (i = 0; i < thread_ex_list.number_of_threads; i++) {
+		for (i = 0; i < thread_ex_list.number_of_threads && offset < obj->size; i++) {
 			struct minidump_thread_ex *thread = R_NEW (struct minidump_thread_ex);
 			if (!thread) {
 				break;
 			}
 			r = r_buf_read_at (obj->b, offset, (ut8 *)thread, sizeof (*thread));
@@ -611,11 +617,11 @@ static bool r_bin_mdmp_init_directory_entry(struct r_bin_mdmp_obj *obj, struct m
 				memory64_list.number_of_memory_ranges),
 			0);
 
 		obj->streams.memories64.base_rva = memory64_list.base_rva;
 		offset = entry->location.rva + sizeof (memory64_list);
-		for (i = 0; i < memory64_list.number_of_memory_ranges; i++) {
+		for (i = 0; i < memory64_list.number_of_memory_ranges && offset < obj->size; i++) {
 			struct minidump_memory_descriptor64 *desc = R_NEW (struct minidump_memory_descriptor64);
 			if (!desc) {
 				break;
 			}
 			read_desc (obj->b, offset, desc);
@@ -706,11 +712,11 @@ static bool r_bin_mdmp_init_directory_entry(struct r_bin_mdmp_obj *obj, struct m
 			entry->location.rva, 0);
 		sdb_set (obj->kv, "mdmp_unloaded_module_list.format", "ddd "
 			"SizeOfHeader SizeOfEntry NumberOfEntries", 0);
 
 		offset = entry->location.rva + sizeof (unloaded_module_list);
-		for (i = 0; i < unloaded_module_list.number_of_entries; i++) {
+		for (i = 0; i < unloaded_module_list.number_of_entries && offset < obj->size; i++) {
 			struct minidump_unloaded_module *module = R_NEW (struct minidump_unloaded_module);
 			if (!module) {
 				break;
 			}
 			r = r_buf_read_at (obj->b, offset, (ut8 *)module, sizeof (*module));
@@ -761,11 +767,11 @@ static bool r_bin_mdmp_init_directory_entry(struct r_bin_mdmp_obj *obj, struct m
 				"NumberOfEntries (mdmp_memory_info)MemoryInfo",
 				memory_info_list.number_of_entries),
 			0);
 
 		offset = entry->location.rva + sizeof (memory_info_list);
-		for (i = 0; i < memory_info_list.number_of_entries; i++) {
+		for (i = 0; i < memory_info_list.number_of_entries && offset < obj->size; i++) {
 			struct minidump_memory_info *info = R_NEW (struct minidump_memory_info);
 			if (!info) {
 				break;
 			}
 			r = r_buf_read_at (obj->b, offset, (ut8 *)info, sizeof (*info));
@@ -791,11 +797,11 @@ static bool r_bin_mdmp_init_directory_entry(struct r_bin_mdmp_obj *obj, struct m
 				entry->location.rva, 0);
 		sdb_set (obj->kv, "mdmp_thread_info_list.format", "ddd "
 			"SizeOfHeader SizeOfEntry NumberOfEntries", 0);
 
 		offset = entry->location.rva + sizeof (thread_info_list);
-		for (i = 0; i < thread_info_list.number_of_entries; i++) {
+		for (i = 0; i < thread_info_list.number_of_entries && offset < obj->size; i++) {
 			struct minidump_thread_info *info = R_NEW (struct minidump_thread_info);
 			if (!info) {
 				break;
 			}
 			r = r_buf_read_at (obj->b, offset, (ut8 *)info, sizeof (*info));
@@ -817,11 +823,11 @@ static bool r_bin_mdmp_init_directory_entry(struct r_bin_mdmp_obj *obj, struct m
 			entry->location.rva, 0);
 		sdb_set (obj->kv, "mdmp_handle_operation_list.format", "dddd "
 			"SizeOfHeader SizeOfEntry NumberOfEntries Reserved", 0);
 
 		offset = entry->location.rva + sizeof (handle_operation_list);
-		for (i = 0; i < handle_operation_list.number_of_entries; i++) {
+		for (i = 0; i < handle_operation_list.number_of_entries && offset < obj->size; i++) {
 			struct avrf_handle_operation *op = R_NEW (struct avrf_handle_operation);
 			if (!op) {
 				break;
 			}
 			r = r_buf_read_at (obj->b, offset, (ut8 *)op, sizeof (*op));
@@ -847,11 +853,11 @@ static bool r_bin_mdmp_init_directory_entry(struct r_bin_mdmp_obj *obj, struct m
 			entry->location.rva, 0);
 		sdb_set (obj->kv, "mdmp_token_info_list.format", "dddd "
 			"TokenListSize TokenListEntries ListHeaderSize ElementHeaderSize", 0);
 
 		offset = entry->location.rva + sizeof (token_info_list);
-		for (i = 0; i < token_info_list.number_of_entries; i++) {
+		for (i = 0; i < token_info_list.number_of_entries && offset < obj->size; i++) {
 			struct minidump_token_info *info = R_NEW (struct minidump_token_info);
 			if (!info) {
 				break;
 			}
 			r = r_buf_read_at (obj->b, offset, (ut8 *)info, sizeof (*info));

Vulnerable code: static void read_module(RBuffer *b, ut64 addr, struct minidump_module *module) {
	r_buf_seek (b, addr, R_BUF_SET);
		for (i = 0; i < module_list.number_of_modules; i++) {
			struct minidump_module *module = R_NEW (struct minidump_module);
				break;
			read_module (obj->b, offset, module);
		for (i = 0; i < memory_list.number_of_memory_ranges; i++) {
		for (i = 0; i < thread_ex_list.number_of_threads; i++) {
		for (i = 0; i < memory64_list.number_of_memory_ranges; i++) {
		for (i = 0; i < unloaded_module_list.number_of_entries; i++) {
		for (i = 0; i < memory_info_list.number_of_entries; i++) {
		for (i = 0; i < thread_info_list.number_of_entries; i++) {
		for (i = 0; i < handle_operation_list.number_of_entries; i++) {
		for (i = 0; i < token_info_list.number_of_entries; i++) {
Fixed code: static struct minidump_module *read_module(RBuffer *b, ut64 addr) {
	if (r_buf_seek (b, addr, R_BUF_SET) == -1) {
		return NULL;
	}
	struct minidump_module *module = R_NEW0 (struct minidump_module);
	if (!module) {
		return NULL;
	}
	return module;
		for (i = 0; i < module_list.number_of_modules && offset < obj->size; i++) {
			struct minidump_module *module = read_module (obj->b, offset);
				break;	
		for (i = 0; i < memory_list.number_of_memory_ranges && offset < obj->size; i++) {
		for (i = 0; i < thread_ex_list.number_of_threads && offset < obj->size; i++) {
		for (i = 0; i < memory64_list.number_of_memory_ranges && offset < obj->size; i++) {
		for (i = 0; i < unloaded_module_list.number_of_entries && offset < obj->size; i++) {
		for (i = 0; i < memory_info_list.number_of_entries && offset < obj->size; i++) {
		for (i = 0; i < thread_info_list.number_of_entries && offset < obj->size; i++) {
		for (i = 0; i < handle_operation_list.number_of_entries && offset < obj->size; i++) {
		for (i = 0; i < token_info_list.number_of_entries && offset < obj->size; i++) {