diff options
author | wpaul <wpaul@FreeBSD.org> | 2001-08-10 23:15:13 +0000 |
---|---|---|
committer | wpaul <wpaul@FreeBSD.org> | 2001-08-10 23:15:13 +0000 |
commit | 69603fe5d4a5db02b03e6a8d979e6e4ecf1787a4 (patch) | |
tree | 65fc7ee5df389e3d8dc729739d518da5eaa8d65a /sys/kern/link_elf_obj.c | |
parent | add729e8404a84d920980fd5865f0ef019373b8b (diff) | |
download | FreeBSD-src-69603fe5d4a5db02b03e6a8d979e6e4ecf1787a4.zip FreeBSD-src-69603fe5d4a5db02b03e6a8d979e6e4ecf1787a4.tar.gz |
Fix some of the GDB linkage setup. The l_name member of the gdb linkage
structure is always free()ed yet only sometimes malloc()ed. In particular,
it was simply set to point to l_filename from the a linker_file_t in
link_elf_link_preload_finish(). The l_filename had been malloc()ed inside
the kern_linker.c module and was being free()ed twice: once by
link_elf_unload_file() and again by linker_file_unload(), leading to
a panic.
How to duplicate the problem:
- Pre-load a kernel module from the loader, i.e. if_sis.ko
- Boot system
- Attempt to unload module with kldunload if_sis
- Bewm
The problem here is that the case where the module was loaded with kldload
after system boot would work correctly, so this bug went unnoticed until
I stubbed my toe on it just now. (Also, you can only trip this bug if
you compile a kernel with options DDB, but that's the default now.)
Fix: remember to malloc() a separate copy of the module name for the
l_name member of the gdb linkage structure in three places where the
linkage structure can be initialized.
Diffstat (limited to 'sys/kern/link_elf_obj.c')
-rw-r--r-- | sys/kern/link_elf_obj.c | 16 |
1 files changed, 14 insertions, 2 deletions
diff --git a/sys/kern/link_elf_obj.c b/sys/kern/link_elf_obj.c index 785d23a..0f6a87a 100644 --- a/sys/kern/link_elf_obj.c +++ b/sys/kern/link_elf_obj.c @@ -173,6 +173,9 @@ link_elf_init(void* arg) caddr_t modptr, baseptr, sizeptr; elf_file_t ef; char *modname; +#ifdef DDB + char *newfilename; +#endif #endif linker_add_class(&link_elf_class); @@ -219,7 +222,9 @@ link_elf_init(void* arg) #ifdef DDB ef->gdb.l_addr = linker_kernel_file->address; - ef->gdb.l_name = modname; + newfilename = malloc(strlen(modname) + 1, M_LINKER, M_WAITOK); + strcpy(newfilename, modname); + ef->gdb.l_name = newfilename; ef->gdb.l_ld = dp; ef->gdb.l_prev = 0; ef->gdb.l_next = 0; @@ -473,6 +478,9 @@ link_elf_link_preload_finish(linker_file_t lf) { elf_file_t ef; int error; +#ifdef DDB + char *newfilename; +#endif ef = (elf_file_t) lf; #if 0 /* this will be more trouble than it's worth for now */ @@ -493,7 +501,9 @@ link_elf_link_preload_finish(linker_file_t lf) #ifdef DDB GDB_STATE(RT_ADD); ef->gdb.l_addr = lf->address; - ef->gdb.l_name = lf->filename; + newfilename = malloc(strlen(lf->filename) + 1, M_LINKER, M_WAITOK); + strcpy(newfilename, lf->filename); + ef->gdb.l_name = newfilename; ef->gdb.l_ld = ef->dynamic; link_elf_add_gdb(&ef->gdb); GDB_STATE(RT_CONSISTENT); @@ -530,7 +540,9 @@ link_elf_load_file(linker_class_t cls, const char* filename, linker_file_t* resu int symstrindex; int symcnt; int strcnt; +#ifdef DDB char *newfilename; +#endif GIANT_REQUIRED; |