[PATCH v4 3/3] RAS: Fix integer overflow in ARM processor error context walk
From: Abbott Liu
Date: Wed Sep 09 2026 - 07:39:04 EST
sz is an int while ctx_info->size is a u32, so a size greater than
0x7fffffff makes sz negative and moves ctx_info below the error
record. The header check of the next iteration then passes, because
the offset of ctx_info relative to err is negative, and ctx_info->size
is read from a wild pointer. A negative sz also deflates ctx_len,
which can keep vsei_len non-negative, so the truncated record path is
not taken and the out-of-section ctx_info is traced as vendor error
data.
Check each context entry with 64-bit arithmetic: both the header and
the context data must fit within err + section_length. Stop the walk
at the first entry that does not fit, flag the record as overflowed
and take the truncated record path, which sanitizes the values
passed to trace_arm_event(), instead of detecting the overflow after
the walk only from a negative vsei_len.
Fixes: 87880af2d24e ("APEI/GHES: ARM processor Error: don't go past allocated memory")
Fixes: 05954511b73e ("RAS: Report all ARM processor CPER information to userspace")
Reported-by: Hanjun Guo <guohanjun@xxxxxxxxxx>
Link: https://lore.kernel.org/all/20260825134323.4181892-1-liuwenliang@xxxxxxxxxx/
Signed-off-by: Abbott Liu <liuwenliang@xxxxxxxxxx>
---
drivers/ras/ras.c | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/drivers/ras/ras.c b/drivers/ras/ras.c
index 085fe2d980e5..db378fd6f1ff 100644
--- a/drivers/ras/ras.c
+++ b/drivers/ras/ras.c
@@ -59,6 +59,7 @@ void log_arm_hw_error(struct cper_sec_proc_arm *err, const u8 sev)
struct cper_arm_ctx_info *ctx_info;
u8 *ven_err_data;
s32 ctx_len = 0;
+ bool overflow = false;
int n, sz, cpu;
s32 vsei_len;
s32 pei_len;
@@ -74,15 +75,21 @@ void log_arm_hw_error(struct cper_sec_proc_arm *err, const u8 sev)
for (n = 0; n < err->context_info_num; n++) {
sz = sizeof(struct cper_arm_ctx_info);
- if (sz + (long)ctx_info - (long)err <= err->section_length)
+ if ((sz + (long)ctx_info - (long)err <= err->section_length) &&
+ ((u64)sz + ctx_info->size + ((long)ctx_info - (long)err) <=
+ err->section_length)) {
sz += ctx_info->size;
+ } else {
+ overflow = true;
+ break;
+ }
ctx_info = (struct cper_arm_ctx_info *)((long)ctx_info + sz);
ctx_len += sz;
}
vsei_len = err->section_length - (sizeof(struct cper_sec_proc_arm) + pei_len + ctx_len);
- if (vsei_len < 0) {
+ if (overflow || vsei_len < 0) {
pr_warn(FW_BUG "section length: %d\n", err->section_length);
pr_warn(FW_BUG "section length is too small\n");
pr_warn(FW_BUG "firmware-generated error record is incorrect\n");
--
2.43.0