Fix range check bugs

This is a patch hunting for fuzzing failures and adding
appropriate range checks.


Change-Id: Ieae02b7e461b9a6c5e25de6c663a768f7a0d5e10
Signed-off-by: Ed Tanous <etanous@nvidia.com>
diff --git a/sections/cper-section-ia32x64.c b/sections/cper-section-ia32x64.c
index f217612..bf7f565 100644
--- a/sections/cper-section-ia32x64.c
+++ b/sections/cper-section-ia32x64.c
@@ -21,7 +21,8 @@
 cper_ia32x64_bus_check_to_ir(EFI_IA32_X64_BUS_CHECK_INFO *bus_check);
 json_object *cper_ia32x64_ms_check_to_ir(EFI_IA32_X64_MS_CHECK_INFO *ms_check);
 json_object *cper_ia32x64_processor_context_info_to_ir(
-	EFI_IA32_X64_PROCESSOR_CONTEXT_INFO *context_info, void **cur_pos);
+	EFI_IA32_X64_PROCESSOR_CONTEXT_INFO *context_info, void **cur_pos,
+	UINT32 *remaining_size);
 json_object *
 cper_ia32x64_register_32bit_to_ir(EFI_CONTEXT_IA32_REGISTER_STATE *registers);
 json_object *
@@ -43,10 +44,15 @@
 //////////////////
 
 //Converts the IA32/x64 error section described in the given descriptor into intermediate format.
-json_object *cper_section_ia32x64_to_ir(const void *section)
+json_object *cper_section_ia32x64_to_ir(const UINT8 *section, UINT32 size)
 {
+	if (size < sizeof(EFI_IA32_X64_PROCESSOR_ERROR_RECORD)) {
+		return NULL;
+	}
 	EFI_IA32_X64_PROCESSOR_ERROR_RECORD *record =
 		(EFI_IA32_X64_PROCESSOR_ERROR_RECORD *)section;
+	UINT32 remaining_size =
+		size - sizeof(EFI_IA32_X64_PROCESSOR_ERROR_RECORD);
 	json_object *record_ir = json_object_new_object();
 
 	//Validation bits.
@@ -89,16 +95,34 @@
 	EFI_IA32_X64_PROCESS_ERROR_INFO *current_error_info =
 		(EFI_IA32_X64_PROCESS_ERROR_INFO *)(record + 1);
 	json_object *error_info_array = json_object_new_array();
+	if (remaining_size < (processor_error_info_num *
+			      sizeof(EFI_IA32_X64_PROCESS_ERROR_INFO))) {
+		json_object_put(error_info_array);
+		json_object_put(record_ir);
+		printf("Invalid CPER file: Invalid processor error info num.\n");
+		return NULL;
+	}
+
 	for (int i = 0; i < processor_error_info_num; i++) {
 		json_object_array_add(error_info_array,
 				      cper_ia32x64_processor_error_info_to_ir(
 					      current_error_info));
 		current_error_info++;
 	}
+	remaining_size -= processor_error_info_num *
+			  sizeof(EFI_IA32_X64_PROCESS_ERROR_INFO);
+
 	json_object_object_add(record_ir, "processorErrorInfo",
 			       error_info_array);
 
 	//Processor context information, of the amount described above.
+	if (remaining_size < (processor_context_info_num *
+			      sizeof(EFI_IA32_X64_PROCESSOR_CONTEXT_INFO))) {
+		json_object_put(error_info_array);
+		json_object_put(record_ir);
+		printf("Invalid CPER file: Invalid processor context info num.\n");
+		return NULL;
+	}
 	EFI_IA32_X64_PROCESSOR_CONTEXT_INFO *current_context_info =
 		(EFI_IA32_X64_PROCESSOR_CONTEXT_INFO *)current_error_info;
 	void *cur_pos = (void *)current_context_info;
@@ -106,11 +130,14 @@
 	for (int i = 0; i < processor_context_info_num; i++) {
 		json_object_array_add(context_info_array,
 				      cper_ia32x64_processor_context_info_to_ir(
-					      current_context_info, &cur_pos));
+					      current_context_info, &cur_pos,
+					      &remaining_size));
 		current_context_info =
 			(EFI_IA32_X64_PROCESSOR_CONTEXT_INFO *)cur_pos;
