Skip to content
This repository has been archived by the owner on Jul 16, 2024. It is now read-only.

Commit

Permalink
BACKPORT: ACPI / APEI: Make GHES estatus header validation more user …
Browse files Browse the repository at this point in the history
…friendly

ghes_read_estatus() checks various lengths in the top-level header to
ensure the CPER records to be read aren't obviously corrupt.

Take the opportunity to make this more user-friendly, printing a
(ratelimited) message about the nature of the header format error.

This patch is needed because Quicksilver firmware-first error handling
uses the SDEI notification type for communication between trusted
firmware and the OS. This adds needed NMI and SDEI functionality so
that the SDEI path in the kernel through APEI acts as an NMI and is
properly wired up to the APEI interfaces.

Backported from: torvalds/linux@f2a681b

Suggested-by: Borislav Petkov <[email protected]>
Signed-off-by: James Morse <[email protected]>
Signed-off-by: Tyler Baicar <[email protected]>
  • Loading branch information
James Morse authored and tphan-ampere committed Apr 21, 2020
1 parent 15304bd commit 4c66fd1
Showing 1 changed file with 32 additions and 14 deletions.
46 changes: 32 additions & 14 deletions drivers/acpi/apei/ghes.c
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,30 @@ static void ghes_copy_tofrom_phys(void *buffer, u64 paddr, u32 len,
}
}

/* Check the top-level record header has an appropriate size. */
int __ghes_check_estatus(struct ghes *ghes,
struct acpi_hest_generic_status *estatus)
{
u32 len = cper_estatus_len(estatus);

if (len < sizeof(*estatus)) {
pr_warn_ratelimited(FW_WARN GHES_PFX "Truncated error status block!\n");
return -EIO;
}

if (len > ghes->generic->error_block_length) {
pr_warn_ratelimited(FW_WARN GHES_PFX "Invalid error status block length!\n");
return -EIO;
}

if (cper_estatus_check_header(estatus)) {
pr_warn_ratelimited(FW_WARN GHES_PFX "Invalid CPER header!\n");
return -EIO;
}

return 0;
}

static int ghes_read_estatus(struct ghes *ghes,
struct acpi_hest_generic_status *estatus,
u64 *buf_paddr, enum fixed_addresses fixmap_idx)
Expand All @@ -319,27 +343,21 @@ static int ghes_read_estatus(struct ghes *ghes,
return -ENOENT;
}

rc = -EIO;
rc = __ghes_check_estatus(ghes, estatus);
if (rc)
return rc;

len = cper_estatus_len(estatus);
if (len < sizeof(*estatus))
goto err_read_block;
if (len > ghes->generic->error_block_length)
goto err_read_block;
if (cper_estatus_check_header(estatus))
goto err_read_block;
ghes_copy_tofrom_phys(estatus + 1,
*buf_paddr + sizeof(*estatus),
len - sizeof(*estatus), 1, fixmap_idx);
if (cper_estatus_check(estatus))
goto err_read_block;
rc = 0;

err_read_block:
if (rc)
if (cper_estatus_check(estatus)) {
pr_warn_ratelimited(FW_WARN GHES_PFX
"Failed to read error status block!\n");
return -EIO;
}

return rc;
return 0;
}

static void ghes_clear_estatus(struct ghes *ghes,
Expand Down

0 comments on commit 4c66fd1

Please sign in to comment.