File lcrash-sanity-check of Package lcrash
From: Bernhard Walle <bwalle@suse.de>
Subject: [PATCH] Check for the validity of mapfile early
This patch is to prevent using of wrong mapfiles for debugging. It just reads
the value of linux_banner very early during vtop initialisation. We know that
linux_banner must start with "Linux version" and it's unlikely to change in
future.
Mostly, if wrong mapfiles are used, they're completely wrong. So we read
garbage here, can detect it and the user gets a clear output message instead of
just hangs and crashes.
If the check is passed, it's not 100 % that the mapfile is valid. Also, there
might be a risk that the memory region around linux_banner is corrupted and the
rest is ok. The probability is very low, and for this case the user can just
continue debugging -- but he has been warned!
Signed-off-by: Bernhard Walle <bwalle@suse.de>
---
lib/libklib/include/kl_mem.h | 5 ++
lib/libklib/kl_kern.c | 85 +++++++++++++++++++++++++++++++++++++++++++
lib/libklib/kl_kern_i386.c | 16 ++++++++
lib/libklib/kl_kern_ia64.c | 5 ++
lib/libklib/kl_kern_x86_64.c | 16 +++++++-
5 files changed, 126 insertions(+), 1 deletion(-)
--- a/lib/libklib/include/kl_mem.h
+++ b/lib/libklib/include/kl_mem.h
@@ -98,4 +98,9 @@ kaddr_t kl_next_valid_physaddr(kaddr_t);
kaddr_t kl_fix_vaddr(kaddr_t, size_t);
int kl_init_virtop(void);
+/*
+ * other stuff
+ */
+int kl_linux_banner_valid(kaddr_t (*simple_vtop)(kaddr_t));
+
#endif /* __KL_MEM_H */
--- a/lib/libklib/kl_kern.c
+++ b/lib/libklib/kl_kern.c
@@ -49,6 +49,91 @@ kl_valid_physmem(kaddr_t addr, int size)
return(1);
}
+static uint8_t
+kl_read_uint8_simple(kaddr_t (*simple_vtop)(kaddr_t), kaddr_t vaddr)
+{
+ if (simple_vtop) {
+ kaddr_t paddr = simple_vtop(vaddr);
+ return KLP->dump->func.read_uint8(paddr);
+ } else {
+ return KLP->dump->func.vread_uint8(vaddr);
+ }
+}
+
+static kaddr_t
+kl_read_ptr_simple(kaddr_t (*simple_vtop)(kaddr_t), kaddr_t vaddr)
+{
+ if (simple_vtop) {
+ kaddr_t paddr = simple_vtop(vaddr);
+ return KLP->dump->func.read_ptr(paddr);
+ } else {
+ return KLP->dump->func.vread_ptr(vaddr);
+ }
+}
+
+/*
+ * Name: kl_linux_banner_valid()
+ * Func: This function checks if the global symbol "linux_banner" contains valid
+ * data, i.e. starts with "Linux version". This is to simply check if the
+ * given mapfile fits to the memory dump corefile. Wrong mapfiles can
+ * lead to vaious strange error messages afterwards, and this should be
+ * a clear indicator to avoid strange error messages and give a clear
+ * message.
+ * The function returns FALSE if the value is invalid, and TRUE if it's valid.
+ */
+int
+kl_linux_banner_valid(kaddr_t (*simple_vtop)(kaddr_t))
+{
+ const char reference[] = "Linux version";
+ const char *refptr;
+ syment_t *sp;
+ kaddr_t addr;
+ kaddr_t location;
+ int check_valid;
+
+ sp = kl_lkup_symname("linux_banner");
+ if (!sp) {
+ fprintf(KL_ERRORFP, "Lookup of linux_banner has failed\n");
+ return(0);
+ }
+ addr = sp->s_addr;
+
+
+ /*
+ * try char linux_banner[] first (new kernels)
+ */
+
+ check_valid = 1;
+ location = addr;
+ refptr = reference;
+ while (*refptr) {
+ uint8_t val = kl_read_uint8_simple(simple_vtop, location++);
+ if (*refptr++ != (char)val) {
+ check_valid = 0;
+ break;
+ }
+ }
+
+ /*
+ * and now try char *linux_banner (old kernels)
+ */
+ if (!check_valid) {
+ location = kl_read_ptr_simple(simple_vtop, addr);
+ refptr = reference;
+ check_valid = 1;
+
+ while (*refptr) {
+ uint8_t val = kl_read_uint8_simple(simple_vtop, location++);
+ if (*refptr++ != (char)val) {
+ check_valid = 0;
+ break;
+ }
+ }
+ }
+
+ return check_valid;
+}
+
/*
* Name: kl_valid_physaddr()
* Func: Returns 1 if a physical address represents valid physical
--- a/lib/libklib/kl_kern_i386.c
+++ b/lib/libklib/kl_kern_i386.c
@@ -90,6 +90,17 @@ kl_fix_vaddr_i386(kaddr_t vaddr, size_t
}
/*
+ * Name: simple_vtop
+ * Func: Simple virtual to physical address translation if the virtual address
+ * is in kernel text
+ */
+static kaddr_t
+simple_vtop(kaddr_t vaddr)
+{
+ return vaddr - KL_PAGE_OFFSET_I386;
+}
+
+/*
* Name: kl_init_virtop_i386()
* Func: initialize virtual to physical address translation
* This function must at least initialize high_memory and init_mm.
@@ -105,6 +116,11 @@ kl_init_virtop_i386(void)
return ret;
}
+ if (!kl_linux_banner_valid(simple_vtop)) {
+ fprintf(KL_ERRORFP, "\nlinux_banner contains invalid data - "
+ "most likely your mapfile is invalid.");
+ }
+
/* Get the cr4 settings. This will tell us if the system is PAE enabled
*
*/
--- a/lib/libklib/kl_kern_ia64.c
+++ b/lib/libklib/kl_kern_ia64.c
@@ -911,6 +911,11 @@ kl_init_virtop_ia64(void)
} else {
VMALLOC_END = 0xafffffffffffffff;
}
+
+ if (!kl_linux_banner_valid(simple_vtop)) {
+ fprintf(KL_ERRORFP, "\nlinux_banner contains invalid data - "
+ "most likely your mapfile is invalid.");
+ }
check_arch_ia64();
--- a/lib/libklib/kl_kern_x86_64.c
+++ b/lib/libklib/kl_kern_x86_64.c
@@ -94,6 +94,17 @@ kl_fix_vaddr_x86_64(kaddr_t vaddr, size_
}
/*
+ * Name: simple_vtop
+ * Func: Simple virtual to physical address translation if the virtual address
+ * is in kernel text
+ */
+static kaddr_t
+simple_vtop(kaddr_t vaddr)
+{
+ return vaddr - KL_START_KERNEL_map_X86_64;
+}
+
+/*
* Name: kl_init_virtop_x86_64()
* Func: initialize virtual to physical address translation
* This function must at least initialize high_memory and init_mm.
@@ -122,7 +133,10 @@ kl_init_virtop_x86_64(void)
KL_HIGH_MEMORY = (kaddr_t) -1;
}
-
+ if (!kl_linux_banner_valid(simple_vtop)) {
+ fprintf(KL_ERRORFP, "\nlinux_banner contains invalid data - "
+ "most likely your mapfile is invalid.");
+ }
/* Get the address of init_mm and convert it to a physical address
* so that we can make direct calls to kl_readmem(). We make a call