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