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

HATAYAMA Daisuke d.hatayama at jp.fujitsu.com
Fri Oct 28 05:48:26 EDT 2011


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 at 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;




More information about the kexec mailing list