NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

lib/41482: False cache hits in ld.elf_so



>Number:         41482
>Category:       lib
>Synopsis:       False cache hits in ld.elf_so
>Confidential:   no
>Severity:       serious
>Priority:       high
>Responsible:    lib-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Sun May 24 17:50:00 +0000 2009
>Originator:     Michael Eriksson
>Release:        NetBSD 5.0
>Environment:
Vanilla NetBSD 5.0, x86_64 and i386 and probably other architectures.

>Description:

The ld.elf_so run-time linker has a single-entry cache in
_rtld_find_symdef() for faster symbol lookup. Cache matching is done
on referencing object and symbol number. The referencing object data
structures are allocated on the heap with malloc(), and if there has
been a free() of the last data structure, the same memory area may be
resused, and false cache hits will result. This may happen when an
application uses dlopen().

>How-To-Repeat:

In my case, try to use the py-imagingtk pkgsrc package on NetBSD 5.0
with in-tree xorg X11. This triggered the bug on both i386 and amd64;
I have not tried any other machines or combinations.

The bug will cause symbols to be resolved to the wrong memory address.
I was fortunate and a read-write data symbol was mapped to read-only
code text memory, which caused an easily identifiable segmentation
violation.

>Fix:

Apply the patch below, wich resets the cache in dlopen().

Index: rtld.c
===================================================================
RCS file: /cvsroot/src/libexec/ld.elf_so/rtld.c,v
retrieving revision 1.123
diff -u -r1.123 rtld.c
--- rtld.c      26 Oct 2008 07:11:54 -0000      1.123
+++ rtld.c      24 May 2009 16:04:54 -0000
@@ -780,6 +780,10 @@
                if (*old_obj_tail != NULL) {    /* We loaded something new. */
                        assert(*old_obj_tail == obj);
 
+#ifdef COMBRELOC
+                       /* Reset the COMBRELOC cache */
+                       combreloc_last_refobj = NULL;
+#endif
                        if (_rtld_load_needed_objects(obj, mode) == -1 ||
                            (_rtld_init_dag(obj),
                            _rtld_relocate_objects(obj,
Index: rtld.h
===================================================================
RCS file: /cvsroot/src/libexec/ld.elf_so/rtld.h,v
retrieving revision 1.79
diff -u -r1.79 rtld.h
--- rtld.h      4 Oct 2008 09:37:12 -0000       1.79
+++ rtld.h      24 May 2009 16:04:54 -0000
@@ -268,6 +268,9 @@
 unsigned long _rtld_elf_hash(const char *);
 const Elf_Sym *_rtld_symlook_obj(const char *, unsigned long,
     const Obj_Entry *, bool);
+#ifdef COMBRELOC
+extern const Obj_Entry *combreloc_last_refobj;
+#endif
 const Elf_Sym *_rtld_find_symdef(unsigned long, const Obj_Entry *,
     const Obj_Entry **, bool);
 const Elf_Sym *_rtld_symlook_list(const char *, unsigned long,
Index: symbol.c
===================================================================
RCS file: /cvsroot/src/libexec/ld.elf_so/symbol.c,v
retrieving revision 1.47
diff -u -r1.47 symbol.c
--- symbol.c    4 Oct 2008 09:37:12 -0000       1.47
+++ symbol.c    24 May 2009 16:04:54 -0000
@@ -235,6 +235,9 @@
        return NULL;
 }
 
+#ifdef COMBRELOC
+const Obj_Entry *combreloc_last_refobj;
+#endif
 /*
  * Given a symbol number in a referencing object, find the corresponding
  * definition of the symbol.  Returns a pointer to the symbol, or NULL if
@@ -261,10 +264,9 @@
         */
        static unsigned long last_symnum;
        static const Elf_Sym *last_def;
-       static const Obj_Entry *last_refobj;
        static const Obj_Entry *last_defobj;
 
-       if (symnum == last_symnum && refobj == last_refobj
+       if (symnum == last_symnum && refobj == combreloc_last_refobj
            && in_plt == false) {
                *defobj_out = last_defobj;
                return last_def;
@@ -318,7 +320,7 @@
                         * non-PLT lookup.
                         */
                        last_symnum = symnum;
-                       last_refobj = refobj;
+                       combreloc_last_refobj = refobj;
                        last_def = def;
                        last_defobj = defobj;
                }



Home | Main Index | Thread Index | Old Index