Re: [PATCH v3 02/10] efi/cper: Reject CPER records with an out-of-range error_data_length

Shuai Xue <[email protected]> Wed, 12 Aug 2026 20:23:15 +0800
Newsgroups gmane.linux.acpi.devel
Message-ID <[email protected]>

On 7/18/26 12:16 AM, Dave Jiang wrote:
> sashiko-bot flagged that the "len < sizeof(*rec)" guard added in this
> series can be bypassed by an integer overflow in the shared length check.
> 
> cper_estatus_check() bounds firmware CPER data before the section
> handlers in ghes_do_proc() run. It sizes each section with
> acpi_hest_get_record_size(), which adds the firmware-controlled u32
> error_data_length to the header size using signed int helpers in
> <acpi/ghes.h>. A value like 0xffffffb9 sign-converts to a negative
> number, wraps the record size small, and slips past the
> "record_size > data_len" check. A section handler then copies a
> fixed-size payload out of it and reads past the record.
> 
> Reject a section whose error_data_length is negative once sign-converted
> or larger than the remaining data, before the size arithmetic runs.
> 
> Reported-by: [email protected]
> Closes: https://sashiko.dev/#/patchset/[email protected]?part=1
> Fixes: 45b14a4ffcc1 ("efi: cper: Fix possible out-of-bounds access")
> Assisted-by: Claude:claude-opus-4-8
> Signed-off-by: Dave Jiang <[email protected]>
> ---
> v3:
> - New patch. Fix the signed error_data_length overflow that lets a
>    crafted section bypass cper_estatus_check() and defeat the per-caller
>    size guards (sashiko).
> ---
>   drivers/firmware/efi/cper.c | 10 ++++++++++
>   1 file changed, 10 insertions(+)
> 
> diff --git a/drivers/firmware/efi/cper.c b/drivers/firmware/efi/cper.c
> index 06b4fdb59917..99a86b2675e3 100644
> --- a/drivers/firmware/efi/cper.c
> +++ b/drivers/firmware/efi/cper.c
> @@ -765,6 +765,16 @@ int cper_estatus_check(const struct acpi_hest_generic_status *estatus)
>   		if (acpi_hest_get_size(gdata) > data_len)
>   			return -EINVAL;
>   
> +		/*
> +		 * error_data_length reaches record_size below as a signed int
> +		 * (see <acpi/ghes.h>), so a value with the sign bit set can
> +		 * wrap record_size small and slip past the bound check. Reject
> +		 * it before the arithmetic.
> +		 */
> +		if (acpi_hest_get_error_length(gdata) < 0 ||
> +		    acpi_hest_get_error_length(gdata) > data_len)
> +			return -EINVAL;
> +
>   		record_size = acpi_hest_get_record_size(gdata);
>   		if (record_size > data_len)
>   			return -EINVAL;

Minor: Could pull the helper result into a local, it's called twice.

Reviewed-by: Shuai Xue <[email protected]>

Thanks.
Shuai