mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
Verify that a s390 dump header contains a valid CPU count value.
This bug was found with an input file produced by AFL + ASAN.
$ ./zdump/zgetdump -i ~/input.bin
=================================================================
==3928488==ERROR: AddressSanitizer: global-buffer-overflow on address 0x000001043e90 at pc 0x000001025dca bp 0x03ffe96fe128 sp 0x03ffe96fe120
READ of size 4 at 0x000001043e90 thread T0
#0 0x1025dc9 in df_s390_cpu_info_add /root/s390-tools/zdump/df_s390.c:57
#1 0x101bb59 in dfi_s390_init_gen /root/s390-tools/zdump/dfi_s390.c:169
#2 0x101bb59 in dfi_s390_init_gen /root/s390-tools/zdump/dfi_s390.c:156
#3 0x1015d23 in dfi_init /root/s390-tools/zdump/dfi.c:1216
#4 0x1006a0d in do_dump_info /root/s390-tools/zdump/zgetdump.c:127
#5 0x1006a0d in main /root/s390-tools/zdump/zgetdump.c:182
#6 0x3ffb93abe03 in __libc_start_main (/lib64/libc.so.6+0x2be03)
#7 0x10077bd (/root/s390-tools/zdump/zgetdump+0x10077bd)
0x000001043e91 is located 0 bytes to the right of global variable 'l' defined in 'dfi_s390.c:30:3' (0x1042e80) of size 4113
SUMMARY: AddressSanitizer: global-buffer-overflow /root/s390-tools/zdump/df_s390.c:57 in df_s390_cpu_info_add
Shadow bytes around the buggy address:
0x10000000208780: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10000000208790: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100000002087a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100000002087b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100000002087c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x100000002087d0: 00 00[01]f9 f9 f9 f9 f9 00 00 00 00 00 00 00 00
0x100000002087e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100000002087f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10000000208800: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10000000208810: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10000000208820: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
Shadow gap: cc
==3928488==ABORTING
Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
192 lines
4.4 KiB
C
192 lines
4.4 KiB
C
/*
|
|
* zgetdump - Tool for copying and converting System z dumps
|
|
*
|
|
* S390 dump input format
|
|
*
|
|
* Copyright IBM Corp. 2001, 2017
|
|
*
|
|
* s390-tools is free software; you can redistribute it and/or modify
|
|
* it under the terms of the MIT license. See LICENSE for details.
|
|
*/
|
|
|
|
#include <fcntl.h>
|
|
#include <linux/fs.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/types.h>
|
|
#include <time.h>
|
|
#include <unistd.h>
|
|
|
|
#include "zgetdump.h"
|
|
|
|
/*
|
|
* File local static data
|
|
*/
|
|
static struct {
|
|
struct df_s390_hdr hdr; /* s390 dump header */
|
|
struct df_s390_em em; /* s390 end marker */
|
|
bool extended; /* Extended input dump format */
|
|
} l;
|
|
|
|
/*
|
|
* s390 mem chunk read callback
|
|
*/
|
|
static void dfi_s390_mem_chunk_read(struct dfi_mem_chunk *mem_chunk, u64 off,
|
|
void *buf, u64 cnt)
|
|
{
|
|
(void) mem_chunk;
|
|
|
|
zg_seek(g.fh, off + DF_S390_HDR_SIZE, ZG_CHECK);
|
|
zg_read(g.fh, buf, cnt, ZG_CHECK);
|
|
}
|
|
|
|
/*
|
|
* s390_ext mem chunk read callback
|
|
*/
|
|
static void dfi_s390_ext_mem_chunk_read(struct dfi_mem_chunk *mem_chunk,
|
|
u64 off, void *buf, u64 cnt)
|
|
{
|
|
u64 *mem_chunk_off = mem_chunk->data;
|
|
|
|
zg_seek(g.fh, *mem_chunk_off + off, ZG_CHECK);
|
|
zg_read(g.fh, buf, cnt, ZG_CHECK);
|
|
}
|
|
|
|
|
|
/*
|
|
* Read s390 dump header
|
|
*/
|
|
static int read_s390_hdr(void)
|
|
{
|
|
u64 magic_number;
|
|
|
|
magic_number = l.extended ? DF_S390_MAGIC_EXT : DF_S390_MAGIC;
|
|
if ((zg_type(g.fh) == ZG_TYPE_FILE) && (zg_size(g.fh) < sizeof(l.hdr)))
|
|
return -ENODEV;
|
|
if (zg_read(g.fh, &l.hdr, sizeof(l.hdr), ZG_CHECK_ERR) != sizeof(l.hdr))
|
|
return -ENODEV;
|
|
if (l.hdr.magic != magic_number)
|
|
return -ENODEV;
|
|
if (l.hdr.cpu_cnt > DF_S390_CPU_MAX)
|
|
return -ENODEV;
|
|
df_s390_hdr_add(&l.hdr);
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Init end marker
|
|
*/
|
|
static int read_s390_em(void)
|
|
{
|
|
u64 rc;
|
|
|
|
rc = zg_read(g.fh, &l.em, sizeof(l.em), ZG_CHECK_ERR);
|
|
if (rc != sizeof(l.em))
|
|
return -EINVAL;
|
|
if (df_s390_em_verify(&l.em, &l.hdr) != 0)
|
|
return -EINVAL;
|
|
df_s390_em_add(&l.em);
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Register memory chunks and verify the end marker
|
|
*/
|
|
static int mem_chunks_add(void)
|
|
{
|
|
u64 rc;
|
|
|
|
/* Single memory chunk for non-extended dump format */
|
|
dfi_mem_chunk_add(0, l.hdr.mem_size, NULL,
|
|
dfi_s390_mem_chunk_read,
|
|
NULL);
|
|
rc = zg_seek(g.fh, DF_S390_HDR_SIZE + l.hdr.mem_size,
|
|
ZG_CHECK_NONE);
|
|
if (rc != DF_S390_HDR_SIZE + l.hdr.mem_size)
|
|
return -EINVAL;
|
|
/* Read and verify the end marker */
|
|
return read_s390_em();
|
|
}
|
|
|
|
/*
|
|
* Register memory chunks (extended dump format) and verify the end marker
|
|
*/
|
|
static int mem_chunks_add_ext(void)
|
|
{
|
|
struct df_s390_dump_segm_hdr dump_segm;
|
|
u64 rc, off, old = 0, dump_size = 0;
|
|
|
|
off = zg_seek(g.fh, DF_S390_HDR_SIZE, ZG_CHECK_NONE);
|
|
if (off != DF_S390_HDR_SIZE)
|
|
return -EINVAL;
|
|
while (off < DF_S390_HDR_SIZE + l.hdr.mem_size - PAGE_SIZE) {
|
|
rc = zg_read(g.fh, &dump_segm, PAGE_SIZE, ZG_CHECK_ERR);
|
|
if (rc != PAGE_SIZE)
|
|
return -EINVAL;
|
|
off += PAGE_SIZE;
|
|
/* Add zero memory chunk */
|
|
dfi_mem_chunk_add(old, dump_segm.start - old, NULL,
|
|
dfi_mem_chunk_read_zero, NULL);
|
|
/* Add memory chunk for a dump segment */
|
|
u64 *off_ptr = zg_alloc(sizeof(*off_ptr));
|
|
*off_ptr = off;
|
|
dfi_mem_chunk_add(dump_segm.start, dump_segm.len, off_ptr,
|
|
dfi_s390_ext_mem_chunk_read, zg_free);
|
|
off_ptr = NULL;
|
|
old = dump_segm.start + dump_segm.len;
|
|
dump_size += dump_segm.len;
|
|
off = zg_seek_cur(g.fh, dump_segm.len, ZG_CHECK_NONE);
|
|
if (dump_segm.stop_marker)
|
|
break;
|
|
}
|
|
/* Add zero memory chunk at the end */
|
|
dfi_mem_chunk_add(old, l.hdr.mem_size - old, NULL,
|
|
dfi_mem_chunk_read_zero, NULL);
|
|
/* Set the actual size of the dump file */
|
|
dfi_attr_file_size_set(dump_size);
|
|
/* Check if the last dump segment found */
|
|
if (!dump_segm.stop_marker)
|
|
return -EINVAL;
|
|
/* Read and verify the end marker */
|
|
return read_s390_em();
|
|
}
|
|
|
|
/*
|
|
* Initialize s390 single-volume DFI general function
|
|
*/
|
|
int dfi_s390_init_gen(bool extended)
|
|
{
|
|
int rc;
|
|
|
|
l.extended = extended;
|
|
if (read_s390_hdr() != 0)
|
|
return -ENODEV;
|
|
if (!extended)
|
|
rc = mem_chunks_add();
|
|
else
|
|
rc = mem_chunks_add_ext();
|
|
if (rc)
|
|
return rc;
|
|
df_s390_cpu_info_add(&l.hdr, l.hdr.mem_size);
|
|
zg_seek(g.fh, sizeof(l.hdr), ZG_CHECK);
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Initialize s390 single-volume DFI (non-extended)
|
|
*/
|
|
static int dfi_s390_init(void)
|
|
{
|
|
return dfi_s390_init_gen(DUMP_NON_EXTENDED);
|
|
}
|
|
|
|
/*
|
|
* s390 single-volume DFI (non-extended) operations
|
|
*/
|
|
struct dfi dfi_s390 = {
|
|
.name = "s390",
|
|
.init = dfi_s390_init,
|
|
.feat_bits = DFI_FEAT_COPY | DFI_FEAT_SEEK,
|
|
};
|