+
 		//The context array is a non-fixed size, pointer is shifted within the above function.
 	}
+
 	json_object_object_add(record_ir, "processorContextInfo",
 			       context_info_array);
 
@@ -424,13 +451,18 @@
 
 //Converts a single IA32/x64 processor context info entry into JSON IR format.
 json_object *cper_ia32x64_processor_context_info_to_ir(
-	EFI_IA32_X64_PROCESSOR_CONTEXT_INFO *context_info, void **cur_pos)
+	EFI_IA32_X64_PROCESSOR_CONTEXT_INFO *context_info, void **cur_pos,
+	UINT32 *remaining_size)
 {
+	if (*remaining_size < sizeof(EFI_IA32_X64_PROCESSOR_CONTEXT_INFO)) {
+		return NULL;
+	}
+	*remaining_size -= sizeof(EFI_IA32_X64_PROCESSOR_CONTEXT_INFO);
 	json_object *context_info_ir = json_object_new_object();
 
 	//Register context type.
 	json_object *context_type = integer_to_readable_pair(
-		context_info->RegisterType, 8,
+		context_info->RegisterType, IA32X64_REGISTER_CONTEXT_TYPES_SIZE,
 		IA32X64_REGISTER_CONTEXT_TYPES_KEYS,
 		IA32X64_REGISTER_CONTEXT_TYPES_VALUES, "Unknown (Reserved)");
 	json_object_object_add(context_info_ir, "registerContextType",
@@ -449,21 +481,34 @@
 	//Register array.
 	json_object *register_array = NULL;
 	if (context_info->RegisterType == EFI_REG_CONTEXT_TYPE_IA32) {
+		if (*remaining_size < sizeof(EFI_CONTEXT_IA32_REGISTER_STATE)) {
+			json_object_put(context_info_ir);
+			return NULL;
+		}
 		EFI_CONTEXT_IA32_REGISTER_STATE *register_state =
 			(EFI_CONTEXT_IA32_REGISTER_STATE *)(context_info + 1);
 		register_array =
 			cper_ia32x64_register_32bit_to_ir(register_state);
 		*cur_pos = (void *)(register_state + 1);
+		*remaining_size -= sizeof(EFI_CONTEXT_IA32_REGISTER_STATE);
 	} else if (context_info->RegisterType == EFI_REG_CONTEXT_TYPE_X64) {
+		if (*remaining_size < sizeof(EFI_CONTEXT_X64_REGISTER_STATE)) {
+			json_object_put(context_info_ir);
+			return NULL;
+		}
 		EFI_CONTEXT_X64_REGISTER_STATE *register_state =
 			(EFI_CONTEXT_X64_REGISTER_STATE *)(context_info + 1);
 		register_array =
 			cper_ia32x64_register_64bit_to_ir(register_state);
 		*cur_pos = (void *)(register_state + 1);
+		*remaining_size -= sizeof(EFI_CONTEXT_X64_REGISTER_STATE);
 	} else {
 		//No parseable data, just dump as base64 and shift the head to the next item.
 		*cur_pos = (void *)(context_info + 1);
-
+		if (*remaining_size < context_info->ArraySize) {
+			json_object_put(context_info_ir);
+			return NULL;
+		}
 		int32_t encoded_len = 0;
 		char *encoded = base64_encode((UINT8 *)*cur_pos,
 					      context_info->ArraySize,
@@ -480,6 +525,7 @@
 
 		*cur_pos =
 			(void *)(((char *)*cur_pos) + context_info->ArraySize);
+		*remaining_size -= context_info->ArraySize;
 	}
 	json_object_object_add(context_info_ir, "registerArray",
 			       register_array);