diff --git a/Makefile b/Makefile index 20e9c70..558c017 100644 --- a/Makefile +++ b/Makefile @@ -45,9 +45,10 @@ MAN_OWNER = root SYSLOGD_PIDNAME = -DSYSLOGD_PIDNAME=\"syslogd.pid\" SYSLOGD_FLAGS= -DSYSLOG_INET -DSYSLOG_UNIXAF -DNO_SCCS ${FSSTND} \ - ${SYSLOGD_PIDNAME} -DDEBRELEASE=\"$(revision)\" + ${SYSLOGD_PIDNAME} SYSLOG_FLAGS= -DALLOW_KERNEL_LOGGING -KLOGD_FLAGS = ${FSSTND} ${KLOGD_START_DELAY} -DDEBRELEASE=\"$(revision)\" +KLOGD_FLAGS = ${FSSTND} ${KLOGD_START_DELAY} +DEB = .c.o: ${CC} ${CFLAGS} -c $*.c @@ -69,13 +70,13 @@ syslog_tst: syslog_tst.o ${CC} ${LDFLAGS} -o syslog_tst syslog_tst.o syslogd.o: syslogd.c version.h - ${CC} ${CFLAGS} ${SYSLOGD_FLAGS} -c syslogd.c + ${CC} ${CFLAGS} ${SYSLOGD_FLAGS} $(DEB) -c syslogd.c syslog.o: syslog.c ${CC} ${CFLAGS} ${SYSLOG_FLAGS} -c syslog.c klogd.o: klogd.c klogd.h version.h - ${CC} ${CFLAGS} ${KLOGD_FLAGS} -c klogd.c + ${CC} ${CFLAGS} ${KLOGD_FLAGS} $(DEB) -c klogd.c ksym.o: ksym.c klogd.h ${CC} ${CFLAGS} ${KLOGD_FLAGS} -c ksym.c diff --git a/klogd.c b/klogd.c index 6ff0f53..2f062e9 100644 --- a/klogd.c +++ b/klogd.c @@ -141,11 +141,6 @@ * termination cleanup sequence. This minimizes the potential for * conflicting pidfiles causing immediate termination at boot time. * - * Sun May 12 12:18:21 MET DST 1996: Martin Schulze - * Corrected incorrect/insecure use of strpbrk for a not necessarily - * null-terminated buffer. Used a patch from Chris Hanson - * (cph@martigny.ai.mit.edu), thanks. - * * Wed Aug 21 09:13:03 CDT 1996: Dr. Wettstein * Added ability to reload static symbols and kernel module symbols * under control of SIGUSR1 and SIGUSR2 signals. @@ -158,6 +153,20 @@ * * Added the -i and -I command line switches to signal the currently * executing daemon. + * + * Tue Nov 19 10:15:36 PST 1996: Lee Olds + * Corrected vulnerability to buffer overruns by rewriting LogLine + * routine. Obscenely long kernel messages will now be broken up + * into lines no longer than LOG_LINE_LENGTH. + * + * The last version of LogLine was vulnerable to buffer overruns: + * - Kernel messages longer than LOG_LINE_LENGTH caused a buffer + * overrun. + * - If a line was determined to be shorter than LOG_LINE_LENGTH, + * the routine "ExpandKadds" could cause the line grow by + * an unknown amount and overrun a buffer. + * I turned these routines into a little parsing state machine that + * should not have these problems. */ @@ -170,7 +179,9 @@ #include #include #include +#include #include "klogd.h" +#include "ksyms.h" #include "pidfile.h" #include "version.h" @@ -428,13 +439,8 @@ static enum LOGSRC GetKernelLogSrc(void) { /* Initialize kernel logging. */ ksyslog(1, NULL, 0); -#ifdef DEBRELEASE - Syslog(LOG_INFO, "klogd %s-%s#%s, log source = ksyslog " - "started.", VERSION, PATCHLEVEL, DEBRELEASE); -#else Syslog(LOG_INFO, "klogd %s-%s, log source = ksyslog " "started.", VERSION, PATCHLEVEL); -#endif return(kernel); } @@ -446,13 +452,8 @@ static enum LOGSRC GetKernelLogSrc(void) exit(1); } -#ifdef DEBRELEASE - Syslog(LOG_INFO, "klogd %s-%s#%s, log source = %s started.", \ - VERSION, PATCHLEVEL, DEBRELEASE, _PATH_KLOG); -#else Syslog(LOG_INFO, "klogd %s-%s, log source = %s started.", \ VERSION, PATCHLEVEL, _PATH_KLOG); -#endif return(proc); } @@ -521,79 +522,218 @@ extern void Syslog(int priority, char *fmt, ...) return; } - -static void LogLine(char *ptr, int len) +/* + * Copy characters from ptr to line until a char in the delim + * string is encountered or until min( space, len ) chars have + * been copied. + * + * Returns the actual number of chars copied. + */ +static int copyin( char *line, int space, + const char *ptr, int len, + const char *delim ) { - auto int idx = 0; - static int index = 0; - auto char *nl; - auto char *pend = ptr + len; - static char line[LOG_LINE_LENGTH], - eline[LOG_LINE_LENGTH]; + auto int i; + auto int count; + count = len < space ? len : space; - if ( debugging && (len != 0) ) - { - fprintf(stderr, "Log buffer contains: %d characters.\n", len); - fprintf(stderr, "Line buffer contains: %d characters.\n", \ - index); - while ( idx <= len ) - { - fprintf(stderr, "Character #%d - %d:%c\n", idx, \ - ptr[idx], ptr[idx]); - ++idx; - } - if ( index != 0 ) - { - fputs("Line buffer contains an unterminated line:\n", \ - stderr); - fprintf(stderr, "\tCount: %d\n", index); - fprintf(stderr, "%s\n\n", line); - } - } + for(i=0; i]", + * where "aaaaaa" is the address. These are replaced with + * "[symbolname+offset/size]" in the output line - symbolname, + * offset, and size come from the kernel symbol table. + * + * If a kernel symbol happens to fall at the end of a message close + * in length to LOG_LINE_LENGTH, the symbol will not be expanded. + * (This should never happen, since the kernel should never generate + * messages that long. + */ +static void LogLine(char *ptr, int len) +{ + enum parse_state_enum { + PARSING_TEXT, + PARSING_SYMSTART, /* at < */ + PARSING_SYMBOL, + PARSING_SYMEND /* at ] */ + }; + + static char line_buff[LOG_LINE_LENGTH]; + + static char *line =line_buff; + static enum parse_state_enum parse_state = PARSING_TEXT; + static int space = sizeof(line_buff)-1; + + static char *sym_start; /* points at the '<' of a symbol */ + + auto int delta = 0; /* number of chars copied */ + + while( len >= 0 ) + { + if( space == 0 ) /* line buffer is full */ + { + /* + ** Line too long. Start a new line. + */ + *line = 0; /* force null terminator */ + + if ( debugging ) + { + fputs("Line buffer full:\n", stderr); + fprintf(stderr, "\tLine: %s\n", line); + } + + Syslog( LOG_INFO, line_buff ); + line = line_buff; + space = sizeof(line_buff)-1; + parse_state = PARSING_TEXT; + } + + switch( parse_state ) + { + case PARSING_TEXT: + delta = copyin( line, space, ptr, len, "\n[" ); + line += delta; + ptr += delta; + space -= delta; + len -= delta; + if( space == 0 || len == 0 ) + { + break; /* full line_buff or end of input buffer */ + } + if( *ptr == '\n' ) /* newline */ + { + *line++ = *ptr++; /* copy it in */ + space -= 1; + len -= 1; + + *line = 0; /* force null terminator */ + Syslog( LOG_INFO, line_buff ); + line = line_buff; + space = sizeof(line_buff)-1; + break; + } + if( *ptr == '[' ) /* possible kernel symbol */ + { + *line++ = *ptr++; + space -= 1; + len -= 1; + parse_state = PARSING_SYMSTART; /* at < */ + break; + } + break; + + case PARSING_SYMSTART: + if( *ptr != '<' ) + { + parse_state = PARSING_TEXT; /* not a symbol */ + break; + } + + /* + ** Save this character for now. If this turns out to + ** be a valid symbol, this char will be replaced later. + ** If not, we'll just leave it there. + */ + + sym_start = line; /* this will point at the '<' */ + + *line++ = *ptr++; + space -= 1; + len -= 1; + parse_state = PARSING_SYMBOL; /* symbol... */ + break; + + case PARSING_SYMBOL: + delta = copyin( line, space, ptr, len, ">\n[" ); + line += delta; + ptr += delta; + space -= delta; + len -= delta; + if( space == 0 || len == 0 ) + { + break; /* full line_buff or end of input buffer */ + } + if( *ptr != '>' ) + { + parse_state = PARSING_TEXT; + break; + } + + *line++ = *ptr++; /* copy the '>' */ + space -= 1; + len -= 1; + + parse_state = PARSING_SYMEND; + + break; + + case PARSING_SYMEND: + if( *ptr != ']' ) + { + parse_state = PARSING_TEXT; /* not a symbol */ + break; + } + + /* + ** It's really a symbol! Replace address with the + ** symbol text. + */ + { + auto int sym_space; + + auto int value; + auto struct symbol sym; + auto char *symbol; + + *(line-1) = 0; /* null terminate the address string */ + value = strtol(sym_start+1, (char **) 0, 16); + *(line-1) = '>'; /* put back delim */ + + symbol = LookupSymbol(value, &sym); + if ( symbol == (char *) 0 ) + { + parse_state = PARSING_TEXT; + break; + } + + /* + ** verify there is room in the line buffer + */ + sym_space = space + ( line - sym_start ); + if( sym_space < strlen(symbol) + 30 ) /*(30 should be overkill)*/ + { + parse_state = PARSING_TEXT; /* not enough space */ + break; + } + + delta = sprintf( sym_start, "%s+%d/%d]", + symbol, sym.offset, sym.size ); + + space = sym_space + delta; + line = sym_start + delta; + } + ptr++; + len--; + parse_state = PARSING_TEXT; + break; + + default: /* Can't get here! */ + parse_state = PARSING_TEXT; + + } + } + + return; } @@ -697,11 +837,8 @@ int main(argc, argv) use_syscall = 1; break; case 'v': -#ifdef DEBRELEASE - printf("klogd %s-%s#%s\n", VERSION, PATCHLEVEL, DEBRELEASE); -#else printf("klogd %s-%s\n", VERSION, PATCHLEVEL); -#endif exit (1); + exit (1); } diff --git a/klogd.h b/klogd.h index 548fa38..ef60f08 100644 --- a/klogd.h +++ b/klogd.h @@ -1,3 +1,24 @@ +/* + klogd.h - main header file for Linux kernel log daemon. + Copyright (c) 1995 Dr. G.W. Wettstein + + This file is part of the sysklogd package, a kernel and system log daemon. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + /* * Symbols and definitions needed by klogd. * diff --git a/ksym.c b/ksym.c index 59eef4e..c3dc9ab 100644 --- a/ksym.c +++ b/ksym.c @@ -76,6 +76,10 @@ * Mon Jun 9 17:12:42 CST 1997: Martin Schulze * Added #1 and #2 to some error messages in order to being able * to divide them (ulmo@Q.Net) + * + * Fri Jun 13 10:50:23 CST 1997: Martin Schulze + * Changed definition of LookupSymbol to non-static because it is + * used in klogd.c, too. */ @@ -122,7 +126,6 @@ extern int debugging; /* Function prototypes. */ static char * FindSymbolFile(void); static int AddSymbol(unsigned long, char*); -static char * LookupSymbol(unsigned long, struct symbol *); static void FreeSymbols(void); static int CheckVersion(char *); @@ -552,7 +555,7 @@ static int AddSymbol(address, symbol) * closely matching the address is returned. **************************************************************************/ -static char * LookupSymbol(value, sym) +char * LookupSymbol(value, sym) unsigned long value; diff --git a/ksym_mod.c b/ksym_mod.c new file mode 100644 index 0000000..f93d853 --- /dev/null +++ b/ksym_mod.c @@ -0,0 +1,636 @@ +/* + ksym_mod.c - functions for building symbol lookup tables for klogd + Copyright (c) 1995, 1996 Dr. G.W. Wettstein + Copyright (c) 1996 Enjellic Systems Development + + This file is part of the sysklogd package, a kernel and system log daemon. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +/* + * This file implements functions which are useful for building + * a symbol lookup table based on the in kernel symbol table + * maintained by the Linux kernel. + * + * Proper logging of kernel panics generated by loadable modules + * tends to be difficult. Since the modules are loaded dynamically + * their addresses are not known at kernel load time. A general + * protection fault (Oops) cannot be properly deciphered with + * classic methods using the static symbol map produced at link time. + * + * One solution to this problem is to have klogd attempt to translate + * addresses from module when the fault occurs. By referencing the + * the kernel symbol table proper resolution of these symbols is made + * possible. + * + * At least that is the plan. + * + * Wed Aug 21 09:20:09 CDT 1996: Dr. Wettstein + * The situation where no module support has been compiled into a + * kernel is now detected. An informative message is output indicating + * that the kernel has no loadable module support whenever kernel + * module symbols are loaded. + * + * An informative message is printed indicating the number of kernel + * modules and the number of symbols loaded from these modules. + */ + + +/* Includes. */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "klogd.h" +#include "ksyms.h" + + +/* + * The following bit uses some kernel/library magic to product what + * looks like a function call to user level code. This function is + * actually a system call in disguise. The purpose of the getsyms + * call is to return a current copy of the in-kernel symbol table. + */ +#define __LIBRARY__ +#include +#define __NR_getsyms __NR_get_kernel_syms +_syscall1(int, getsyms, struct kernel_sym *, syms); +#undef __LIBRARY__ +extern int getsyms(struct kernel_sym *); + + +/* Variables static to this module. */ +struct sym_table +{ + unsigned long value; + char *name; +}; + +struct Module +{ + struct sym_table *sym_array; + int num_syms; + + char *name; + struct module module; +}; + +static int num_modules = 0; +struct Module *sym_array_modules = (struct Module *) 0; + +static int have_modules = 0; + +#if defined(TEST) +static int debugging = 1; +#else +extern int debugging; +#endif + + +/* Function prototypes. */ +static void FreeModules(void); +static int AddSymbol(struct Module *mp, unsigned long, char *); +static int AddModule(unsigned long, char *); +static int symsort(const void *, const void *); + + +/************************************************************************** + * Function: InitMsyms + * + * Purpose: This function is responsible for building a symbol + * table which can be used to resolve addresses for + * loadable modules. + * + * Arguements: Void + * + * Return: A boolean return value is assumed. + * + * A false value indicates that something went wrong. + * + * True if loading is successful. + **************************************************************************/ + +extern int InitMsyms() + +{ + auto int rtn, + tmp; + + auto struct kernel_sym *ksym_table, + *p; + + + /* Initialize the kernel module symbol table. */ + FreeModules(); + + + /* + * The system call which returns the kernel symbol table has + * essentialy two modes of operation. Called with a null pointer + * the system call returns the number of symbols defined in the + * the table. + * + * The second mode of operation is to pass a valid pointer to + * the call which will then load the current symbol table into + * the memory provided. + * + * Returning the symbol table is essentially an all or nothing + * proposition so we need to pre-allocate enough memory for the + * complete table regardless of how many symbols we need. + * + * Bummer. + */ + if ( (rtn = getsyms((struct kernel_sym *) 0)) < 0 ) + { + if ( errno == ENOSYS ) + Syslog(LOG_INFO, "No module symbols loaded - " + "kernel modules not enabled.\n"); + else + Syslog(LOG_ERR, "Error loading kernel symbols " \ + "- %s\n", strerror(errno)); + return(0); + } + if ( debugging ) + fprintf(stderr, "Loading kernel module symbols - " + "Size of table: %d\n", rtn); + + ksym_table = (struct kernel_sym *) malloc(rtn * \ + sizeof(struct kernel_sym)); + if ( ksym_table == (struct kernel_sym *) 0 ) + { + Syslog(LOG_WARNING, " Failed memory allocation for kernel " \ + "symbol table.\n"); + return(0); + } + if ( (rtn = getsyms(ksym_table)) < 0 ) + { + Syslog(LOG_WARNING, "Error reading kernel symbols - %s\n", \ + strerror(errno)); + return(0); + } + + + /* + * Build a symbol table compatible with the other one used by + * klogd. + */ + tmp = rtn; + p = ksym_table; + while ( tmp-- ) + { + if ( !AddModule(p->value, p->name) ) + { + Syslog(LOG_WARNING, "Error adding kernel module table " + "entry.\n"); + free(ksym_table); + return(0); + } + ++p; + } + + /* Sort the symbol tables in each module. */ + for (rtn = tmp= 0; tmp < num_modules; ++tmp) + { + rtn += sym_array_modules[tmp].num_syms; + if ( sym_array_modules[tmp].num_syms < 2 ) + continue; + qsort(sym_array_modules[tmp].sym_array, \ + sym_array_modules[tmp].num_syms, \ + sizeof(struct sym_table), symsort); + } + + if ( rtn == 0 ) + Syslog(LOG_INFO, "No module symbols loaded."); + else + Syslog(LOG_INFO, "Loaded %d %s from %d module%s", rtn, \ + (rtn == 1) ? "symbol" : "symbols", \ + num_modules, (num_modules == 1) ? "." : "s."); + free(ksym_table); + return(1); +} + + +static int symsort(p1, p2) + + const void *p1; + + const void *p2; + +{ + auto const struct sym_table *sym1 = p1, + *sym2 = p2; + + if ( sym1->value < sym2->value ) + return(-1); + if ( sym1->value == sym2->value ) + return(0); + return(1); +} + + +/************************************************************************** + * Function: FreeModules + * + * Purpose: This function is used to free all memory which has been + * allocated for the modules and their symbols. + * + * Arguements: None specified. + * + * Return: void + **************************************************************************/ + +static void FreeModules() + +{ + auto int nmods, + nsyms; + + auto struct Module *mp; + + + /* Check to see if the module symbol tables need to be cleared. */ + have_modules = 0; + if ( num_modules == 0 ) + return; + + + for (nmods= 0; nmods < num_modules; ++nmods) + { + mp = &sym_array_modules[nmods]; + if ( mp->num_syms == 0 ) + continue; + + for (nsyms= 0; nsyms < mp->num_syms; ++nsyms) + free(mp->sym_array[nsyms].name); + free(mp->sym_array); + } + + free(sym_array_modules); + sym_array_modules = (struct Module *) 0; + num_modules = 0; + return; +} + + +/************************************************************************** + * Function: AddModule + * + * Purpose: This function is responsible for adding a module to + * the list of currently loaded modules. + * + * Arguements: (unsigned long) address, (char *) symbol + * + * address:-> The address of the module. + * + * symbol:-> The name of the module. + * + * Return: int + **************************************************************************/ + +static int AddModule(address, symbol) + + unsigned long address; + + char *symbol; + +{ + auto int memfd; + + auto struct Module *mp; + + + /* Return if we have loaded the modules. */ + if ( have_modules ) + return(1); + + /* + * The following section of code is responsible for determining + * whether or not we are done reading the list of modules. + */ + if ( symbol[0] == '#' ) + { + + if ( symbol[1] == '\0' ) + { + /* + * A symbol which consists of a # sign only + * signifies a a resident kernel segment. When we + * hit one of these we are done reading the + * module list. + */ + have_modules = 1; + return(1); + } + /* Allocate space for the module. */ + sym_array_modules = (struct Module *) \ + realloc(sym_array_modules, \ + (num_modules+1) * sizeof(struct Module)); + if ( sym_array_modules == (struct Module *) 0 ) + { + Syslog(LOG_WARNING, "Cannot allocate Module array.\n"); + return(0); + } + mp = &sym_array_modules[num_modules]; + + if ( (memfd = open("/dev/kmem", O_RDONLY)) < 0 ) + { + Syslog(LOG_WARNING, "Error opening /dev/kmem\n"); + return(1); + } + if ( lseek(memfd, address, SEEK_SET) < 0 ) + { + Syslog(LOG_WARNING, "Error seeking in /dev/kmem\n"); + return(0); + } + if ( read(memfd, \ + (char *)&sym_array_modules[num_modules].module, \ + sizeof(struct module)) < 0 ) + { + Syslog(LOG_WARNING, "Error reading module " + "descriptor.\n"); + return(0); + } + close(memfd); + + /* Save the module name. */ + mp->name = (char *) malloc(strlen(&symbol[1]) + 1); + if ( mp->name == (char *) 0 ) + return(0); + strcpy(mp->name, &symbol[1]); + + mp->num_syms = 0; + mp->sym_array = (struct sym_table *) 0; + ++num_modules; + return(1); + } + else + { + mp = &sym_array_modules[num_modules - 1]; + AddSymbol(mp, address, symbol); + } + + + return(1); +} + + +/************************************************************************** + * Function: AddSymbol + * + * Purpose: This function is responsible for adding a symbol name + * and its address to the symbol table. + * + * Arguements: (struct Module *) mp, (unsigned long) address, (char *) symbol + * + * mp:-> A pointer to the module which the symbol is + * to be added to. + * + * address:-> The address of the symbol. + * + * symbol:-> The name of the symbol. + * + * Return: int + * + * A boolean value is assumed. True if the addition is + * successful. False if not. + **************************************************************************/ + +static int AddSymbol(mp, address, symbol) + + struct Module *mp; + + unsigned long address; + + char *symbol; + +{ + auto int tmp; + + + /* Allocate space for the symbol table entry. */ + mp->sym_array = (struct sym_table *) realloc(mp->sym_array, \ + (mp->num_syms+1) * sizeof(struct sym_table)); + if ( mp->sym_array == (struct sym_table *) 0 ) + return(0); + + /* Then the space for the symbol. */ + tmp = strlen(symbol); + tmp += (strlen(mp->name) + 1); + mp->sym_array[mp->num_syms].name = (char *) malloc(tmp + 1); + if ( mp->sym_array[mp->num_syms].name == (char *) 0 ) + return(0); + memset(mp->sym_array[mp->num_syms].name, '\0', tmp + 1); + + /* Stuff interesting information into the module. */ + mp->sym_array[mp->num_syms].value = address; + strcpy(mp->sym_array[mp->num_syms].name, mp->name); + strcat(mp->sym_array[mp->num_syms].name, ":"); + strcat(mp->sym_array[mp->num_syms].name, symbol); + ++mp->num_syms; + + return(1); +} + + +/************************************************************************** + * Function: LookupModuleSymbol + * + * Purpose: Find the symbol which is related to the given address from + * a kernel module. + * + * Arguements: (long int) value, (struct symbol *) sym + * + * value:-> The address to be located. + * + * sym:-> A pointer to a structure which will be + * loaded with the symbol's parameters. + * + * Return: (char *) + * + * If a match cannot be found a diagnostic string is printed. + * If a match is found the pointer to the symbolic name most + * closely matching the address is returned. + **************************************************************************/ + +extern char * LookupModuleSymbol(value, sym) + + unsigned long value; + + struct symbol *sym; + +{ + auto int nmod, + nsym; + + auto struct sym_table *last; + + auto struct Module *mp; + + + sym->size = 0; + sym->offset = 0; + if ( num_modules == 0 ) + return((char *) 0); + + for(nmod= 0; nmod < num_modules; ++nmod) + { + mp = &sym_array_modules[nmod]; + + /* + * Run through the list of symbols in this module and + * see if the address can be resolved. + */ + for(nsym= 1, last = &mp->sym_array[0]; + nsym < mp->num_syms; + ++nsym) + { + if ( mp->sym_array[nsym].value > value ) + { + sym->offset = value - last->value; + sym->size = mp->sym_array[nsym].value - \ + last->value; + return(last->name); + } + last = &mp->sym_array[nsym]; + } + + + /* + * At this stage of the game we still cannot give up the + * ghost. There is the possibility that the address is + * from a module which has no symbols registered with + * the kernel. The solution is to compare the address + * against the starting address and extant of the module + * If it is in this range we can at least return the + * name of the module. + */ + if ( (void *) value >= mp->module.addr && + (void *) value <= (mp->module.addr + \ + mp->module.size * 4096) ) + { + /* + * A special case needs to be checked for. The above + * conditional tells us that we are within the + * extant of this module but symbol lookup has + * failed. + * + * We need to check to see if any symbols have + * been defined in this module. If there have been + * symbols defined the assumption must be made that + * the faulting address lies somewhere beyond the + * last symbol. About the only thing we can do + * at this point is use an offset from this + * symbol. + */ + if ( mp->num_syms > 0 ) + { + last = &mp->sym_array[mp->num_syms - 1]; + sym->size = (int) mp->module.addr + \ + (mp->module.size * 4096) - value; + sym->offset = value - last->value; + return(last->name); + } + + /* + * There were no symbols defined for this module. + * Return the module name and the offset of the + * faulting address in the module. + */ + sym->size = mp->module.size * 4096; + sym->offset = (void *) value - mp->module.addr; + return(mp->name); + } + } + + /* It has been a hopeless exercise. */ + return((char *) 0); +} + + +/* + * Setting the -DTEST define enables the following code fragment to + * be compiled. This produces a small standalone program which will + * dump the current kernel symbol table. + */ +#if defined(TEST) + +#include + + +extern int main(int, char **); + + +int main(argc, argv) + + int argc; + + char *argv[]; + +{ + auto int lp, syms; + + + if ( !InitMsyms() ) + { + fprintf(stderr, "Cannot load module symbols.\n"); + return(1); + } + + printf("Number of modules: %d\n\n", num_modules); + + for(lp= 0; lp < num_modules; ++lp) + { + printf("Module #%d = %s, Number of symbols = %d\n", lp + 1, \ + sym_array_modules[lp].name, \ + sym_array_modules[lp].num_syms); + + for (syms= 0; syms < sym_array_modules[lp].num_syms; ++syms) + { + printf("\tSymbol #%d\n", syms + 1); + printf("\tName: %s\n", \ + sym_array_modules[lp].sym_array[syms].name); + printf("\tAddress: %lx\n\n", \ + sym_array_modules[lp].sym_array[syms].value); + } + } + + FreeModules(); + return(0); +} + +extern void Syslog(int priority, char *fmt, ...) + +{ + va_list ap; + + va_start(ap, fmt); + fprintf(stdout, "Pr: %d, ", priority); + vfprintf(stdout, fmt, ap); + va_end(ap); + fputc('\n', stdout); + + return; +} + +#endif diff --git a/ksyms.h b/ksyms.h new file mode 100644 index 0000000..4e70ba0 --- /dev/null +++ b/ksyms.h @@ -0,0 +1,35 @@ +/* + ksym.h - Definitions for symbol table utilities. + Copyright (c) 1995, 1996 Dr. G.W. Wettstein + Copyright (c) 1996 Enjellic Systems Development + + This file is part of the sysklogd package, a kernel and system log daemon. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +/* Variables, structures and type definitions static to this module. */ + +struct symbol +{ + char *name; + int size; + int offset; +}; + + +/* Function prototypes. */ +extern char * LookupSymbol(unsigned long, struct symbol *); +extern char * LookupModuleSymbol(unsigned long int, struct symbol *); diff --git a/modutils.patch b/modutils.patch new file mode 100644 index 0000000..4dff7f3 --- /dev/null +++ b/modutils.patch @@ -0,0 +1,65 @@ +diff -u --new-file --recursive base/modules-2.0.0/depmod/modprobe.c ./modules-2.0.0/depmod/modprobe.c +--- base/modules-2.0.0/depmod/modprobe.c Mon Jun 10 05:29:08 1996 ++++ ./modules-2.0.0/depmod/modprobe.c Thu Aug 29 09:58:01 1996 +@@ -233,6 +233,13 @@ + verbose ("\r\t%s\n\t\t",cmd); + int ret = system(cmd); + #endif ++ if ( fork() == 0 ) ++ { ++ /* Child process. */ ++ if ( execlp("klogd", "klogd", "-i", (char *) 0) < 0 ) ++ fprintf(stderr, "Failure in signaling klogd.\n"); ++ exit(0); ++ } + return ret; + } + /* +diff -u --new-file --recursive base/modules-2.0.0/insmod/insmod.c ./modules-2.0.0/insmod/insmod.c +--- base/modules-2.0.0/insmod/insmod.c Mon Jun 10 06:42:25 1996 ++++ ./modules-2.0.0/insmod/insmod.c Thu Aug 29 09:56:53 1996 +@@ -253,6 +253,18 @@ + ++n_stringpatches; + } + ++ ++void signal_klogd() { ++ if ( fork() == 0 ) ++ { ++ if ( execlp("klogd", "klogd", "-i", (char *) 0) < 0 ) ++ fprintf(stderr, "Failure in signaling klogd.\n"); ++ exit(0); ++ } ++ return; ++} ++ ++ + int main(int argc, char **argv) + { + FILE *fp; +@@ -983,6 +995,8 @@ + symvalue(sp) + addr, symtype, symname(sp)); + } + ++ signal_klogd(); ++ + if (nksyms > 0) + free(ksymtab); /* it has done its job */ + +@@ -1292,6 +1306,7 @@ + --argc; + ++argv; + } ++ signal_klogd(); + return errors; + } + /* else recursive removal */ +@@ -1353,6 +1368,8 @@ + break; + } + } ++ ++ signal_klogd(); + + return errors; + } diff --git a/oops.c b/oops.c new file mode 100644 index 0000000..14573f0 --- /dev/null +++ b/oops.c @@ -0,0 +1,118 @@ +/* + * Loadable driver which provides the ability to generate a kernel + * protection fault. Mainly useful for testing the address translation + * capabilities of klogd. + * + * Fri Oct 27 14:34:27 CDT 1995: Dr. Wettstein + * + * Initial version. + */ + +#define NEW_MODULES + +/* Kernel includes. */ +#include +#include +#include +#include + +/* Standard module stuff. */ +#if defined(NEW_MODULES) +#include +#else +#include +#include +char kernel_version[] = UTS_RELEASE; +#endif + + +static int major = 32; + + +#ifdef MODULE +static int oops_ioctl(struct inode *, struct file *, unsigned int cmd, unsigned long arg); +static int oops_open(struct inode * node, struct file * file); +static void oops(void); + +static struct symbol_table these_symbols = { +#include + X(oops_open), + X(oops_ioctl), + X(oops), +#include +}; + +/* driver specific module definitions */ +static struct file_operations oops_fops1 = { + NULL, /* hw_lseek */ + NULL, /* hw_read */ + NULL, /* write */ + NULL, /* hw_readdir */ + NULL, /* hw_select */ + oops_ioctl, /* hw_ioctl */ + NULL, /* mmap */ + oops_open, /* hw_open */ + NULL, /* hw_release */ + NULL /* fsync */ +}; + +static int oops_open(struct inode * node, struct file * file) +{ + printk("Called oops_open.\n"); + return(0); +} + + +static int oops_ioctl(struct inode * node, struct file * file, \ + unsigned int cmd, unsigned long arg) +{ + + printk("Called oops_ioctl.\n"); + printk("Cmd: %d, Arg: %ld\n", cmd, arg); + if ( cmd == 1 ) + { + oops(); + } + + return(0); +} + +static void oops() + +{ + auto unsigned long *p = (unsigned long *) 828282828; + *p = 5; + return; +} + + +int +init_module(void) +{ + printk("oops: Module initilization.\n"); + if (register_chrdev(major, "oops", &oops_fops1)) { + printk("register_chrdev failed."); + return -EIO; + } + + printk("oops: Registering symbols.\n"); + register_symtab(&these_symbols); + + return 0; +} + + +void +cleanup_module(void) +{ + /* driver specific cleanups, ususally "unregister_*()" */ + printk("oops: Module unloadeding.\n"); + if (unregister_chrdev(major, "oops") != 0) + printk("cleanup_module failed\n"); + else + printk("cleanup_module succeeded\n"); + + return; + +} +#endif /* MODULE */ diff --git a/oops_test.c b/oops_test.c new file mode 100644 index 0000000..f710d4c --- /dev/null +++ b/oops_test.c @@ -0,0 +1,52 @@ +/* + * This is a small test program for generating a kernel protection fault + * using the oops loadable module. + * + * Fri Apr 26 12:52:43 CDT 1996: Dr. Wettstein + * Initial version. + */ + + +/* Includes. */ +#include +#include +#include +#include + + +/* Function prototypes. */ +extern int main(int, char **); + + +extern int main(argc, argv) + + int argc; + + char *argv[]; + +{ + auto int fd; + + if ( argc != 2 ) + { + fprintf(stderr, "No oops device specified.\n"); + return(1); + } + + if ( (fd = open(argv[1], O_RDONLY)) < 0 ) + { + fprintf(stderr, "Cannot open device: %s.\n", argv[1]); + return(1); + } + + if ( ioctl(fd, 1, 0) < 0 ) + { + fprintf(stderr, "Failed on oops.\n"); + return(1); + } + + printf("OOoops\n"); + + close(fd); + return(0); +}