Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

EFI/CPER: don't go past the ARM processor CPER record buffer

There's a logic inside GHES/CPER to detect if the section_length
is too small, but it doesn't detect if it is too big.

Currently, if the firmware receives an ARM processor CPER record
stating that a section length is big, kernel will blindly trust
section_length, producing a very long dump. For instance, a 67
bytes record with ERR_INFO_NUM set 46198 and section length
set to 854918320 would dump a lot of data going a way past the
firmware memory-mapped area.

Fix it by adding a logic to prevent it to go past the buffer
if ERR_INFO_NUM is too big, making it report instead:

[Hardware Error]: Hardware error from APEI Generic Hardware Error Source: 1
[Hardware Error]: event severity: recoverable
[Hardware Error]: Error 0, type: recoverable
[Hardware Error]: section_type: ARM processor error
[Hardware Error]: MIDR: 0xff304b2f8476870a
[Hardware Error]: section length: 854918320, CPER size: 67
[Hardware Error]: section length is too big
[Hardware Error]: firmware-generated error record is incorrect
[Hardware Error]: ERR_INFO_NUM is 46198

Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
Acked-by: Ard Biesheuvel <ardb@kernel.org>
Reviewed-by: Hanjun Guo <guohanjun@huawei.com>
[ rjw: Subject and changelog tweaks ]
Link: https://patch.msgid.link/41cd9f6b3ace3cdff7a5e864890849e4b1c58b63.1767871950.git.mchehab+huawei@kernel.org
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>

authored by

Mauro Carvalho Chehab and committed by
Rafael J. Wysocki
eae21bee 87880af2

+12 -6
+8 -4
drivers/firmware/efi/cper-arm.c
··· 226 226 } 227 227 228 228 void cper_print_proc_arm(const char *pfx, 229 - const struct cper_sec_proc_arm *proc) 229 + const struct cper_sec_proc_arm *proc, 230 + u32 length) 230 231 { 231 232 int i, len, max_ctx_type; 232 233 struct cper_arm_err_info *err_info; ··· 239 238 240 239 len = proc->section_length - (sizeof(*proc) + 241 240 proc->err_info_num * (sizeof(*err_info))); 242 - if (len < 0) { 243 - printk("%ssection length: %d\n", pfx, proc->section_length); 244 - printk("%ssection length is too small\n", pfx); 241 + 242 + if (len < 0 || proc->section_length > length) { 243 + printk("%ssection length: %d, CPER size: %d\n", 244 + pfx, proc->section_length, length); 245 + printk("%ssection length is too %s\n", pfx, 246 + (len < 0) ? "small" : "big"); 245 247 printk("%sfirmware-generated error record is incorrect\n", pfx); 246 248 printk("%sERR_INFO_NUM is %d\n", pfx, proc->err_info_num); 247 249 return;
+2 -1
drivers/firmware/efi/cper.c
··· 659 659 660 660 printk("%ssection_type: ARM processor error\n", newpfx); 661 661 if (gdata->error_data_length >= sizeof(*arm_err)) 662 - cper_print_proc_arm(newpfx, arm_err); 662 + cper_print_proc_arm(newpfx, arm_err, 663 + gdata->error_data_length); 663 664 else 664 665 goto err_section_too_small; 665 666 #endif
+2 -1
include/linux/cper.h
··· 595 595 const char *cper_mem_err_unpack(struct trace_seq *, 596 596 struct cper_mem_err_compact *); 597 597 void cper_print_proc_arm(const char *pfx, 598 - const struct cper_sec_proc_arm *proc); 598 + const struct cper_sec_proc_arm *proc, 599 + u32 length); 599 600 void cper_print_proc_ia(const char *pfx, 600 601 const struct cper_sec_proc_ia *proc); 601 602 int cper_mem_err_location(struct cper_mem_err_compact *mem, char *msg);