Subject: Fix segmentation violation in symbol_search

Fix a possible segmentation violation in crash if a module name
is not NUL-terminated. Although store_module_symbols_v2 complains
about an overly long module name, there are several problems
with the current approach:

1. The maximum size is hard-wired in defs.h and the current
   constant doesn't even match struct module's name field size
   on any architecture.

2. If the string is too long, it is probably not NUL-terminated,
   so we can't use strlen() on it.

3. Even though only the first MAX_MOD_NAME-1 bytes are copied
   to struct load_module, the _MODULE_* pseudo-symbol names are
   generated from the unabridged module name.  As a consequence,
   they are not found further on in the loop at the end of
   store_module_symbols_v2, so lm->mod_symtable remains NULL
   for that module.  The symbol_search() function is not
   prepared for that situation and tries to dereference that
   NULL pointer here:

		sp = lm->mod_symtable;
                sp_end = lm->mod_symend;

                for ( ; sp <= sp_end; sp++) {
                	if (!pseudos && MODULE_PSEUDO_SYMBOL(sp))
							    ^^^^

Signed-off-by: Petr Tesarik <ptesarik@suse.cz>

---
 symbols.c |   30 +++++++++++++++++++++---------
 1 file changed, 21 insertions(+), 9 deletions(-)

--- a/symbols.c
+++ b/symbols.c
@@ -1337,6 +1337,7 @@ store_module_symbols_v2(ulong total, int
 	char *strbuf, *modbuf, *modsymbuf;
 	struct syment *sp;
 	ulong first, last;
+	size_t max_mod_name;
 
 	st->mods_installed = mods_installed;
 
@@ -1367,6 +1368,16 @@ store_module_symbols_v2(ulong total, int
 	    (st->mods_installed, sizeof(struct load_module))) == NULL)
 		error(FATAL, "load_module array malloc: %s\n", strerror(errno));
 
+	max_mod_name = MEMBER_SIZE("module", "name");
+	if (max_mod_name > MAX_MOD_NAME) {
+		error(INFO, "size of module.name is larger than MAX_MOD_NAME"
+			" (%d > %d)", max_mod_name, MAX_MOD_NAME);
+		max_mod_name = MAX_MOD_NAME;
+	} else if (max_mod_name <= 0) {
+		error(INFO, "cannot determine max module name length");
+		max_mod_name = MAX_MOD_NAME;
+	}
+
 	modbuf = GETBUF(SIZE(module));
 	modsymbuf = NULL;
 	m = mcnt = mod_next = 0;
@@ -1396,13 +1407,14 @@ store_module_symbols_v2(ulong total, int
 		lm->mod_base = ULONG(modbuf + OFFSET(module_module_core));
 		lm->module_struct = mod;
 		lm->mod_size = size;
-        	if (strlen(mod_name) < MAX_MOD_NAME)
+		if (memchr(mod_name, 0, max_mod_name))
                 	strcpy(lm->mod_name, mod_name);
         	else {
-			error(INFO, 
-			    "module name greater than MAX_MOD_NAME: %s\n",
-				mod_name);
-                	strncpy(lm->mod_name, mod_name, MAX_MOD_NAME-1);
+                	memcpy(lm->mod_name, mod_name, max_mod_name-1);
+			lm->mod_name[max_mod_name-1] = '\0';
+			error(INFO,
+			    "module name too long: %s (truncated)\n",
+				lm->mod_name);
 		}
 		if (CRASHDEBUG(3))
 			fprintf(fp, 
@@ -1434,7 +1446,7 @@ store_module_symbols_v2(ulong total, int
 		st->ext_module_symtable[mcnt].value = lm->mod_base;
 		st->ext_module_symtable[mcnt].type = 'm';
 		st->ext_module_symtable[mcnt].flags |= MODULE_SYMBOL;
-		sprintf(buf2, "%s%s", "_MODULE_START_", mod_name);
+		sprintf(buf2, "%s%s", "_MODULE_START_", lm->mod_name);
 		namespace_ctl(NAMESPACE_INSTALL, &st->ext_module_namespace,
 			&st->ext_module_symtable[mcnt], buf2);
 		lm_mcnt = mcnt;
@@ -1444,7 +1456,7 @@ store_module_symbols_v2(ulong total, int
 			st->ext_module_symtable[mcnt].value = lm->mod_init_module_ptr;
 			st->ext_module_symtable[mcnt].type = 'm';
 			st->ext_module_symtable[mcnt].flags |= MODULE_SYMBOL;
-			sprintf(buf3, "%s%s", "_MODULE_INIT_START_", mod_name);
+			sprintf(buf3, "%s%s", "_MODULE_INIT_START_", lm->mod_name);
 			namespace_ctl(NAMESPACE_INSTALL, 
 					&st->ext_module_namespace,
 					&st->ext_module_symtable[mcnt], buf3);
@@ -1627,7 +1639,7 @@ store_module_symbols_v2(ulong total, int
 		st->ext_module_symtable[mcnt].value = lm->mod_base + size;
 		st->ext_module_symtable[mcnt].type = 'm';
 		st->ext_module_symtable[mcnt].flags |= MODULE_SYMBOL;
-		sprintf(buf2, "%s%s", "_MODULE_END_", mod_name);
+		sprintf(buf2, "%s%s", "_MODULE_END_", lm->mod_name);
                 namespace_ctl(NAMESPACE_INSTALL, 
 			&st->ext_module_namespace,
                         &st->ext_module_symtable[mcnt], buf2);
@@ -1637,7 +1649,7 @@ store_module_symbols_v2(ulong total, int
 			st->ext_module_symtable[mcnt].value = lm->mod_init_module_ptr + lm->mod_init_size;
 			st->ext_module_symtable[mcnt].type = 'm';
 			st->ext_module_symtable[mcnt].flags |= MODULE_SYMBOL;
-			sprintf(buf4, "%s%s", "_MODULE_INIT_END_", mod_name);
+			sprintf(buf4, "%s%s", "_MODULE_INIT_END_", lm->mod_name);
 			namespace_ctl(NAMESPACE_INSTALL, 
 					&st->ext_module_namespace,
 					&st->ext_module_symtable[mcnt], buf4);
