readelf: pointer validy checks patch
Andreas Jaeger
aj@suse.de
Fri May 26 02:49:00 GMT 2000
ldconfig crashed when one of the elf structures is broken and a
pointer points outside the mmapped region. I've added now checks to
prevent the most common cases. We can still segfault if e.g. the end
of file is in the middle of a string - but I don't think we should
test all those cases and concentrate on the common ones first.
I'll commit this patch later,
Andreas
2000-05-26 Andreas Jaeger <aj@suse.de>
* sysdeps/generic/readelflib.c (check_ptr): New.
(process_elf_file): Use check_ptr to check all accesses to the
mmapped file.
* elf/readlib.c (known_libs): Add more libraries.
============================================================
Index: elf/ldconfig.h
--- elf/ldconfig.h 2000/05/07 21:20:01 1.3
+++ elf/ldconfig.h 2000/05/26 09:42:23
@@ -46,7 +46,8 @@
/* Declared in readelflib.c. */
extern int process_elf_file (const char *file_name, const char *lib, int *flag,
- char **soname, void *file_contents);
+ char **soname, void *file_contents,
+ size_t file_length);
/* Declared in ldconfig.c. */
============================================================
Index: elf/readlib.c
--- elf/readlib.c 2000/04/11 16:22:06 1.3
+++ elf/readlib.c 2000/05/26 09:42:23
@@ -56,8 +56,10 @@
static struct known_names known_libs [] =
{
{"libc.so.6", FLAG_ELF_LIBC6},
+ {"libc.so.6.1", FLAG_ELF_LIBC6},
{"libc.so.5", FLAG_ELF_LIBC5},
{"libm.so.6", FLAG_ELF_LIBC6},
+ {"libm.so.6.1", FLAG_ELF_LIBC6},
{"libm.so.5", FLAG_ELF_LIBC5}
};
@@ -65,7 +67,8 @@
/* Returns 0 if everything is ok, != 0 in case of error. */
int
-process_file (const char *file_name, const char *lib, int *flag, char **soname, int is_link)
+process_file (const char *file_name, const char *lib, int *flag,
+ char **soname, int is_link)
{
FILE *file;
struct stat statbuf;
@@ -156,7 +159,8 @@
goto done;
}
- if (process_elf_file (file_name, lib, flag, soname, file_contents))
+ if (process_elf_file (file_name, lib, flag, soname, file_contents,
+ statbuf.st_size))
ret = 1;
done:
============================================================
Index: sysdeps/generic/readelflib.c
--- sysdeps/generic/readelflib.c 1999/12/04 07:56:05 1.1
+++ sysdeps/generic/readelflib.c 2000/05/26 09:42:23
@@ -23,10 +23,24 @@
which need to handle both 32bit and 64bit ELF libraries, this file is
included twice for each arch size. */
+/* check_ptr checks that a pointer is in the mmaped file and doesn't
+ point outside it. */
+#define check_ptr(ptr) \
+do \
+ { \
+ if ((void *)(ptr) < file_contents \
+ || (void *)(ptr) > (file_contents+file_length)) \
+ { \
+ error (0, 0, _("file %s is truncated\n"), file_name); \
+ return 1; \
+ } \
+ } \
+ while (0);
+
/* Returns 0 if everything is ok, != 0 in case of error. */
int
-process_elf_file (const char *file_name, const char *lib, int *flag, char **soname,
- void *file_contents)
+process_elf_file (const char *file_name, const char *lib, int *flag,
+ char **soname, void *file_contents, size_t file_length)
{
int i;
unsigned int j;
@@ -65,6 +79,7 @@
/* Get information from elf program header. */
elf_pheader = (ElfW(Phdr) *) (elf_header->e_phoff + file_contents);
+ check_ptr (elf_pheader);
/* The library is an elf library, now search for soname and
libc5/libc6. */
@@ -77,6 +92,8 @@
for (i = 0, segment = elf_pheader;
i < elf_header->e_phnum; i++, segment++)
{
+ check_ptr (segment);
+
switch (segment->p_type)
{
case PT_LOAD:
@@ -94,6 +111,7 @@
break;
case PT_INTERP:
program_interpreter = (char *) (file_contents + segment->p_offset);
+ check_ptr (program_interpreter);
/* Check if this is enough to classify the binary. */
for (j = 0; j < sizeof (interpreters) / sizeof (interpreters [0]);
@@ -120,15 +138,18 @@
return 1;
dynamic_segment = (ElfW(Dyn) *) (file_contents + dynamic_addr);
+ check_ptr (dynamic_segment);
/* Find the string table. */
dynamic_strings = NULL;
for (dyn_entry = dynamic_segment; dyn_entry->d_tag != DT_NULL;
++dyn_entry)
{
+ check_ptr (dyn_entry);
if (dyn_entry->d_tag == DT_STRTAB)
{
dynamic_strings = (char *) (file_contents + dyn_entry->d_un.d_val - loadaddr);
+ check_ptr (dynamic_strings);
break;
}
}
@@ -143,6 +164,7 @@
if (dyn_entry->d_tag == DT_NEEDED || dyn_entry->d_tag == DT_SONAME)
{
char *name = dynamic_strings + dyn_entry->d_un.d_val;
+ check_ptr (name);
if (dyn_entry->d_tag == DT_NEEDED)
{
============================================================
Index: sysdeps/unix/sysv/linux/sparc/readelflib.c
--- sysdeps/unix/sysv/linux/sparc/readelflib.c 1999/12/04 07:55:35 1.1
+++ sysdeps/unix/sysv/linux/sparc/readelflib.c 2000/05/26 09:42:23
@@ -20,23 +20,27 @@
int process_elf32_file (const char *file_name, const char *lib, int *flag,
- char **soname, void *file_contents);
+ char **soname, void *file_contents,
+ size_t file_length);
int process_elf64_file (const char *file_name, const char *lib, int *flag,
- char **soname, void *file_contents);
+ char **soname, void *file_contents,
+ size_t file_length);
/* Returns 0 if everything is ok, != 0 in case of error. */
int
process_elf_file (const char *file_name, const char *lib, int *flag,
- char **soname, void *file_contents)
+ char **soname, void *file_contents, size_t size)
{
ElfW(Ehdr) *elf_header = (ElfW(Ehdr) *) file_contents;
int ret;
if (elf_header->e_ident [EI_CLASS] == ELFCLASS32)
- return process_elf32_file (file_name, lib, flag, soname, file_contents);
+ return process_elf32_file (file_name, lib, flag, soname, file_contents,
+ file_length);
else
{
- ret = process_elf64_file (file_name, lib, flag, soname, file_contents);
+ ret = process_elf64_file (file_name, lib, flag, soname, file_contents,
+ file_length);
/* Sparc 64bit libraries are always libc.so.6+. */
if (!ret)
*flag = FLAG_SPARC_LIB64|FLAG_ELF_LIBC6;
--
Andreas Jaeger
SuSE Labs aj@suse.de
private aj@arthur.rhein-neckar.de
More information about the Libc-hacker
mailing list