[PATCH v5 3/5] alpha: bound EV6 logout decoding by the processor area

From: Magnus Lindholm

Date: Fri Oct 09 2026 - 08:39:59 EST


The ES40 correctable logout frame has only the common CPU registers before
its system area at offset 0x58. The EV6 decoder treats those system words
as extra CPU registers and reads beyond the 0x80-byte frame.

Validate the CPU and system boundaries before decoding or dumping data.
Print the additional CPU registers only when the processor area contains
them. This also rejects truncated processor frames passed by console-log
handlers. See the ES40 Service Guide EK-ES240-SV A01, Table D-19.

Signed-off-by: Magnus Lindholm <linmag7@xxxxxxxxx>
---
arch/alpha/kernel/err_ev6.c | 36 ++++++++++++++++++++++++++----------
1 file changed, 26 insertions(+), 10 deletions(-)

diff --git a/arch/alpha/kernel/err_ev6.c b/arch/alpha/kernel/err_ev6.c
index 8144f2045b5b..ec0b63b0f377 100644
--- a/arch/alpha/kernel/err_ev6.c
+++ b/arch/alpha/kernel/err_ev6.c
@@ -190,6 +190,23 @@ ev6_process_logout_frame(struct el_common *mchk_header, int print)
(struct el_common_EV6_mcheck *)mchk_header;
int status = MCHK_DISPOSITION_UNKNOWN_ERROR;

+ /*
+ * ES40 correctable frames end the CPU area before EXC_ADDR (Table
+ * D-19). Validate both regions before decoding or dumping any data.
+ */
+ if (mchk_header->proc_offset != offsetof(struct el_common_EV6_mcheck,
+ I_STAT) ||
+ mchk_header->sys_offset < offsetof(struct el_common_EV6_mcheck,
+ EXC_ADDR) ||
+ mchk_header->sys_offset > mchk_header->size ||
+ ((mchk_header->sys_offset | mchk_header->size) & 7)) {
+ if (print)
+ printk("%s Invalid EV6 logout frame: size %x, CPU %x, system %x\n",
+ err_print_prefix, mchk_header->size,
+ mchk_header->proc_offset, mchk_header->sys_offset);
+ return MCHK_DISPOSITION_UNKNOWN_ERROR;
+ }
+
status |= ev6_parse_ibox(ev6mchk->I_STAT, print);
status |= ev6_parse_mbox(ev6mchk->MM_STAT, ev6mchk->DC_STAT,
ev6mchk->C_STAT, print);
@@ -203,16 +220,15 @@ ev6_process_logout_frame(struct el_common *mchk_header, int print)
if (status != MCHK_DISPOSITION_DISMISS) {
char *saved_err_prefix = err_print_prefix;

- /*
- * Dump some additional information from the frame
- */
- printk("%s EXC_ADDR: 0x%016lx IER_CM: 0x%016lx"
- " ISUM: 0x%016lx\n"
- " PAL_BASE: 0x%016lx I_CTL: 0x%016lx"
- " PCTX: 0x%016lx\n",
- err_print_prefix,
- ev6mchk->EXC_ADDR, ev6mchk->IER_CM, ev6mchk->ISUM,
- ev6mchk->PAL_BASE, ev6mchk->I_CTL, ev6mchk->PCTX);
+ /* These registers are absent from short correctable frames. */
+ if (mchk_header->sys_offset >= sizeof(*ev6mchk))
+ printk("%s EXC_ADDR: 0x%016lx IER_CM: 0x%016lx"
+ " ISUM: 0x%016lx\n"
+ " PAL_BASE: 0x%016lx I_CTL: 0x%016lx"
+ " PCTX: 0x%016lx\n",
+ err_print_prefix,
+ ev6mchk->EXC_ADDR, ev6mchk->IER_CM, ev6mchk->ISUM,
+ ev6mchk->PAL_BASE, ev6mchk->I_CTL, ev6mchk->PCTX);

if (status == MCHK_DISPOSITION_UNKNOWN_ERROR) {
printk("%s UNKNOWN error, frame follows:\n",
--
2.43.0