mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
Check that a CPU's lowcore address falls within a valid memory region before accessing it. This prevents potential illegal memory accesses in case a dump contains invalid CPU lowcore addresses. This bug was found with AFL fuzzing and ASAN. Starting program: /root/s390-tools/zdump/zgetdump -iVVVVV /root/zgetdump-fuzzing/findings/crashes/id:000004,sig:06,src:000005,op:flip32,pos:3055 [Thread debugging using libthread_db enabled] Using host libthread_db library "/lib64/libthread_db.so.1". TRACE: DFI initialization DEBUG: DFI trying s390tape DEBUG: DFI s390tape returned with rc -19 DEBUG: DFI trying devmem DEBUG: DFI devmem returned with rc -19 DEBUG: DFI trying s390mv_ext DEBUG: DFI s390mv_ext returned with rc -19 DEBUG: DFI trying s390mv DEBUG: DFI s390mv returned with rc -19 DEBUG: DFI trying s390_ext DEBUG: DFI S390 extended initialization DEBUG: DFI s390_ext returned with rc -19 DEBUG: DFI trying s390 DEBUG: DFI S390 initialization INFO: DFI S390 version 5 DEBUG: DFI S390 mem_size 0x00000000000dbba0 DEBUG: DFI add vol mem chunk start 0x0000000000000000 size 0x00000000000dbba0 volnr 0 [snip] TRACE: DFI virt mem read addr 0x0000000000000000 size 0x0000000000002000 TRACE: DFI virt mem read addr 0x0000000000000000 size 0x0000000000002000 TRACE: DFI virt mem read addr 0x0000000000000000 size 0x0000000000002000 TRACE: DFI virt mem read addr 0x0000000000000000 size 0x0000000000002000 TRACE: DFI virt mem read addr 0x0000000000000000 size 0x0000000000002000 TRACE: DFI virt mem read addr 0x0000000000000000 size 0x0000000000002000 TRACE: DFI virt mem read addr 0x0000000000000000 size 0x0000000000002000 TRACE: DFI virt mem read addr 0x0000000000000000 size 0x0000000000002000 TRACE: DFI virt mem read addr 0x0000000000000000 size 0x0000000000002000 TRACE: DFI virt mem read addr 0x0000000000000000 size 0x0000000000002000 TRACE: DFI virt mem read addr 0x0000000000000000 size 0x0000000000002000 TRACE: DFI virt mem read addr 0x0000000000000000 size 0x0000000000002000 TRACE: DFI virt mem read addr 0x0000000000000000 size 0x0000000000002000 TRACE: DFI virt mem read addr 0x0000000000000000 size 0x0000000000002000 TRACE: DFI virt mem read addr 0x00000000000000ff size 0x0000000000002000 TRACE: DFI virt mem read addr 0x00000000ffffff00 size 0x0000000000002000 Program received signal SIGSEGV, Segmentation fault. 0x000000000100fbb0 in mem_read (cnt=<optimized out>, buf=0x3ffffffc7d0, addr=4294967040, mem=0x104b218 <l+152>) at dfi.c:339 339 size = MIN(cnt - copied, mem_chunk->end - addr + 1); Missing separate debuginfos, use: dnf debuginfo-install fuse-libs-2.9.9-11.fc34.s390x glibc-2.33-20.1.ibm.fc34.s390x libasan-11.0.1-0.3.1.ibm.fc34.s390x libgcc-11.0.1-0.3.1.ibm.fc34.s390x libstdc++-11.0.1-0.3.1.ibm.fc34.s390x zlib-1.2.11-26.fc34.s390x (gdb) bt Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com> Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
297 lines
8.3 KiB
C
297 lines
8.3 KiB
C
/*
|
|
* zgetdump - Tool for copying and converting System z dumps
|
|
*
|
|
* Generic input dump format functions (DFI - Dump Format Input)
|
|
*
|
|
* Copyright IBM Corp. 2001, 2018
|
|
*
|
|
* s390-tools is free software; you can redistribute it and/or modify
|
|
* it under the terms of the MIT license. See LICENSE for details.
|
|
*/
|
|
|
|
#ifndef DFI_H
|
|
#define DFI_H
|
|
|
|
#include <linux/utsname.h>
|
|
|
|
#include "lib/zt_common.h"
|
|
#include "lib/util_list.h"
|
|
|
|
#include "zg.h"
|
|
|
|
/*
|
|
* CPU info functions and definitions
|
|
*/
|
|
|
|
enum dfi_arch {
|
|
DFI_ARCH_32 = 0,
|
|
DFI_ARCH_64 = 1,
|
|
DFI_ARCH_UNKNOWN = 2,
|
|
};
|
|
|
|
struct dfi_lowcore_32 {
|
|
u8 pad_0x0000[0x0084 - 0x0000]; /* 0x0000 */
|
|
u16 cpu_addr; /* 0x0084 */
|
|
u8 pad_0x0086[0x00d4 - 0x0086]; /* 0x0086 */
|
|
u32 extended_save_area_addr; /* 0x00d4 */
|
|
u32 timer_save_area[2]; /* 0x00d8 */
|
|
u32 clock_comp_save_area[2]; /* 0x00e0 */
|
|
u32 mcck_interruption_code[2]; /* 0x00e8 */
|
|
u8 pad_0x00f0[0x00f4-0x00f0]; /* 0x00f0 */
|
|
u32 external_damage_code; /* 0x00f4 */
|
|
u32 failing_storage_address; /* 0x00f8 */
|
|
u8 pad_0x00fc[0x0100-0x00fc]; /* 0x00fc */
|
|
u32 st_status_fixed_logout[2]; /* 0x0100 */
|
|
u32 prefixreg_save_area; /* 0x0108 */
|
|
u8 pad_0x0110[0x0120-0x010c]; /* 0x010c */
|
|
u32 access_regs_save_area[16]; /* 0x0120 */
|
|
u32 floating_pt_save_area[8]; /* 0x0160 */
|
|
u32 gpregs_save_area[16]; /* 0x0180 */
|
|
u32 cregs_save_area[16]; /* 0x01c0 */
|
|
u8 pad_0x0200[0x1000 - 0x0200]; /* 0x0200 */
|
|
};
|
|
|
|
struct dfi_lowcore_64 {
|
|
u8 pad_0x0000[0x0084 - 0x0000]; /* 0x0000 */
|
|
u16 cpu_addr; /* 0x0084 */
|
|
u8 pad_0x0086[0x11b0 - 0x0086]; /* 0x0086 */
|
|
u64 vector_save_area_addr; /* 0x11b0 */
|
|
u8 pad_0x11b8[0x1200 - 0x11b8]; /* 0x11b8 */
|
|
u64 floating_pt_save_area[16]; /* 0x1200 */
|
|
u64 gpregs_save_area[16]; /* 0x1280 */
|
|
u32 st_status_fixed_logout[4]; /* 0x1300 */
|
|
u8 pad_0x1310[0x1318-0x1310]; /* 0x1310 */
|
|
u32 prefixreg_save_area; /* 0x1318 */
|
|
u32 fpt_creg_save_area; /* 0x131c */
|
|
u8 pad_0x1320[0x1324-0x1320]; /* 0x1320 */
|
|
u32 tod_progreg_save_area; /* 0x1324 */
|
|
u32 timer_save_area[2]; /* 0x1328 */
|
|
u32 clock_comp_save_area[2]; /* 0x1330 */
|
|
u8 pad_0x1338[0x1340-0x1338]; /* 0x1338 */
|
|
u32 access_regs_save_area[16]; /* 0x1340 */
|
|
u64 cregs_save_area[16]; /* 0x1380 */
|
|
u8 pad_0x1400[0x2000-0x1400]; /* 0x1400 */
|
|
} __packed;
|
|
|
|
static inline u64 dfi_lc_size(enum dfi_arch arch)
|
|
{
|
|
if (arch == DFI_ARCH_64)
|
|
return 0x2000;
|
|
else
|
|
return 0x1000;
|
|
}
|
|
|
|
struct dfi_vxrs {
|
|
u64 low;
|
|
u64 high;
|
|
};
|
|
|
|
struct dfi_cpu {
|
|
struct util_list_node list;
|
|
u64 gprs[16];
|
|
u64 ctrs[16];
|
|
u32 acrs[16];
|
|
u64 fprs[16];
|
|
u32 fpc;
|
|
u64 psw[2];
|
|
u32 prefix;
|
|
u64 timer;
|
|
u64 todcmp;
|
|
u32 todpreg;
|
|
u64 vxrs_low[16];
|
|
struct dfi_vxrs vxrs_high[16];
|
|
u16 cpu_id;
|
|
};
|
|
|
|
struct dfi_cpu_32 {
|
|
u32 gprs[16];
|
|
u32 ctrs[16];
|
|
u32 acrs[16];
|
|
u64 fprs[4];
|
|
u32 psw[2];
|
|
u32 prefix;
|
|
u64 timer;
|
|
u64 todcmp;
|
|
u64 vxrs_low[16];
|
|
struct dfi_vxrs vxrs_high[16];
|
|
};
|
|
|
|
extern void dfi_cpu_64_to_32(struct dfi_cpu_32 *cpu_32, struct dfi_cpu *cpu_64);
|
|
|
|
extern enum dfi_arch dfi_arch(void);
|
|
extern void dfi_arch_set(enum dfi_arch arch);
|
|
extern const char *dfi_arch_str(enum dfi_arch arch);
|
|
|
|
enum dfi_cpu_content {
|
|
DFI_CPU_CONTENT_NONE, /* No register information available */
|
|
DFI_CPU_CONTENT_LC, /* Only lowcore information available */
|
|
DFI_CPU_CONTENT_ALL, /* Complete register information available */
|
|
};
|
|
|
|
#define DFI_CPU_CONTENT_FAC_VX 0x00000001
|
|
extern int dfi_cpu_content_fac_check(int flags);
|
|
extern void dfi_cpu_content_fac_add(int flags);
|
|
|
|
#define dfi_cpu_iterate(cpu) \
|
|
util_list_iterate(dfi_cpu_list(), cpu)
|
|
|
|
extern struct util_list *dfi_cpu_list(void);
|
|
extern void dfi_cpu_info_init(enum dfi_cpu_content content);
|
|
extern struct dfi_cpu *dfi_cpu_alloc(void);
|
|
extern struct dfi_cpu *dfi_cpu(unsigned int cpu_nr);
|
|
extern void dfi_cpu_add(struct dfi_cpu *cpu);
|
|
extern unsigned int dfi_cpu_cnt(void);
|
|
extern enum dfi_cpu_content dfi_cpu_content(void);
|
|
extern int dfi_cpu_add_from_lc(u32 lc_addr);
|
|
|
|
#define DFI_VX_SA_SIZE (32 * 16)
|
|
extern int dfi_cpu_lc_has_vx_sa(void *lc);
|
|
extern void dfi_cpu_vx_copy(void *buf, struct dfi_cpu *cpu);
|
|
|
|
/*
|
|
* Mem chunk functions and definitions
|
|
*/
|
|
struct dfi_mem_chunk;
|
|
|
|
typedef void (*dfi_mem_chunk_read_fn)(struct dfi_mem_chunk *mem_chunk,
|
|
u64 off, void *buf, u64 cnt);
|
|
typedef void (*dfi_mem_chunk_free_fn)(void *data);
|
|
|
|
struct dfi_mem_chunk {
|
|
struct util_list_node list; /* List */
|
|
u64 start; /* Start address in memory */
|
|
u64 end; /* End address in memory */
|
|
u64 size; /* Size of chunk in dump file */
|
|
dfi_mem_chunk_read_fn read_fn; /* Chunk read callback */
|
|
dfi_mem_chunk_free_fn free_fn; /* Free data callback */
|
|
void *data; /* Data for callback */
|
|
u32 volnr; /* Volume id where chunk resides */
|
|
};
|
|
|
|
extern void dfi_mem_chunk_read_zero(struct dfi_mem_chunk *UNUSED(mem_chunk),
|
|
u64 UNUSED(off), void *buf, u64 cnt);
|
|
extern void dfi_mem_chunk_add_vol(u64 start, u64 size, void *data,
|
|
dfi_mem_chunk_read_fn read_fn,
|
|
dfi_mem_chunk_free_fn free_fn,
|
|
u32 volnr);
|
|
extern void dfi_mem_chunk_add(u64 start, u64 size, void *data,
|
|
dfi_mem_chunk_read_fn read_fn,
|
|
dfi_mem_chunk_free_fn free_fn);
|
|
extern void dfi_mem_chunk_virt_add(u64 start, u64 size, void *data,
|
|
dfi_mem_chunk_read_fn read_fn,
|
|
dfi_mem_chunk_free_fn free_fn);
|
|
extern u64 dfi_mem_range(void);
|
|
extern int dfi_mem_range_valid(u64 addr, u64 len);
|
|
extern unsigned int dfi_mem_chunk_cnt(void);
|
|
extern struct dfi_mem_chunk *dfi_mem_chunk_first(void);
|
|
extern struct dfi_mem_chunk *dfi_mem_chunk_last(void);
|
|
extern struct dfi_mem_chunk *dfi_mem_chunk_next(struct dfi_mem_chunk *chunk);
|
|
extern struct dfi_mem_chunk *dfi_mem_chunk_prev(struct dfi_mem_chunk *chunk);
|
|
extern struct dfi_mem_chunk *dfi_mem_chunk_find(u64 addr);
|
|
|
|
extern struct util_list *dfi_mem_chunk_list(void);
|
|
#define dfi_mem_chunk_iterate(mem_chunk) \
|
|
util_list_iterate(dfi_mem_chunk_list(), mem_chunk)
|
|
|
|
/*
|
|
* Dump header attribute set/get functions
|
|
*/
|
|
extern void dfi_attr_time_set(struct timeval *time);
|
|
extern struct timeval *dfi_attr_time(void);
|
|
|
|
extern void dfi_attr_time_end_set(struct timeval *time_end);
|
|
extern struct timeval *dfi_attr_time_end(void);
|
|
|
|
extern void dfi_attr_cpu_id_set(u64 cpu_id);
|
|
extern u64 *dfi_attr_cpu_id(void);
|
|
|
|
extern void dfi_attr_utsname_set(struct new_utsname *utsname);
|
|
extern struct new_utsname *dfi_attr_utsname(void);
|
|
|
|
extern void dfi_attr_dump_method_set(char *dump_method);
|
|
extern char *dfi_attr_dump_method(void);
|
|
|
|
extern void dfi_attr_mem_size_real_set(u64 mem_size_real);
|
|
extern u64 *dfi_attr_mem_size_real(void);
|
|
|
|
extern void dfi_attr_file_size_set(u64 dump_size);
|
|
extern u64 *dfi_attr_file_size(void);
|
|
|
|
extern void dfi_attr_vol_nr_set(unsigned int vol_nr);
|
|
extern unsigned int *dfi_attr_vol_nr(void);
|
|
|
|
extern void dfi_attr_version_set(unsigned int dfi_version);
|
|
extern unsigned int *dfi_attr_dfi_version(void);
|
|
|
|
extern void dfi_attr_build_arch_set(enum dfi_arch build_arch);
|
|
extern enum dfi_arch *dfi_attr_build_arch(void);
|
|
|
|
extern void dfi_attr_real_cpu_cnt_set(u32 real_cpu_cnt);
|
|
extern u32 *dfi_attr_real_cpu_cnt(void);
|
|
|
|
/*
|
|
* DFI external functions
|
|
*/
|
|
extern void dfi_mem_read(u64 addr, void *buf, size_t cnt);
|
|
extern int dfi_mem_read_rc(u64 addr, void *buf, size_t cnt);
|
|
extern void dfi_mem_phys_read(u64 addr, void *buf, size_t cnt);
|
|
extern void dfi_info_print(void);
|
|
|
|
/*
|
|
* DFI feature bits
|
|
*/
|
|
#define DFI_FEAT_SEEK 0x1 /* Necessary for fuse mount */
|
|
#define DFI_FEAT_COPY 0x2 /* Necessary for stdout */
|
|
|
|
extern int dfi_feat_seek(void);
|
|
extern int dfi_feat_copy(void);
|
|
|
|
/*
|
|
* DFI kdump functions
|
|
*/
|
|
extern unsigned long dfi_kdump_base(void);
|
|
|
|
/*
|
|
* DFI vmcoreinfo functions
|
|
*/
|
|
extern void dfi_vmcoreinfo_init(void);
|
|
extern char *dfi_vmcoreinfo_get(void);
|
|
extern int dfi_vmcoreinfo_tag(char *str, int len, const char *sym);
|
|
extern int dfi_vmcoreinfo_symbol(unsigned long *val, const char *sym);
|
|
extern int dfi_vmcoreinfo_offset(unsigned long *offs, const char *sym);
|
|
extern int dfi_vmcoreinfo_size(unsigned long *size, const char *sym);
|
|
extern int dfi_vmcoreinfo_length(unsigned long *len, const char *sym);
|
|
extern int dfi_vmcoreinfo_val(unsigned long *val, const char *sym);
|
|
|
|
/*
|
|
* DFI operations
|
|
*/
|
|
struct dfi {
|
|
const char *name;
|
|
int (*init)(void);
|
|
void (*exit)(void);
|
|
void (*info_dump)(void);
|
|
int feat_bits;
|
|
};
|
|
|
|
extern const char *dfi_name(void);
|
|
extern int dfi_init(void);
|
|
extern void dfi_exit(void);
|
|
|
|
/*
|
|
* Dump access
|
|
*/
|
|
extern struct zg_fh *dfi_dump_open(const char *path);
|
|
|
|
/*
|
|
* Live dump memory magic
|
|
*/
|
|
extern u64 dfi_live_dump_magic;
|
|
|
|
/*
|
|
* Dump methods
|
|
*/
|
|
#define DFI_DUMP_METHOD_LIVE "live"
|
|
|
|
#endif /* DFI_H */
|