Re: [PATCH] efi: cper: validate processor section item bounds
"Ard Biesheuvel" <[email protected]> Sat, 01 Aug 2026 15:03:56 +0200
| Newsgroups | org.kernel.vger.linux-acpi,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
On Mon, 6 Jul 2026, at 11:31, Pengpeng Hou wrote: > CPER processor error sections contain counted arrays after the fixed > section header. The ARM path receives the section length, but it read > each context header size before proving that a full context header > remains. The IA32/X64 path received only the payload pointer, so it > could not bound its error information and context walks against the > section payload. > > Pass the IA32/X64 payload length into the printer and track the > remaining bytes while walking variable records. Also make the ARM path > prove that a context header remains before reading its variable size > field. > Please split this into two patches (or more), and explain in more detail what the problem is and how you are fixing it. > Signed-off-by: Pengpeng Hou <[email protected]> > --- > drivers/firmware/efi/cper-arm.c | 10 ++++++++-- > drivers/firmware/efi/cper-x86.c | 32 ++++++++++++++++++++++++++++++-- > drivers/firmware/efi/cper.c | 3 ++- > include/linux/cper.h | 3 ++- > 4 files changed, 42 insertions(+), 6 deletions(-) > > diff --git a/drivers/firmware/efi/cper-arm.c b/drivers/firmware/efi/cper-arm.c > index b21cb1232d82..75a32f3a31a0 100644 > --- a/drivers/firmware/efi/cper-arm.c > +++ b/drivers/firmware/efi/cper-arm.c > @@ -313,10 +313,16 @@ 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); > + int size; > > printk("%sContext info structure %d:\n", pfx, i); > - if (len < size) { > + if (len < sizeof(*ctx_info)) { > + pr_warn("%ssection length is too small\n", newpfx); > + pr_warn("%sfirmware-generated error record is incorrect\n", pfx); > + return; > + } > + size = ALIGN(sizeof(*ctx_info) + ctx_info->size, 16); > + if (size > len) { > printk("%ssection length is too small\n", newpfx); > printk("%sfirmware-generated error record is incorrect\n", pfx); > return; > diff --git a/drivers/firmware/efi/cper-x86.c b/drivers/firmware/efi/cper-x86.c > index 3949d7b5e808..77621a5677da 100644 > --- a/drivers/firmware/efi/cper-x86.c > +++ b/drivers/firmware/efi/cper-x86.c > @@ -3,6 +3,7 @@ > > #include <linux/cper.h> > #include <linux/acpi.h> > +#include <linux/printk.h> > > /* > * We don't need a "CPER_IA" prefix since these are all locally > defined. > @@ -254,17 +255,26 @@ static void print_err_info(const char *pfx, u8 > err_type, u64 check) > } > } > > -void cper_print_proc_ia(const char *pfx, const struct cper_sec_proc_ia *proc) > +void cper_print_proc_ia(const char *pfx, const struct cper_sec_proc_ia *proc, > + u32 length) > { > int i; > + u32 len; > struct cper_ia_err_info *err_info; > struct cper_ia_proc_ctx *ctx_info; > char newpfx[64], infopfx[64]; > u8 err_type; > > + if (length < sizeof(*proc)) { > + pr_warn("%ssection length is too small\n", pfx); > + pr_warn("%sfirmware-generated error record is incorrect\n", pfx); > + return; > + } > + > if (proc->validation_bits & VALID_LAPIC_ID) > printk("%sLocal APIC_ID: 0x%llx\n", pfx, proc->lapic_id); > > + len = length - sizeof(*proc); > if (proc->validation_bits & VALID_CPUID_INFO) { > printk("%sCPUID Info:\n", pfx); > print_hex_dump(pfx, "", DUMP_PREFIX_OFFSET, 16, 4, proc->cpuid, > @@ -276,6 +286,11 @@ void cper_print_proc_ia(const char *pfx, const > struct cper_sec_proc_ia *proc) > err_info = (struct cper_ia_err_info *)(proc + 1); > for (i = 0; i < VALID_PROC_ERR_INFO_NUM(proc->validation_bits); i++) { > printk("%sError Information Structure %d:\n", pfx, i); > + if (len < sizeof(*err_info)) { > + pr_warn("%ssection length is too small\n", newpfx); > + pr_warn("%sfirmware-generated error record is incorrect\n", pfx); > + return; > + } > > err_type = cper_get_err_type(&err_info->err_type); > printk("%sError Structure Type: %s\n", newpfx, > @@ -321,14 +336,26 @@ void cper_print_proc_ia(const char *pfx, const > struct cper_sec_proc_ia *proc) > } > > err_info++; > + len -= sizeof(*err_info); > } > > ctx_info = (struct cper_ia_proc_ctx *)err_info; > for (i = 0; i < VALID_PROC_CXT_INFO_NUM(proc->validation_bits); i++) { > - int size = ALIGN(sizeof(*ctx_info) + ctx_info->reg_arr_size, 16); > + int size; > int groupsize = 4; > > printk("%sContext Information Structure %d:\n", pfx, i); > + if (len < sizeof(*ctx_info)) { > + pr_warn("%ssection length is too small\n", newpfx); > + pr_warn("%sfirmware-generated error record is incorrect\n", pfx); > + return; > + } > + size = ALIGN(sizeof(*ctx_info) + ctx_info->reg_arr_size, 16); > + if (size > len) { > + pr_warn("%ssection length is too small\n", newpfx); > + pr_warn("%sfirmware-generated error record is incorrect\n", pfx); > + return; > + } > > printk("%sRegister Context Type: %s\n", newpfx, > ctx_info->reg_ctx_type < ARRAY_SIZE(ia_reg_ctx_strs) ? > @@ -357,5 +384,6 @@ void cper_print_proc_ia(const char *pfx, const > struct cper_sec_proc_ia *proc) > } > > ctx_info = (struct cper_ia_proc_ctx *)((long)ctx_info + size); > + len -= size; > } > } > diff --git a/drivers/firmware/efi/cper.c b/drivers/firmware/efi/cper.c > index 06b4fdb59917..87e65377a15d 100644 > --- a/drivers/firmware/efi/cper.c > +++ b/drivers/firmware/efi/cper.c > @@ -675,7 +675,8 @@ cper_estatus_print_section(const char *pfx, struct > acpi_hest_generic_data *gdata > > printk("%ssection_type: IA32/X64 processor error\n", newpfx); > if (gdata->error_data_length >= sizeof(*ia_err)) > - cper_print_proc_ia(newpfx, ia_err); > + cper_print_proc_ia(newpfx, ia_err, > + gdata->error_data_length); > else > goto err_section_too_small; > #endif > diff --git a/include/linux/cper.h b/include/linux/cper.h > index 440b35e459e5..a2fa9376f6c0 100644 > --- a/include/linux/cper.h > +++ b/include/linux/cper.h > @@ -598,7 +598,8 @@ void cper_print_proc_arm(const char *pfx, > const struct cper_sec_proc_arm *proc, > u32 length); > void cper_print_proc_ia(const char *pfx, > - const struct cper_sec_proc_ia *proc); > + const struct cper_sec_proc_ia *proc, > + u32 length); > int cper_mem_err_location(struct cper_mem_err_compact *mem, char *msg); > int cper_dimm_err_location(struct cper_mem_err_compact *mem, char *msg); > > -- > 2.43.0