mirror of
https://github.com/torvalds/linux.git
synced 2026-11-06 21:58:01 +01:00
ACPI: APEI: GHES: Validate CXL protocol error section length before RAS cap copy
cxl_cper_setup_prot_err_work_data() locates the RAS Capability block at
prot_err + sizeof(*prot_err) + dvsec_len and copies it, but dvsec_len is
firmware controlled and never validated, so it can point the copy outside
the section.
Extend cxl_cper_sec_prot_err_valid() to check that the section can hold
the header, and that the header, DVSEC and RAS Capability block together
fit the reported section length.
Reported-by: sashiko-bot@kernel.org
Link: https://sashiko.dev/#/patchset/20260617-topics-ahmtib01-ras_ffh_arm_internal_review-v6-0-91f725174aa0@arm.com?part=6
Link: https://lore.kernel.org/linux-cxl/20260709165457.8BA181F000E9@smtp.kernel.org/
Fixes: 315c2f0b53 ("acpi/ghes, cper: Recognize and cache CXL Protocol errors")
Reviewed-by: Alison Schofield <alison.schofield@intel.com>
Reviewed-by: Shuai Xue <xueshuai@linux.alibaba.com>
Reviewed-by: Ben Cheatham <benjamin.cheatham@amd.com>
Reviewed-by: Jonathan Cameron <jonathan.cameron@oss.qualcomm.com>
Reviewed-by: Hanjun Guo <guohanjun@huawei.com>
Signed-off-by: Dave Jiang <dave.jiang@intel.com>
Link: https://patch.msgid.link/20260904172337.1409775-10-dave.jiang@intel.com
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
This commit is contained in:
parent
b7a4915a2b
commit
8bf5881531
|
|
@ -248,7 +248,8 @@ static int extlog_print(struct notifier_block *nb, unsigned long val,
|
|||
acpi_hest_get_payload(gdata);
|
||||
|
||||
cxl_cper_post_prot_err(prot_err,
|
||||
gdata->error_severity);
|
||||
gdata->error_severity,
|
||||
gdata->error_data_length);
|
||||
} else if (guid_equal(sec_type, &CPER_SEC_PCIE)) {
|
||||
struct cper_sec_pcie *pcie_err = acpi_hest_get_payload(gdata);
|
||||
|
||||
|
|
|
|||
|
|
@ -753,12 +753,12 @@ static DEFINE_RAW_SPINLOCK(cxl_cper_prot_err_work_lock);
|
|||
struct work_struct *cxl_cper_prot_err_work;
|
||||
|
||||
void cxl_cper_post_prot_err(struct cxl_cper_sec_prot_err *prot_err,
|
||||
int severity)
|
||||
int severity, u32 len)
|
||||
{
|
||||
#ifdef CONFIG_ACPI_APEI_PCIEAER
|
||||
struct cxl_cper_prot_err_work_data wd;
|
||||
|
||||
if (cxl_cper_sec_prot_err_valid(prot_err))
|
||||
if (cxl_cper_sec_prot_err_valid(prot_err, len))
|
||||
return;
|
||||
|
||||
guard(raw_spinlock_irqsave)(&cxl_cper_prot_err_work_lock);
|
||||
|
|
@ -965,7 +965,8 @@ static void ghes_do_proc(struct ghes *ghes,
|
|||
} else if (guid_equal(sec_type, &CPER_SEC_CXL_PROT_ERR)) {
|
||||
struct cxl_cper_sec_prot_err *prot_err = acpi_hest_get_payload(gdata);
|
||||
|
||||
cxl_cper_post_prot_err(prot_err, gdata->error_severity);
|
||||
cxl_cper_post_prot_err(prot_err, gdata->error_severity,
|
||||
gdata->error_data_length);
|
||||
} else if (guid_equal(sec_type, &CPER_SEC_CXL_GEN_MEDIA_GUID)) {
|
||||
struct cxl_cper_event_rec *rec = acpi_hest_get_payload(gdata);
|
||||
|
||||
|
|
|
|||
|
|
@ -5,8 +5,15 @@
|
|||
#include <linux/aer.h>
|
||||
#include <cxl/event.h>
|
||||
|
||||
int cxl_cper_sec_prot_err_valid(struct cxl_cper_sec_prot_err *prot_err)
|
||||
int cxl_cper_sec_prot_err_valid(struct cxl_cper_sec_prot_err *prot_err, u32 len)
|
||||
{
|
||||
if (len < sizeof(*prot_err)) {
|
||||
pr_err_ratelimited(FW_WARN
|
||||
"CXL CPER prot err section too small (%u)\n",
|
||||
len);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!(prot_err->valid_bits & PROT_ERR_VALID_AGENT_ADDRESS)) {
|
||||
pr_err_ratelimited("CXL CPER invalid agent type\n");
|
||||
return -EINVAL;
|
||||
|
|
@ -23,6 +30,15 @@ int cxl_cper_sec_prot_err_valid(struct cxl_cper_sec_prot_err *prot_err)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* The RAS Capability block sits after a firmware-sized DVSEC. */
|
||||
if (sizeof(*prot_err) + prot_err->dvsec_len +
|
||||
sizeof(struct cxl_ras_capability_regs) > len) {
|
||||
pr_err_ratelimited(FW_WARN
|
||||
"CXL CPER prot err DVSEC (%u) overruns section (%u)\n",
|
||||
prot_err->dvsec_len, len);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if ((prot_err->agent_type == RCD || prot_err->agent_type == DEVICE ||
|
||||
prot_err->agent_type == LD || prot_err->agent_type == FMLD) &&
|
||||
!(prot_err->valid_bits & PROT_ERR_VALID_SERIAL_NUMBER))
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ void ghes_estatus_pool_region_free(unsigned long addr, u32 size);
|
|||
|
||||
struct cxl_cper_sec_prot_err;
|
||||
void cxl_cper_post_prot_err(struct cxl_cper_sec_prot_err *prot_err,
|
||||
int severity);
|
||||
int severity, u32 len);
|
||||
#else
|
||||
static inline struct list_head *ghes_get_devices(void) { return NULL; }
|
||||
|
||||
|
|
|
|||
|
|
@ -312,13 +312,13 @@ static inline int cxl_cper_prot_err_kfifo_get(struct cxl_cper_prot_err_work_data
|
|||
#endif
|
||||
|
||||
#ifdef CONFIG_ACPI_APEI_PCIEAER
|
||||
int cxl_cper_sec_prot_err_valid(struct cxl_cper_sec_prot_err *prot_err);
|
||||
int cxl_cper_sec_prot_err_valid(struct cxl_cper_sec_prot_err *prot_err, u32 len);
|
||||
int cxl_cper_setup_prot_err_work_data(struct cxl_cper_prot_err_work_data *wd,
|
||||
struct cxl_cper_sec_prot_err *prot_err,
|
||||
int severity);
|
||||
#else
|
||||
static inline int
|
||||
cxl_cper_sec_prot_err_valid(struct cxl_cper_sec_prot_err *prot_err)
|
||||
cxl_cper_sec_prot_err_valid(struct cxl_cper_sec_prot_err *prot_err, u32 len)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user