[PATCH v2 04/14] Verify and read VMCORE(s) in sadump-related formats

HATAYAMA Daisuke
2011-10-28T09:48:31Z

Try to read VMCORE(s) as sadump-related formats: single partition,
diskset or media backup and verify their header information. If the
VMCORE(s) doesn't belong to each of them, the check continues to
checking of ELF format.

Signed-off-by: HATAYAMA Daisuke <d.hatayama@jp.fujitsu.com>
---

makedumpfile.c | 17 +-
sadump_info.c | 480 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
sadump_info.h | 10 +
3 files changed, 500 insertions(+), 7 deletions(-)

diff --git a/makedumpfile.c b/makedumpfile.c
index 8a3a3d3..7057009 100644
--- a/makedumpfile.c
+++ b/makedumpfile.c
@@ -628,11 +628,16 @@ open_dump_memory(void)
if (status == TRUE) {
info->flag_refiltering = TRUE;
return get_kdump_compressed_header_info(info->name_memory);
- } else if (status == FALSE) {
- return TRUE;
- } else {
- return FALSE;
}
+
+ status = check_and_get_sadump_header_info(info->name_memory);
+ if (status == TRUE)
+ return TRUE;
+
+ if (status == ERROR)
+ return TRUE;
+
+ return FALSE;
}

int
@@ -3007,7 +3012,7 @@ dump_dmesg()
if (!open_files_for_creating_dumpfile())
return FALSE;

