[PATCH v2 1/2] efi/cper: validate ARM context headers before reading their size

Pengpeng Hou <[email protected]>
Newsgroups gmane.linux.acpi.devel,gmane.linux.kernel
Message-ID <[email protected]>
ARM processor CPER sections contain a fixed header, a fixed-size
error-information array and variable-size context records.  The parser
derives the remaining byte count in int after subtracting
firmware-controlled unsigned values, then reads ctx_info->size before
proving that a complete context header remains.

Keep the remaining extent in size_t.  Validate the section header and
error-information count before advancing, then require each context
header, payload and 16-byte-aligned record to fit before it is read or
consumed.

Fixes: c6d8c8ef1d0d ("efi: Move ARM CPER code to new file")

Assisted-by: Codex:gpt-5
Signed-off-by: Pengpeng Hou <[email protected]>
---
 drivers/firmware/efi/cper-arm.c | 53 ++++++++++++++++++++++++++-------
 1 file changed, 42 insertions(+), 11 deletions(-)

diff --git a/drivers/firmware/efi/cper-arm.c b/drivers/firmware/efi/cper-arm.c
index b21cb1232d82..e2f973d7a4a4 100644
--- a/drivers/firmware/efi/cper-arm.c
+++ b/drivers/firmware/efi/cper-arm.c
@@ -229,26 +229,39 @@ void cper_print_proc_arm(const char *pfx,
 			 const struct cper_sec_proc_arm *proc,
 			 u32 length)
 {
-	int i, len, max_ctx_type;
+	int i, max_ctx_type;
 	struct cper_arm_err_info *err_info;
 	struct cper_arm_ctx_info *ctx_info;
 	char newpfx[64], infopfx[ARRAY_SIZE(newpfx) + 1];
 	char error_type[120];
+	size_t len;
 
-	printk("%sMIDR: 0x%016llx\n", pfx, proc->midr);
+	if (length < sizeof(*proc)) {
+		printk("%ssection length is too small\n", pfx);
+		printk("%sfirmware-generated error record is incorrect\n", pfx);
+		return;
+	}
 
-	len = proc->section_length - (sizeof(*proc) +
-		proc->err_info_num * (sizeof(*err_info)));
+	printk("%sMIDR: 0x%016llx\n", pfx, proc->midr);
 
-	if (len < 0 || proc->section_length > length) {
-		printk("%ssection length: %d, CPER size: %d\n",
+	if (proc->section_length < sizeof(*proc) ||
+	    proc->section_length > length) {
+		printk("%ssection length: %u, CPER size: %u\n",
 		       pfx, proc->section_length, length);
 		printk("%ssection length is too %s\n", pfx,
-		       (len < 0) ? "small" : "big");
+		       proc->section_length < sizeof(*proc) ? "small" : "big");
+		printk("%sfirmware-generated error record is incorrect\n", pfx);
+		return;
+	}
+
+	len = proc->section_length - sizeof(*proc);
+	if (proc->err_info_num > len / sizeof(*err_info)) {
+		printk("%ssection length is too small\n", pfx);
 		printk("%sfirmware-generated error record is incorrect\n", pfx);
 		printk("%sERR_INFO_NUM is %d\n", pfx, proc->err_info_num);
 		return;
 	}
+	len -= proc->err_info_num * sizeof(*err_info);
 
 	if (proc->validation_bits & CPER_ARM_VALID_MPIDR)
 		printk("%sMultiprocessor Affinity Register (MPIDR): 0x%016llx\n",
@@ -313,10 +326,28 @@ void cper_print_proc_arm(const char *pfx,
 	ctx_info = (struct cper_arm_ctx_info *)err_info;
 	max_ctx_type = ARRAY_SIZE(arm_reg_ctx_strs) - 1;
 	for (i = 0; i < proc->context_info_num; i++) {
-		int size = ALIGN(sizeof(*ctx_info) + ctx_info->size, 16);
+		size_t size;
 
 		printk("%sContext info structure %d:\n", pfx, i);
-		if (len < size) {
+		if (len < sizeof(*ctx_info)) {
+			printk("%ssection length is too small\n", newpfx);
+			printk("%sfirmware-generated error record is incorrect\n", pfx);
+			return;
+		}
+		if (ctx_info->size > len - sizeof(*ctx_info)) {
+			printk("%ssection length is too small\n", newpfx);
+			printk("%sfirmware-generated error record is incorrect\n", pfx);
+			return;
+		}
+
+		size = sizeof(*ctx_info) + ctx_info->size;
+		if (size > SIZE_MAX - 15) {
+			printk("%scontext record size is too big\n", newpfx);
+			printk("%sfirmware-generated error record is incorrect\n", pfx);
+			return;
+		}
+		size = ALIGN(size, 16);
+		if (size > len) {
 			printk("%ssection length is too small\n", newpfx);
 			printk("%sfirmware-generated error record is incorrect\n", pfx);
 			return;
@@ -331,11 +362,11 @@ void cper_print_proc_arm(const char *pfx,
 		print_hex_dump(newpfx, "", DUMP_PREFIX_OFFSET, 16, 4,
 				(ctx_info + 1), ctx_info->size, 0);
 		len -= size;
-		ctx_info = (struct cper_arm_ctx_info *)((long)ctx_info + size);
+		ctx_info = (struct cper_arm_ctx_info *)((u8 *)ctx_info + size);
 	}
 
 	if (len > 0) {
-		printk("%sVendor specific error info has %u bytes:\n", pfx,
+		printk("%sVendor specific error info has %zu bytes:\n", pfx,
 		       len);
 		print_hex_dump(newpfx, "", DUMP_PREFIX_OFFSET, 16, 4, ctx_info,
 				len, true);
-- 
2.50.1 (Apple Git-155)
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.