More range checks
This is a second patch adding more range checks where appropriate.
Change-Id: Ie169efe8924153c9cc11e4472a1b07b8d04efb3b
Signed-off-by: Ed Tanous <ed@tanous.net>
diff --git a/cper-utils.c b/cper-utils.c
index 6c76156..11fdbcb 100644
--- a/cper-utils.c
+++ b/cper-utils.c
@@ -425,3 +425,24 @@
return 1;
}
+
+void add_untrusted_string(json_object *ir, const char *field_name,
+ const char *str, int len)
+{
+ int fru_text_len = 0;
+ for (; fru_text_len < len; fru_text_len++) {
+ char c = str[fru_text_len];
+ if (c < 0) {
+ fru_text_len = -1;
+ break;
+ }
+ if (c == '\0') {
+ break;
+ }
+ }
+ if (fru_text_len >= 0) {
+ json_object_object_add(
+ ir, field_name,
+ json_object_new_string_len(str, fru_text_len));
+ }
+}
diff --git a/include/libcper/cper-utils.h b/include/libcper/cper-utils.h
index 50ea3ad..1003c38 100644
--- a/include/libcper/cper-utils.h
+++ b/include/libcper/cper-utils.h
@@ -61,6 +61,9 @@
void string_to_guid(EFI_GUID *out, const char *guid);
int guid_equal(EFI_GUID *a, EFI_GUID *b);
+void add_untrusted_string(json_object *ir, const char *field_name,
+ const char *str, int len);
+
//The available severity types for CPER.
extern const char *CPER_SEVERITY_TYPES[4];
diff --git a/include/libcper/sections/cper-section-arm.h b/include/libcper/sections/cper-section-arm.h
index 5433f80..c0af80f 100644
--- a/include/libcper/sections/cper-section-arm.h
+++ b/include/libcper/sections/cper-section-arm.h
@@ -77,7 +77,6 @@
"Device Memory Access" }
#define ARM_PROCESSOR_INFO_REGISTER_CONTEXT_TYPES_KEYS \
(int[]){ 0, 1, 2, 3, 4, 5, 6, 7, 8 }
-#define ARM_BUS_ADDRESS_SPACE_TYPES_COUNT 9
#define ARM_PROCESSOR_INFO_REGISTER_CONTEXT_TYPES_VALUES \
(const char *[]){ "AArch32 General Purpose Registers", \
@@ -89,6 +88,9 @@
"AArch64 EL2 Context Registers", \
"AArch64 EL3 Context Registers", \
"Miscellaneous System Register Structure" }
+
+#define ARM_PROCESSOR_INFO_REGISTER_CONTEXT_TYPES_COUNT 9
+
#define ARM_AARCH32_GPR_NAMES \
(const char *[]){ "r0", "r1", "r2", "r3", "r4", "r5", \
"r6", "r7", "r8", "r9", "r10", "r11", \
diff --git a/sections/cper-section-arm.c b/sections/cper-section-arm.c
index 6aa0b87..cd06131 100644
--- a/sections/cper-section-arm.c
+++ b/sections/cper-section-arm.c
@@ -18,7 +18,7 @@
cper_arm_error_info_to_ir(EFI_ARM_ERROR_INFORMATION_ENTRY *error_info);
json_object *
cper_arm_processor_context_to_ir(EFI_ARM_CONTEXT_INFORMATION_HEADER *header,
- void **cur_pos);
+ const UINT8 **cur_pos, UINT32 *remaining_size);
json_object *
cper_arm_cache_tlb_error_to_ir(EFI_ARM_CACHE_ERROR_STRUCTURE *cache_tlb_error,
EFI_ARM_ERROR_INFORMATION_ENTRY *error_info);
@@ -46,10 +46,15 @@
//Converts the given processor-generic CPER section into JSON IR.
json_object *cper_section_arm_to_ir(const UINT8 *section, UINT32 size)
{
- if (size < sizeof(EFI_ARM_ERROR_RECORD)) {
+ const UINT8 *cur_pos = section;
+ UINT32 remaining_size = size;
+
+ if (remaining_size < sizeof(EFI_ARM_ERROR_RECORD)) {
return NULL;
}
- EFI_ARM_ERROR_RECORD *record = (EFI_ARM_ERROR_RECORD *)section;
+ EFI_ARM_ERROR_RECORD *record = (EFI_ARM_ERROR_RECORD *)cur_pos;
+ cur_pos += sizeof(EFI_ARM_ERROR_RECORD);
+ remaining_size -= sizeof(EFI_ARM_ERROR_RECORD);
json_object *section_ir = json_object_new_object();
//Length of ValidationBits from spec
@@ -114,23 +119,51 @@
json_object *error_info_array = json_object_new_array();
EFI_ARM_ERROR_INFORMATION_ENTRY *cur_error =
(EFI_ARM_ERROR_INFORMATION_ENTRY *)(record + 1);
+ if (remaining_size <
+ (record->ErrInfoNum * sizeof(EFI_ARM_ERROR_INFORMATION_ENTRY))) {
+ json_object_put(error_info_array);
+ json_object_put(section_ir);
+ printf("Invalid CPER file: Invalid processor error info num.\n");
+ return NULL;
+ }
for (int i = 0; i < record->ErrInfoNum; i++) {
json_object_array_add(error_info_array,
cper_arm_error_info_to_ir(cur_error));
cur_error++;
}
+
+ cur_pos += (UINT32)(record->ErrInfoNum *
+ sizeof(EFI_ARM_ERROR_INFORMATION_ENTRY));
+ remaining_size -= (UINT32)(record->ErrInfoNum *
+ sizeof(EFI_ARM_ERROR_INFORMATION_ENTRY));
+
json_object_object_add(section_ir, "errorInfo", error_info_array);
//Processor context structures.
//The current position is moved within the processing, as it is a dynamic size structure.
- uint8_t *cur_pos = (uint8_t *)cur_error;
json_object *context_info_array = json_object_new_array();
for (int i = 0; i < record->ContextInfoNum; i++) {
+ if (remaining_size <
+ sizeof(EFI_ARM_CONTEXT_INFORMATION_HEADER)) {
+ json_object_put(context_info_array);
+ json_object_put(section_ir);
+ printf("Invalid CPER file: Invalid processor context info num.\n");
+ return NULL;
+ }
EFI_ARM_CONTEXT_INFORMATION_HEADER *header =
(EFI_ARM_CONTEXT_INFORMATION_HEADER *)cur_pos;
+
+ cur_pos += sizeof(EFI_ARM_CONTEXT_INFORMATION_HEADER);
+ remaining_size -= sizeof(EFI_ARM_CONTEXT_INFORMATION_HEADER);
json_object *processor_context =
- cper_arm_processor_context_to_ir(header,
- (void **)&cur_pos);
+ cper_arm_processor_context_to_ir(header, &cur_pos,
+ &remaining_size);
+ if (processor_context == NULL) {
+ json_object_put(context_info_array);
+ json_object_put(section_ir);
+ printf("Invalid CPER file: Invalid processor context info num.\n");
+ return NULL;
+ }
json_object_array_add(context_info_array, processor_context);
}
json_object_object_add(section_ir, "contextInfo", context_info_array);
@@ -141,10 +174,18 @@
json_object *vendor_specific = json_object_new_object();
size_t input_size = (uint8_t *)section +
record->SectionLength - cur_pos;
+ if (remaining_size < input_size) {
+ json_object_put(vendor_specific);
+ json_object_put(section_ir);
+ printf("Invalid CPER file: Invalid vendor-specific info length.\n");
+ return NULL;
+ }
int32_t encoded_len = 0;
char *encoded = base64_encode(cur_pos, input_size,
&encoded_len);
if (encoded == NULL) {
+ json_object_put(vendor_specific);
+ json_object_put(section_ir);
printf("base64 encode of vendorSpecificInfo failed\n");
return NULL;
}
@@ -453,8 +494,13 @@
//Converts a single ARM processor context block into JSON IR.
json_object *
cper_arm_processor_context_to_ir(EFI_ARM_CONTEXT_INFORMATION_HEADER *header,
- void **cur_pos)
+ const UINT8 **cur_pos, UINT32 *remaining_size)
{
+ if (header->RegisterArraySize > *remaining_size) {
+ printf("Invalid CPER file: Invalid processor context info num.\n");
+ return NULL;
+ }
+
json_object *context_ir = json_object_new_object();
//Version.
@@ -463,7 +509,8 @@
//Add the context type.
json_object *context_type = integer_to_readable_pair(
- header->RegisterContextType, 9,
+ header->RegisterContextType,
+ ARM_PROCESSOR_INFO_REGISTER_CONTEXT_TYPES_COUNT,
ARM_PROCESSOR_INFO_REGISTER_CONTEXT_TYPES_KEYS,
ARM_PROCESSOR_INFO_REGISTER_CONTEXT_TYPES_VALUES,
"Unknown (Reserved)");
@@ -475,16 +522,34 @@
json_object_new_uint64(header->RegisterArraySize));
//The register array itself.
- *cur_pos = (void *)(header + 1);
json_object *register_array = NULL;
switch (header->RegisterContextType) {
case EFI_ARM_CONTEXT_TYPE_AARCH32_GPR:
+ if (*remaining_size < sizeof(EFI_ARM_V8_AARCH32_GPR)) {
+ printf("Invalid CPER file: Invalid processor context info num.\n");
+ goto fail;
+ }
+ if (header->RegisterArraySize <
+ sizeof(EFI_ARM_V8_AARCH32_GPR)) {
+ printf("Invalid CPER file: Not enough bytes for aarch32 gpr\n");
+ goto fail;
+ }
register_array = uniform_struct_to_ir(
(UINT32 *)*cur_pos,
sizeof(EFI_ARM_V8_AARCH32_GPR) / sizeof(UINT32),
ARM_AARCH32_GPR_NAMES);
break;
case EFI_ARM_CONTEXT_TYPE_AARCH32_EL1:
+ if (*remaining_size <
+ sizeof(EFI_ARM_AARCH32_EL1_CONTEXT_REGISTERS)) {
+ printf("Invalid CPER file: Invalid processor context info num.\n");
+ goto fail;
+ }
+ if (header->RegisterArraySize <
+ sizeof(EFI_ARM_AARCH32_EL1_CONTEXT_REGISTERS)) {
+ printf("Invalid CPER file: Not enough bytes for aarch32 el1\n");
+ goto fail;
+ }
register_array = uniform_struct_to_ir(
(UINT32 *)*cur_pos,
sizeof(EFI_ARM_AARCH32_EL1_CONTEXT_REGISTERS) /
@@ -492,13 +557,35 @@
ARM_AARCH32_EL1_REGISTER_NAMES);
break;
case EFI_ARM_CONTEXT_TYPE_AARCH32_EL2:
+ if (*remaining_size <
+ sizeof(EFI_ARM_AARCH32_EL2_CONTEXT_REGISTERS)) {
+ printf("Invalid CPER file: Invalid processor context info num.\n");
+ goto fail;
+ }
+ if (header->RegisterArraySize <
+ sizeof(EFI_ARM_AARCH32_EL2_CONTEXT_REGISTERS)) {
+ printf("Invalid CPER file: Not enough bytes for aarch32 el2\n");
+ goto fail;
+ }
register_array = uniform_struct_to_ir(
(UINT32 *)*cur_pos,
sizeof(EFI_ARM_AARCH32_EL2_CONTEXT_REGISTERS) /
sizeof(UINT32),
ARM_AARCH32_EL2_REGISTER_NAMES);
+
break;
case EFI_ARM_CONTEXT_TYPE_AARCH32_SECURE:
+ if (*remaining_size <
+ sizeof(EFI_ARM_AARCH32_SECURE_CONTEXT_REGISTERS)) {
+ json_object_put(context_ir);
+ printf("Invalid CPER file: Invalid processor context info num.\n");
+ return NULL;
+ }
+ if (header->RegisterArraySize <
+ sizeof(EFI_ARM_AARCH32_SECURE_CONTEXT_REGISTERS)) {
+ printf("Invalid CPER file: Not enough bytes for aarch32 secure\n");
+ goto fail;
+ }
register_array = uniform_struct_to_ir(
(UINT32 *)*cur_pos,
sizeof(EFI_ARM_AARCH32_SECURE_CONTEXT_REGISTERS) /
@@ -506,12 +593,31 @@
ARM_AARCH32_SECURE_REGISTER_NAMES);
break;
case EFI_ARM_CONTEXT_TYPE_AARCH64_GPR:
+ if (*remaining_size < sizeof(EFI_ARM_V8_AARCH64_GPR)) {
+ printf("Invalid CPER file: Invalid processor context info num.\n");
+ goto fail;
+ }
+ if (header->RegisterArraySize <
+ sizeof(EFI_ARM_V8_AARCH64_GPR)) {
+ printf("Invalid CPER file: Not enough bytes for aarch64 gpr\n");
+ goto fail;
+ }
register_array = uniform_struct64_to_ir(
(UINT64 *)*cur_pos,
sizeof(EFI_ARM_V8_AARCH64_GPR) / sizeof(UINT64),
ARM_AARCH64_GPR_NAMES);
break;
case EFI_ARM_CONTEXT_TYPE_AARCH64_EL1:
+ if (*remaining_size <
+ sizeof(EFI_ARM_AARCH64_EL1_CONTEXT_REGISTERS)) {
+ printf("Invalid CPER file: Invalid processor context info num.\n");
+ goto fail;
+ }
+ if (header->RegisterArraySize <
+ sizeof(EFI_ARM_AARCH64_EL1_CONTEXT_REGISTERS)) {
+ printf("Invalid CPER file: Not enough bytes for aarch64 el1\n");
+ goto fail;
+ }
register_array = uniform_struct64_to_ir(
(UINT64 *)*cur_pos,
sizeof(EFI_ARM_AARCH64_EL1_CONTEXT_REGISTERS) /
@@ -519,6 +625,16 @@
ARM_AARCH64_EL1_REGISTER_NAMES);
break;
case EFI_ARM_CONTEXT_TYPE_AARCH64_EL2:
+ if (*remaining_size <
+ sizeof(EFI_ARM_AARCH64_EL2_CONTEXT_REGISTERS)) {
+ printf("Invalid CPER file: Invalid processor context info num.\n");
+ goto fail;
+ }
+ if (header->RegisterArraySize <
+ sizeof(EFI_ARM_AARCH64_EL2_CONTEXT_REGISTERS)) {
+ printf("Invalid CPER file: Not enough bytes for aarch64 el2\n");
+ goto fail;
+ }
register_array = uniform_struct64_to_ir(
(UINT64 *)*cur_pos,
sizeof(EFI_ARM_AARCH64_EL2_CONTEXT_REGISTERS) /
@@ -526,6 +642,16 @@
ARM_AARCH64_EL2_REGISTER_NAMES);
break;
case EFI_ARM_CONTEXT_TYPE_AARCH64_EL3:
+ if (*remaining_size <
+ sizeof(EFI_ARM_AARCH64_EL3_CONTEXT_REGISTERS)) {
+ printf("Invalid CPER file: Invalid processor context info num.\n");
+ goto fail;
+ }
+ if (header->RegisterArraySize <
+ sizeof(EFI_ARM_AARCH64_EL3_CONTEXT_REGISTERS)) {
+ printf("Invalid CPER file: Not enough bytes for aarch64 el3\n");
+ goto fail;
+ }
register_array = uniform_struct64_to_ir(
(UINT64 *)*cur_pos,
sizeof(EFI_ARM_AARCH64_EL3_CONTEXT_REGISTERS) /
@@ -533,20 +659,32 @@
ARM_AARCH64_EL3_REGISTER_NAMES);
break;
case EFI_ARM_CONTEXT_TYPE_MISC:
+ if (*remaining_size < sizeof(EFI_ARM_MISC_CONTEXT_REGISTER)) {
+ printf("Invalid CPER file: Invalid processor context info num.\n");
+ goto fail;
+ }
+ if (header->RegisterArraySize <
+ sizeof(EFI_ARM_MISC_CONTEXT_REGISTER)) {
+ printf("Invalid CPER file: Not enough bytes for misc\n");
+ goto fail;
+ }
register_array = cper_arm_misc_register_array_to_ir(
(EFI_ARM_MISC_CONTEXT_REGISTER *)*cur_pos);
break;
default:
+ if (*remaining_size < header->RegisterArraySize) {
+ printf("Invalid CPER file: Invalid processor context info num.\n");
+ goto fail;
+ }
//Unknown register array type, add as base64 data instead.
- register_array = json_object_new_object();
int32_t encoded_len = 0;
char *encoded = base64_encode((UINT8 *)*cur_pos,
header->RegisterArraySize,
&encoded_len);
if (encoded == NULL) {
- printf("Failed to allocate encode output buffer. \n");
- return NULL;
+ goto fail;
}
+ register_array = json_object_new_object();
json_object_object_add(register_array, "data",
json_object_new_string_len(encoded,
encoded_len));
@@ -558,8 +696,13 @@
//Set the current position to after the processor context structure.
*cur_pos = (UINT8 *)(*cur_pos) + header->RegisterArraySize;
+ *remaining_size -= header->RegisterArraySize;
return context_ir;
+
+fail:
+ json_object_put(context_ir);
+ return NULL;
}
//Converts a single CPER ARM miscellaneous register array to JSON IR format.
diff --git a/sections/cper-section-generic.c b/sections/cper-section-generic.c
index ec70b85..0937de4 100644
--- a/sections/cper-section-generic.c
+++ b/sections/cper-section-generic.c
@@ -94,9 +94,9 @@
if (isvalid_prop_to_ir(&ui64Type, 7)) {
//CPU brand string. May not exist if on ARM.
- json_object_object_add(
- section_ir, "cpuBrandString",
- json_object_new_string(section_generic->BrandString));
+ add_untrusted_string(section_ir, "cpuBrandString",
+ section_generic->BrandString,
+ sizeof(section_generic->BrandString));
}
if (isvalid_prop_to_ir(&ui64Type, 8)) {
diff --git a/sections/cper-section-ia32x64.c b/sections/cper-section-ia32x64.c
index bf7f565..c127e93 100644
--- a/sections/cper-section-ia32x64.c
+++ b/sections/cper-section-ia32x64.c
@@ -118,7 +118,6 @@
//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;
diff --git a/sections/cper-section-nvidia.c b/sections/cper-section-nvidia.c
index 83c6083..874e616 100644
--- a/sections/cper-section-nvidia.c
+++ b/sections/cper-section-nvidia.c
@@ -27,8 +27,8 @@
json_object *section_ir = json_object_new_object();
- json_object_object_add(section_ir, "signature",
- json_object_new_string(nvidia_error->Signature));
+ add_untrusted_string(section_ir, "signature", nvidia_error->Signature,
+ sizeof(nvidia_error->Signature));
json_object *severity = json_object_new_object();
json_object_object_add(severity, "code",
diff --git a/sections/cper-section-pci-bus.c b/sections/cper-section-pci-bus.c
index 70b5a2c..ac13187 100644
--- a/sections/cper-section-pci-bus.c
+++ b/sections/cper-section-pci-bus.c
@@ -54,8 +54,8 @@
}
//Miscellaneous numeric fields.
- UINT8 command_type = (bus_error->BusCommand >> 56) &
- 0x1; //Byte 7, bit 0.
+ //Byte 7, bit 0.
+ UINT8 command_type = (bus_error->BusCommand >> 56) & 0x1;
if (isvalid_prop_to_ir(&ui64Type, 3)) {
json_object_object_add(
section_ir, "busAddress",
diff --git a/sections/cper-section-pcie.c b/sections/cper-section-pcie.c
index 93d6331..e616728 100644
--- a/sections/cper-section-pcie.c
+++ b/sections/cper-section-pcie.c
@@ -212,11 +212,12 @@
json_object_new_uint64(
aer_decode->correctable_error_status));
- snprintf(hexstring_buf, EFI_UINT64_HEX_STRING_LEN,
- "0x%08" PRIX32, aer_decode->correctable_error_status);
- json_object_object_add(aer_capability_ir,
- "correctable_error_status_hex",
- json_object_new_string(hexstring_buf));
+ int len = snprintf(hexstring_buf, EFI_UINT64_HEX_STRING_LEN,
+ "0x%08" PRIX32,
+ aer_decode->correctable_error_status);
+ json_object_object_add(
+ aer_capability_ir, "correctable_error_status_hex",
+ json_object_new_string_len(hexstring_buf, len));
json_object_object_add(
aer_capability_ir, "correctable_error_mask",