- if (!info->flag_refiltering) {
+ if (!info->flag_refiltering && !info->flag_sadump) {
if (!get_elf_info(info->fd_memory, info->name_memory))
return FALSE;
}
@@ -5757,7 +5762,7 @@ create_dumpfile(void)
if (!open_files_for_creating_dumpfile())
return FALSE;

- if (!info->flag_refiltering) {
+ if (!info->flag_refiltering && !info->flag_sadump) {
if (!get_elf_info(info->fd_memory, info->name_memory))
return FALSE;
}
diff --git a/sadump_info.c b/sadump_info.c
index c94d233..2f66148 100644
--- a/sadump_info.c
+++ b/sadump_info.c
@@ -20,6 +20,7 @@

#include "makedumpfile.h"
#include "print_info.h"
+#include "sadump_mod.h"

struct sadump_diskset_info {
char *name_memory;
@@ -40,10 +41,470 @@ struct sadump_info {
unsigned long data_offset;
};

+static char *guid_to_str(efi_guid_t *guid, char *buf, size_t buflen);
+static struct tm *efi_time_t_to_tm(const efi_time_t *e);
+static int verify_magic_number(uint32_t magicnum[DUMP_PART_HEADER_MAGICNUM_SIZE]);
+static int read_device(void *buf, size_t bytes, ulong *offset);
+static int read_device_diskset(struct sadump_diskset_info *sdi, void *buf,
+ size_t bytes, ulong *offset);
+static int read_sadump_header(char *filename);
+static int read_sadump_header_diskset(int diskid, struct sadump_diskset_info *sdi);
+
static struct sadump_info sadump_info = {};
static struct sadump_info *si = &sadump_info;

int
+check_and_get_sadump_header_info(char *filename)
+{
+ int i;
+
+ if (!read_sadump_header(filename))
+ return FALSE;
+
+ if (info->flag_sadump_diskset && info->flag_sadump == SADUMP_DISKSET) {
+
+ si->diskset_info[0].fd_memory = info->fd_memory;
+ si->diskset_info[0].sph_memory = si->sph_memory;
+ si->diskset_info[0].data_offset = si->data_offset;
+
+ for (i = 1; i < si->num_disks; ++i) {
+ struct sadump_diskset_info *sdi =
+ &si->diskset_info[i];
+
+ if ((sdi->fd_memory =
+ open(sdi->name_memory, O_RDONLY)) < 0) {
+ ERRMSG("Can't open the dump diskset "
+ "memory(%s). %s\n", sdi->name_memory,
+ strerror(errno));
+ return FALSE;
+ }
+
+ if (!read_sadump_header_diskset(i, sdi))
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+static char *
+guid_to_str(efi_guid_t *guid, char *buf, size_t buflen)
+{
+ snprintf(buf, buflen,
+ "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
+ guid->data1, guid->data2, guid->data3,
+ guid->data4[0], guid->data4[1], guid->data4[2],
+ guid->data4[3], guid->data4[4], guid->data4[5],
+ guid->data4[6], guid->data4[7]);
+
+ return buf;
+}
+
+static struct tm *
+efi_time_t_to_tm(const efi_time_t *e)
+{
+ static struct tm t;
+ time_t ti;
+
+ memset(&t, 0, sizeof(t));
+
+ t.tm_sec = e->second;
+ t.tm_min = e->minute;
+ t.tm_hour = e->hour;
+ t.tm_mday = e->day;
+ t.tm_mon = e->month - 1;
+ t.tm_year = e->year - 1900;
+
+ if (e->timezone != EFI_UNSPECIFIED_TIMEZONE)
+ t.tm_hour += e->timezone;
+
+ else
+ DEBUG_MSG("sadump: timezone information is missing\n");
+
+ ti = mktime(&t);
+ if (ti == (time_t)-1)
+ return &t;
+
+ return localtime_r(&ti, &t);
+}
+
+static int
+verify_magic_number(uint32_t magicnum[DUMP_PART_HEADER_MAGICNUM_SIZE])
+{
+ int i;
+
+ for (i = 1; i < DUMP_PART_HEADER_MAGICNUM_SIZE; ++i)
+ if (magicnum[i] != (magicnum[i - 1] + 7) * 11)
+ return FALSE;
+
+ return TRUE;
+}
+
+static int
+read_device(void *buf, size_t bytes, ulong *offset)
+{
+ if (lseek(info->fd_memory, *offset, SEEK_SET) < 0) {
+ ERRMSG("Can't seek a file(%s). %s\n",
+ info->name_memory, strerror(errno));
+ return FALSE;
+ }
+ if (read(info->fd_memory, buf, bytes) != bytes) {
+ ERRMSG("Can't read a file(%s). %s\n",
+ info->name_memory, strerror(errno));
+ return FALSE;
+ }
+ *offset += bytes;
+ return TRUE;
+}
+
+static int
+read_device_diskset(struct sadump_diskset_info *sdi, void *buf,
+ size_t bytes, unsigned long *offset)
+{
+ if (lseek(sdi->fd_memory, *offset, SEEK_SET) < 0) {
+ ERRMSG("Can't seek a file(%s). %s\n",
+ sdi->name_memory, strerror(errno));
+ return FALSE;
+ }
+ if (read(sdi->fd_memory, buf, bytes) != bytes) {
+ ERRMSG("Can't read a file(%s). %s\n",
+ sdi->name_memory, strerror(errno));
+ return FALSE;
+ }
+ *offset += bytes;
+ return TRUE;
+}
+
+static int
+read_sadump_header(char *filename)
+{
+ struct sadump_part_header *sph = NULL;
+ struct sadump_header *sh = NULL;
+ struct sadump_disk_set_header *sdh = NULL;
+ struct sadump_media_header *smh = NULL;
+ unsigned long offset = 0, sub_hdr_offset;
+ unsigned long block_size = SADUMP_DEFAULT_BLOCK_SIZE;
+ unsigned long bitmap_len, dumpable_bitmap_len;
+ enum sadump_format_type flag_sadump;
+ uint32_t smram_cpu_state_size = 0;
+ char guid[33];
+
+ if ((si->sph_memory = malloc(SADUMP_DEFAULT_BLOCK_SIZE)) == NULL) {
+ ERRMSG("Can't allocate memory for partition header buffer: "
+ "%s\n", strerror(errno));
+ return FALSE;
+ }
+
+ if ((si->sh_memory = malloc(SADUMP_DEFAULT_BLOCK_SIZE)) == NULL) {
+ ERRMSG("Can't allocate memory for dump header buffer: "
+ "%s\n", strerror(errno));
+ return FALSE;
+ }
+
+ if ((si->sdh_memory = malloc(SADUMP_DEFAULT_BLOCK_SIZE)) == NULL) {
+ ERRMSG("Can't allocate memory for disk set header buffer: "
+ "%s\n", strerror(errno));
+ return FALSE;
+ }
+
+ if ((si->smh_memory = malloc(SADUMP_DEFAULT_BLOCK_SIZE)) == NULL) {
+ ERRMSG("Can't allocate memory for media header buffer: "
+ "%s\n", strerror(errno));
+ return FALSE;
+ }
+
+ sph = si->sph_memory;
+ sh = si->sh_memory;
+ sdh = si->sdh_memory;
+ smh = si->smh_memory;
+
+restart:
+ if (block_size < 0)
+ return FALSE;
+
+ if (!read_device(sph, block_size, &offset))
+ return ERROR;
+
+ if (sph->signature1 == SADUMP_SIGNATURE1 &&
+ sph->signature2 == SADUMP_SIGNATURE2) {
+
+ if (sph->set_disk_set == 0) {
+
+ flag_sadump = SADUMP_SINGLE_PARTITION;
+
+ DEBUG_MSG("sadump: read dump device as single partition\n");
+
+ } else {
+
+ flag_sadump = SADUMP_DISKSET;
+
+ DEBUG_MSG("sadump: read dump device as diskset\n");
+
+ }
+
+ } else {
+
+ offset = 0;
+
+ if (!read_device(smh, block_size, &offset))
+ return ERROR;
+
+ if (!read_device(sph, block_size, &offset))
+ return ERROR;
+
+ if (sph->signature1 != SADUMP_SIGNATURE1 ||
+ sph->signature2 != SADUMP_SIGNATURE2) {
+
+ DEBUG_MSG("sadump: does not have partition header\n");
+
+ flag_sadump = SADUMP_UNKNOWN;
+
+ DEBUG_MSG("sadump: read dump device as unknown format\n");
+
+ goto out;
+ }
+
+ flag_sadump = SADUMP_MEDIA_BACKUP;
+
+ DEBUG_MSG("sadump: read dump device as media backup format\n");
+
+ }
+
+ if (!verify_magic_number(sph->magicnum)) {
+ DEBUG_MSG("sadump: invalid magic number\n");
+ return FALSE;
+ }
+
+ if (flag_sadump == SADUMP_DISKSET) {
+ uint32_t header_blocks;
+ size_t header_size;
+
+ if (sph->set_disk_set != 1) {
+ DEBUG_MSG("sadump: id of this disk is %d\n",
+ sph->set_disk_set);
+ return FALSE;
+ }
+
+ if (!read_device(&header_blocks, sizeof(uint32_t),
+ &offset))
+ return FALSE;
+
+ offset -= sizeof(uint32_t);
+ header_size = header_blocks * block_size;
+
+ if (header_size > block_size) {
+ sdh = realloc(sdh, header_size);
+ if (!sdh) {
+ ERRMSG("Can't allocate memory for disk "
+ "set memory\n");
+ return FALSE;
+ }
+ }
+
+ if (!read_device(sdh, header_size, &offset))
+ return ERROR;
+
+ DEBUG_MSG("sadump: the diskset consists of %u disks\n",
+ sdh->disk_num);
+
+ }
+
+ if (!read_device(sh, block_size, &offset))
+ return FALSE;
+
+ sub_hdr_offset = offset;
+
+ if (strncmp(sh->signature, SADUMP_SIGNATURE, 8) != 0) {
+ DEBUG_MSG("sadump: does not have dump header\n");
+ return FALSE;
+ }
+
+ if (flag_sadump == SADUMP_MEDIA_BACKUP) {
+
+ if (memcmp(&sph->sadump_id, &smh->sadump_id,
+ sizeof(efi_guid_t)) != 0) {
+ DEBUG_MSG("sadump: system ID mismatch\n");
+ DEBUG_MSG(" partition header: %s\n",
+ guid_to_str(&sph->sadump_id, guid,
+ sizeof(guid)));
+ DEBUG_MSG(" media header: %s\n",
+ guid_to_str(&smh->sadump_id, guid,
+ sizeof(guid)));
+ return FALSE;
+ }
+
+ if (memcmp(&sph->disk_set_id, &smh->disk_set_id,
+ sizeof(efi_guid_t)) != 0) {
+ DEBUG_MSG("sadump: disk set ID mismtch\n");
+ DEBUG_MSG(" partition header: %s\n",
+ guid_to_str(&sph->disk_set_id, guid,
+ sizeof(guid)));
+ DEBUG_MSG(" media header: %s\n",
+ guid_to_str(&smh->disk_set_id, guid,
+ sizeof(guid)));
+ return FALSE;
+ }
+
+ if (memcmp(&sph->time_stamp, &smh->time_stamp,
+ sizeof(efi_time_t)) != 0) {
+ DEBUG_MSG("sadump: time stamp mismatch\n");
+ DEBUG_MSG(" partition header: %s",
+ asctime(efi_time_t_to_tm(&sph->time_stamp)));
+ DEBUG_MSG(" media header: %s",
+ asctime(efi_time_t_to_tm(&smh->time_stamp)));
+ }
+
+ if (smh->sequential_num != 1) {
+ DEBUG_MSG("sadump: first media file has sequential "
+ "number %d\n", smh->sequential_num);
+ return FALSE;
+ }
+
+ }
+
+ if (sh->block_size != block_size) {
+ block_size = sh->block_size;
+ offset = 0;
+ goto restart;
+ }
+
+ if (sh->sub_hdr_size > 0) {
+ if (!read_device(&smram_cpu_state_size, sizeof(uint32_t),
+ &offset)) {
+ DEBUG_MSG("sadump: cannot read SMRAM CPU STATE size\n");
+ return FALSE;
+ }
+ smram_cpu_state_size /= sh->nr_cpus;
+
+ offset -= sizeof(uint32_t);
+ offset += sh->sub_hdr_size * block_size;
+ }
+
+ if (!sh->bitmap_blocks) {
+ DEBUG_MSG("sadump: bitmap_blocks is zero\n");
+ return FALSE;
+ }
+
+ if (!sh->dumpable_bitmap_blocks) {
+ DEBUG_MSG("sadump: dumpable_bitmap_blocks is zero\n");
+ return FALSE;
+ }
+
+ bitmap_len = block_size * sh->bitmap_blocks;
+ dumpable_bitmap_len = block_size * sh->dumpable_bitmap_blocks;
+
+ si->sub_hdr_offset = sub_hdr_offset;
+ si->smram_cpu_state_size = smram_cpu_state_size;
+ si->data_offset = offset + bitmap_len + dumpable_bitmap_len;
+
+out:
+ switch (flag_sadump) {
+ case SADUMP_SINGLE_PARTITION:
+ DEBUG_MSG("sadump: single partition configuration\n");
+ break;
+ case SADUMP_DISKSET:
+ DEBUG_MSG("sadump: diskset configuration with %d disks\n",
+ sdh->disk_num);
+ break;
+ case SADUMP_MEDIA_BACKUP:
+ DEBUG_MSG("sadump: media backup file\n");
+ break;
+ case SADUMP_UNKNOWN:
+ DEBUG_MSG("sadump: unknown format\n");
+ break;
+ }
+
+ info->flag_sadump = flag_sadump;
+
+ return TRUE;
+}
+
+static int
+read_sadump_header_diskset(int diskid, struct sadump_diskset_info *sdi)
+{
+ struct sadump_part_header *sph = NULL;
+ unsigned long offset = 0;
+ char guid[33];
+
+ if ((sph = malloc(si->sh_memory->block_size)) == NULL) {
+ ERRMSG("Can't allocate memory for partition header buffer. "
+ "%s\n", strerror(errno));
+ goto error;
+ }
+
+ if (!read_device_diskset(sdi, sph, si->sh_memory->block_size,
+ &offset))
+ goto error;
+
+ if (sph->signature1 != SADUMP_SIGNATURE1 ||
+ sph->signature2 != SADUMP_SIGNATURE2) {
+ DEBUG_MSG("sadump: does not have partition header\n");
+ free(sph);
+ goto error;
+ }
+
+ if (memcmp(&si->sph_memory->sadump_id, &sph->sadump_id,
+ sizeof(efi_guid_t)) != 0) {
+ DEBUG_MSG("sadump: system ID mismatch\n");
+ DEBUG_MSG(" partition header on disk #1: %s\n",
+ guid_to_str(&si->sph_memory->sadump_id, guid,
+ sizeof(guid)));
+ DEBUG_MSG(" partition header on disk #%d: %s\n", diskid,
+ guid_to_str(&sph->sadump_id, guid, sizeof(guid)));
+ goto error;
+ }
+
+ if (memcmp(&si->sph_memory->disk_set_id, &sph->disk_set_id,
+ sizeof(efi_guid_t)) != 0) {
+ DEBUG_MSG("sadump: disk set ID mismatch\n");
+ DEBUG_MSG(" partition header on disk #1: %s\n",
+ guid_to_str(&si->sph_memory->disk_set_id, guid,
+ sizeof(guid)));
+ DEBUG_MSG(" partition header on disk #%d: %s\n", diskid,
+ guid_to_str(&sph->disk_set_id, guid, sizeof(guid)));
+ goto error;
+ }
+
+ if (memcmp(&si->sdh_memory->vol_info[diskid-1].id, &sph->vol_id,
+ sizeof(efi_guid_t)) != 0) {
+ DEBUG_MSG("sadump: volume ID mismatch\n");
+ DEBUG_MSG(" disk set header on disk #1: %s\n",
+ guid_to_str(&si->sdh_memory->vol_info[diskid-1].id,
+ guid, sizeof(guid)));
+ DEBUG_MSG(" partition header on disk #%d: %s\n",
+ diskid+1,
+ guid_to_str(&sph->vol_id, guid, sizeof(guid)));
+ goto error;
+ }
+
+ if (memcmp(&si->sph_memory->time_stamp, &sph->time_stamp,
+ sizeof(efi_time_t)) != 0) {
+ DEBUG_MSG("sadump time stamp mismatch\n");
+ DEBUG_MSG(" partition header on disk #1: %s\n",
+ asctime(efi_time_t_to_tm
+ (&si->sph_memory->time_stamp)));
+ DEBUG_MSG(" partition header on disk #%d: %s\n",
+ diskid, asctime(efi_time_t_to_tm(&sph->time_stamp)));
+ }
+
+ if (diskid+1 != sph->set_disk_set) {
+ DEBUG_MSG("sadump: wrong disk order; #%d expected but #%d given\n",
+ diskid+1, sph->set_disk_set);
+ goto error;
+ }
+
+ sdi->sph_memory = sph;
+ sdi->data_offset = si->sh_memory->block_size;
+
+ return TRUE;
+
+error:
+ free(sph);
+
+ return FALSE;
+}
+
+int
sadump_add_diskset_info(char *name_memory)
{
si->num_disks++;
@@ -71,8 +532,25 @@ sadump_head_disk_name_memory(void)
void
free_sadump_info(void)
{
- if (si->diskset_info)
+ if (si->sph_memory)
+ free(si->sph_memory);
+ if (si->sh_memory)
+ free(si->sh_memory);
+ if (si->sdh_memory)
+ free(si->sdh_memory);
+ if (si->smh_memory)
+ free(si->smh_memory);
+ if (si->diskset_info) {
+ int i;
+
+ for (i = 1; i < si->num_disks; ++i) {
+ if (si->diskset_info[i].fd_memory)
+ close(si->diskset_info[i].fd_memory);
+ if (si->diskset_info[i].sph_memory)
+ free(si->diskset_info[i].sph_memory);
+ }
free(si->diskset_info);
+ }
}

#endif /* defined(__x86__) && defined(__x86_64__) */
diff --git a/sadump_info.h b/sadump_info.h
index 863956d..c54d29f 100644
--- a/sadump_info.h
+++ b/sadump_info.h
@@ -24,6 +24,7 @@

#if defined(__x86__) || defined(__x86_64__)

+int check_and_get_sadump_header_info(char *filename);
int sadump_add_diskset_info(char *name_memory);
char *sadump_head_disk_name_memory(void);
void free_sadump_info(void);
@@ -35,6 +36,15 @@ static inline int sadump_is_supported_arch(void)

#else

+static inline int check_and_get_sadump_header_info(char *filename)
+{
+ info->flag_sadump = SADUMP_UNKNOWN;
+
+ DEBUG_MSG("sadump: unsupported architecture\n");
+
+ return TRUE;
+}
+
static inline int sadump_add_diskset_info(char *name_memory)
{
return TRUE;