mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
alpha: bound EV6 logout decoding by the processor area
The ES40 Service Guide, Table D-19, documents a correctable frame with its system area at 0x58 and total size 0x80. The existing EV6 decoder interprets system words as extended CPU registers and reads past its end. This establishes the layout for ES40; whether Titan and Nautilus PALcode also emits this short frame has not been verified. Validate the processor area before decoding it and only print extended registers when present. Preserve rejected frames with a raw dump rather than trusting their invalid offsets. Cap the dump at 1 KiB and round down to complete quadwords. This still relies on firmware supplying an accessible frame of its advertised size; the cap is not pointer validation. Signed-off-by: Magnus Lindholm <linmag7@gmail.com> Reviewed-by: Matt Turner <mattst88@gmail.com> Signed-off-by: Magnus Lindholm <linmag7@gmail.com>
This commit is contained in:
parent
6634cb1490
commit
a182df7cea
|
|
@ -44,6 +44,19 @@ mchk_dump_mem(void *data, size_t length, char **annotation)
|
|||
}
|
||||
}
|
||||
|
||||
/* Preserve rejected frames without trusting their internal offsets. */
|
||||
void
|
||||
mchk_dump_logout_frame_raw(struct el_common *header)
|
||||
{
|
||||
size_t length = header->size;
|
||||
|
||||
/* Bound diagnostic output and never read a partial final quadword. */
|
||||
if (length > 1024)
|
||||
length = 1024;
|
||||
length &= ~7UL;
|
||||
mchk_dump_mem(header, length, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
mchk_dump_logout_frame(struct el_common *mchk_header)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -190,6 +190,25 @@ 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);
|
||||
mchk_dump_logout_frame_raw(mchk_header);
|
||||
}
|
||||
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 +222,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",
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ struct el_subpacket_handler {
|
|||
extern char *err_print_prefix;
|
||||
|
||||
extern void mchk_dump_mem(void *, size_t, char **);
|
||||
extern void mchk_dump_logout_frame_raw(struct el_common *header);
|
||||
extern void mchk_dump_logout_frame(struct el_common *);
|
||||
extern void el_print_timestamp(union el_timestamp *);
|
||||
extern void el_process_subpackets(struct el_subpacket *, int);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user