zdump/dfi_lkcd: Validate LKCD page size before buffer read

read_page_buf() uses the file-controlled pg_hdr->size directly as the
byte count for zg_read() into fixed stack buffers of PAGE_SIZE.
A crafted LKCD dump with pg_hdr->size > PAGE_SIZE overflows the buffer
and smashes the stack frame. A size of 0 for a raw page silently
produces uninitialised data.

Enforce page header size constraints following crash-utility's logic:
- Compressed or Raw pages with size > PAGE_SIZE are invalid;
  exit with an error.
- Raw pages with size 0 contain no data in the file; fill the
  output buffer with zeros without reading.
- Compressed pages with size 0 are caught by the uncompress() return
  code check.
- Raw pages with size != PAGE_SIZE are invalid; exit with an error.

Check the return code of uncompress() and exit with an error if
decompression fails, rather than silently proceeding with an incomplete
output buffer.

Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
This commit is contained in:
Mikhail Zaslonko
2026-07-01 13:59:00 +02:00
committed by Jan Höppner
parent 33c75584cd
commit cdabf280ac

View File

@@ -43,15 +43,29 @@ static void read_page_buf(struct df_lkcd_pg_hdr *pg_hdr, void *buf)
unsigned long size = PAGE_SIZE;
unsigned char cbuf[PAGE_SIZE];
if (pg_hdr->size > PAGE_SIZE)
ERR_EXIT("Dump file inconsistent, LKCD page size too large (%u)",
pg_hdr->size);
switch (pg_hdr->flags) {
case DF_LKCD_DH_RAW:
zg_read(g.fh, buf, pg_hdr->size, ZG_CHECK);
if (pg_hdr->size == 0) {
/* No data in file: treat as zero page */
memset(buf, 0, PAGE_SIZE);
break;
}
if (pg_hdr->size == PAGE_SIZE) {
zg_read(g.fh, buf, pg_hdr->size, ZG_CHECK);
break;
}
ERR_EXIT("Dump file inconsistent, LKCD page size invalid: %u", pg_hdr->size);
break;
case DF_LKCD_DH_COMPRESSED:
zg_read(g.fh, cbuf, pg_hdr->size, ZG_CHECK);
uncompress(buf, &size, cbuf, pg_hdr->size);
if (uncompress(buf, &size, cbuf, pg_hdr->size) != Z_OK)
ERR_EXIT("Dump file inconsistent, LKCD page decompression failed");
if (size != PAGE_SIZE)
ABORT("Invalid page size: %ld", size);
ERR_EXIT("Dump file inconsistent, LKCD decompressed page size invalid: %u",
size);
break;
default:
ERR_EXIT("Unsupported page flags: %x at addr %Lx",