Added patch from Leland Olds which fixes a buffer overrun and improved
symbol lookup.
This commit is contained in:
parent
c05f39c39c
commit
dd5def6ac9
9
Makefile
9
Makefile
@ -45,9 +45,10 @@ MAN_OWNER = root
|
|||||||
SYSLOGD_PIDNAME = -DSYSLOGD_PIDNAME=\"syslogd.pid\"
|
SYSLOGD_PIDNAME = -DSYSLOGD_PIDNAME=\"syslogd.pid\"
|
||||||
|
|
||||||
SYSLOGD_FLAGS= -DSYSLOG_INET -DSYSLOG_UNIXAF -DNO_SCCS ${FSSTND} \
|
SYSLOGD_FLAGS= -DSYSLOG_INET -DSYSLOG_UNIXAF -DNO_SCCS ${FSSTND} \
|
||||||
${SYSLOGD_PIDNAME} -DDEBRELEASE=\"$(revision)\"
|
${SYSLOGD_PIDNAME}
|
||||||
SYSLOG_FLAGS= -DALLOW_KERNEL_LOGGING
|
SYSLOG_FLAGS= -DALLOW_KERNEL_LOGGING
|
||||||
KLOGD_FLAGS = ${FSSTND} ${KLOGD_START_DELAY} -DDEBRELEASE=\"$(revision)\"
|
KLOGD_FLAGS = ${FSSTND} ${KLOGD_START_DELAY}
|
||||||
|
DEB =
|
||||||
|
|
||||||
.c.o:
|
.c.o:
|
||||||
${CC} ${CFLAGS} -c $*.c
|
${CC} ${CFLAGS} -c $*.c
|
||||||
@ -69,13 +70,13 @@ syslog_tst: syslog_tst.o
|
|||||||
${CC} ${LDFLAGS} -o syslog_tst syslog_tst.o
|
${CC} ${LDFLAGS} -o syslog_tst syslog_tst.o
|
||||||
|
|
||||||
syslogd.o: syslogd.c version.h
|
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
|
syslog.o: syslog.c
|
||||||
${CC} ${CFLAGS} ${SYSLOG_FLAGS} -c syslog.c
|
${CC} ${CFLAGS} ${SYSLOG_FLAGS} -c syslog.c
|
||||||
|
|
||||||
klogd.o: klogd.c klogd.h version.h
|
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
|
ksym.o: ksym.c klogd.h
|
||||||
${CC} ${CFLAGS} ${KLOGD_FLAGS} -c ksym.c
|
${CC} ${CFLAGS} ${KLOGD_FLAGS} -c ksym.c
|
||||||
|
309
klogd.c
309
klogd.c
@ -141,11 +141,6 @@
|
|||||||
* termination cleanup sequence. This minimizes the potential for
|
* termination cleanup sequence. This minimizes the potential for
|
||||||
* conflicting pidfiles causing immediate termination at boot time.
|
* 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
|
* Wed Aug 21 09:13:03 CDT 1996: Dr. Wettstein
|
||||||
* Added ability to reload static symbols and kernel module symbols
|
* Added ability to reload static symbols and kernel module symbols
|
||||||
* under control of SIGUSR1 and SIGUSR2 signals.
|
* under control of SIGUSR1 and SIGUSR2 signals.
|
||||||
@ -158,6 +153,20 @@
|
|||||||
*
|
*
|
||||||
* Added the -i and -I command line switches to signal the currently
|
* Added the -i and -I command line switches to signal the currently
|
||||||
* executing daemon.
|
* 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 <linux/time.h>
|
#include <linux/time.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <paths.h>
|
#include <paths.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include "klogd.h"
|
#include "klogd.h"
|
||||||
|
#include "ksyms.h"
|
||||||
#include "pidfile.h"
|
#include "pidfile.h"
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
|
|
||||||
@ -428,13 +439,8 @@ static enum LOGSRC GetKernelLogSrc(void)
|
|||||||
{
|
{
|
||||||
/* Initialize kernel logging. */
|
/* Initialize kernel logging. */
|
||||||
ksyslog(1, NULL, 0);
|
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 "
|
Syslog(LOG_INFO, "klogd %s-%s, log source = ksyslog "
|
||||||
"started.", VERSION, PATCHLEVEL);
|
"started.", VERSION, PATCHLEVEL);
|
||||||
#endif
|
|
||||||
return(kernel);
|
return(kernel);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -446,13 +452,8 @@ static enum LOGSRC GetKernelLogSrc(void)
|
|||||||
exit(1);
|
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.", \
|
Syslog(LOG_INFO, "klogd %s-%s, log source = %s started.", \
|
||||||
VERSION, PATCHLEVEL, _PATH_KLOG);
|
VERSION, PATCHLEVEL, _PATH_KLOG);
|
||||||
#endif
|
|
||||||
return(proc);
|
return(proc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -521,79 +522,218 @@ extern void Syslog(int priority, char *fmt, ...)
|
|||||||
return;
|
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;
|
auto int i;
|
||||||
static int index = 0;
|
auto int count;
|
||||||
auto char *nl;
|
|
||||||
auto char *pend = ptr + len;
|
|
||||||
static char line[LOG_LINE_LENGTH],
|
|
||||||
eline[LOG_LINE_LENGTH];
|
|
||||||
|
|
||||||
|
count = len < space ? len : space;
|
||||||
|
|
||||||
if ( debugging && (len != 0) )
|
for(i=0; i<count && !strchr(delim, *ptr); i++ ) { *line++ = *ptr++; }
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( index == 0 )
|
return( i );
|
||||||
memset(line, '\0', sizeof(line));
|
}
|
||||||
|
|
||||||
while (len) {
|
|
||||||
for (nl = ptr; nl < pend; nl += 1)
|
|
||||||
if ((*nl == '\n') || (*nl == '\r'))
|
|
||||||
break;
|
|
||||||
if (nl != pend) {
|
|
||||||
len -= nl - ptr + 1;
|
|
||||||
strncat(line, ptr, nl - ptr);
|
|
||||||
ptr = nl + 1;
|
|
||||||
/* Check for empty log line (may be produced if
|
|
||||||
kernel messages have multiple terminators, eg.
|
|
||||||
\n\r) */
|
|
||||||
if ( (*line != '\n') && (*line != '\r') )
|
|
||||||
{
|
|
||||||
memset(eline, '\0', sizeof(eline));
|
|
||||||
ExpandKadds(line, eline);
|
|
||||||
Syslog(LOG_INFO, eline);
|
|
||||||
}
|
|
||||||
index = 0;
|
|
||||||
memset(line, '\0', sizeof(line));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if ( debugging )
|
|
||||||
{
|
|
||||||
fputs("No terminator - leftover:\n", stderr);
|
|
||||||
fprintf(stderr, "\tCharacters: %d\n", len);
|
|
||||||
fprintf(stderr, "\tIndex: %d\n", index);
|
|
||||||
fputs("\tLine: ", stderr);
|
|
||||||
fprintf(stderr, "%s\n", line);
|
|
||||||
}
|
|
||||||
|
|
||||||
strncat(line, ptr, len);
|
|
||||||
index += len;
|
|
||||||
len = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
/*
|
||||||
|
* Messages are separated by "\n". Messages longer than
|
||||||
|
* LOG_LINE_LENGTH are broken up.
|
||||||
|
*
|
||||||
|
* Kernel symbols show up in the input buffer as : "[<aaaaaa>]",
|
||||||
|
* 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;
|
use_syscall = 1;
|
||||||
break;
|
break;
|
||||||
case 'v':
|
case 'v':
|
||||||
#ifdef DEBRELEASE
|
|
||||||
printf("klogd %s-%s#%s\n", VERSION, PATCHLEVEL, DEBRELEASE);
|
|
||||||
#else
|
|
||||||
printf("klogd %s-%s\n", VERSION, PATCHLEVEL);
|
printf("klogd %s-%s\n", VERSION, PATCHLEVEL);
|
||||||
#endif exit (1);
|
exit (1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
21
klogd.h
21
klogd.h
@ -1,3 +1,24 @@
|
|||||||
|
/*
|
||||||
|
klogd.h - main header file for Linux kernel log daemon.
|
||||||
|
Copyright (c) 1995 Dr. G.W. Wettstein <greg@wind.rmcc.com>
|
||||||
|
|
||||||
|
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.
|
* Symbols and definitions needed by klogd.
|
||||||
*
|
*
|
||||||
|
7
ksym.c
7
ksym.c
@ -76,6 +76,10 @@
|
|||||||
* Mon Jun 9 17:12:42 CST 1997: Martin Schulze
|
* Mon Jun 9 17:12:42 CST 1997: Martin Schulze
|
||||||
* Added #1 and #2 to some error messages in order to being able
|
* Added #1 and #2 to some error messages in order to being able
|
||||||
* to divide them (ulmo@Q.Net)
|
* 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. */
|
/* Function prototypes. */
|
||||||
static char * FindSymbolFile(void);
|
static char * FindSymbolFile(void);
|
||||||
static int AddSymbol(unsigned long, char*);
|
static int AddSymbol(unsigned long, char*);
|
||||||
static char * LookupSymbol(unsigned long, struct symbol *);
|
|
||||||
static void FreeSymbols(void);
|
static void FreeSymbols(void);
|
||||||
static int CheckVersion(char *);
|
static int CheckVersion(char *);
|
||||||
|
|
||||||
@ -552,7 +555,7 @@ static int AddSymbol(address, symbol)
|
|||||||
* closely matching the address is returned.
|
* closely matching the address is returned.
|
||||||
**************************************************************************/
|
**************************************************************************/
|
||||||
|
|
||||||
static char * LookupSymbol(value, sym)
|
char * LookupSymbol(value, sym)
|
||||||
|
|
||||||
unsigned long value;
|
unsigned long value;
|
||||||
|
|
||||||
|
636
ksym_mod.c
Normal file
636
ksym_mod.c
Normal file
@ -0,0 +1,636 @@
|
|||||||
|
/*
|
||||||
|
ksym_mod.c - functions for building symbol lookup tables for klogd
|
||||||
|
Copyright (c) 1995, 1996 Dr. G.W. Wettstein <greg@wind.rmcc.com>
|
||||||
|
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 <stdlib.h>
|
||||||
|
#include <malloc.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <sys/fcntl.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <linux/time.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <paths.h>
|
||||||
|
|
||||||
|
#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 <linux/unistd.h>
|
||||||
|
#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 <stdarg.h>
|
||||||
|
|
||||||
|
|
||||||
|
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
|
35
ksyms.h
Normal file
35
ksyms.h
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
ksym.h - Definitions for symbol table utilities.
|
||||||
|
Copyright (c) 1995, 1996 Dr. G.W. Wettstein <greg@wind.rmcc.com>
|
||||||
|
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 *);
|
65
modutils.patch
Normal file
65
modutils.patch
Normal file
@ -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;
|
||||||
|
}
|
118
oops.c
Normal file
118
oops.c
Normal file
@ -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 <linux/kernel.h>
|
||||||
|
#include <linux/config.h>
|
||||||
|
#include <linux/errno.h>
|
||||||
|
#include <linux/fs.h>
|
||||||
|
|
||||||
|
/* Standard module stuff. */
|
||||||
|
#if defined(NEW_MODULES)
|
||||||
|
#include <linux/module.h>
|
||||||
|
#else
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/version.h>
|
||||||
|
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 <linux/symtab_begin.h>
|
||||||
|
X(oops_open),
|
||||||
|
X(oops_ioctl),
|
||||||
|
X(oops),
|
||||||
|
#include <linux/symtab_end.h>
|
||||||
|
};
|
||||||
|
|
||||||
|
/* 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 */
|
52
oops_test.c
Normal file
52
oops_test.c
Normal file
@ -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 <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
|
||||||
|
|
||||||
|
/* 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);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user