Source: glibc Version: 2.22 Severity: normal Tags: patch Dear Maintainer,
The failure of the debug/backtrace-tst was introduced by the hppa/submitted-dladdr.diff patch. The code was not prepared to handle being passed an arbitrary address. As a result, _dl_lookup_address generates a segmentation fault. I believe this fixes one or two other tests as well. This is BZ 20098: https://sourceware.org/bugzilla/show_bug.cgi?id=20098 A patch to fix this problem in the upstream source is here: https://sourceware.org/ml/libc-alpha/2016-05/txti8b7kcvurW.txt Attached is a replacement for the current hppa/submitted-dladdr.diff patch. Please update current patch. Thanks, Dave -- System Information: Debian Release: stretch/sid APT prefers unstable APT policy: (500, 'unstable') Architecture: hppa (parisc64) Kernel: Linux 3.18.29+ (SMP w/4 CPU cores) Locale: LANG=en_US.UTF-8, LC_CTYPE=en_US.UTF-8 (charmap=UTF-8) (ignored: LC_ALL set to en_CA.utf8) Shell: /bin/sh linked to /bin/dash Init: sysvinit (via /sbin/init)
2016-01-02 John David Anglin <dang...@gcc.gnu.org> [BZ #19415] * sysdeps/hppa/dl-fptr.c (_dl_fixup): Declare. (elf_machine_resolve): New. Return address of _dl_runtime_resolve. (_dl_lookup_address): Rewrite using function resolver trampoline. * sysdeps/hppa/dl-lookupcfg.h (DL_LOOKUP_ADDRESS): Don't clear bottom two bits in address. Index: glibc-2.22/sysdeps/hppa/dl-fptr.c =================================================================== --- glibc-2.22.orig/sysdeps/hppa/dl-fptr.c +++ glibc-2.22/sysdeps/hppa/dl-fptr.c @@ -321,23 +321,76 @@ _dl_unmap (struct link_map *map) map->l_mach.fptr_table = NULL; } +extern ElfW(Addr) _dl_fixup (struct link_map *, ElfW(Word)) attribute_hidden; + +static inline Elf32_Addr +elf_machine_resolve (void) +{ + Elf32_Addr addr; + + asm ("b,l 1f,%0\n" +" depi 0,31,2,%0\n" +"1: addil L'_dl_runtime_resolve - ($PIC_pcrel$0 - 8),%0\n" +" ldo R'_dl_runtime_resolve - ($PIC_pcrel$0 - 12)(%%r1),%0\n" + : "=r" (addr) : : "r1"); + + return addr; +} + +static inline int +_dl_read_access_allowed (unsigned int *addr) +{ + int result; + + asm ("proberi (%1),3,%0" : "=r" (result) : "r" (addr) : ); + + return result; +} ElfW(Addr) _dl_lookup_address (const void *address) { ElfW(Addr) addr = (ElfW(Addr)) address; - struct fdesc_table *t; - unsigned long int i; + unsigned int *desc, *gptr; - for (t = local.root; t != NULL; t = t->next) - { - i = (struct fdesc *) addr - &t->fdesc[0]; - if (i < t->first_unused && addr == (ElfW(Addr)) &t->fdesc[i]) - { - addr = t->fdesc[i].ip; - break; - } - } + /* Return ADDR if the least-significant two bits of ADDR are not consistent + with ADDR being a linker defined function pointer. The normal value for + a code address in a backtrace is 3. */ + if (((unsigned int) addr & 3) != 2) + return addr; - return addr; + /* Handle special case where ADDR points to page 0. */ + if ((unsigned int) addr < 4096) + return addr; + + /* Clear least-significant two bits from descriptor address. */ + desc = (unsigned int *) ((unsigned int) addr & ~3); + if (!_dl_read_access_allowed (desc)) + return addr; + + /* Load first word of candidate descriptor. It should be a pointer + with word alignment and point to memory that can be read. */ + gptr = (unsigned int *) desc[0]; + if (((unsigned int) gptr & 3) != 0 + || !_dl_read_access_allowed (gptr)) + return addr; + + /* See if descriptor requires resolution. The following trampoline is + used in each global offset table for function resolution: + + ldw 0(r20),r22 + bv r0(r22) + ldw 4(r20),r21 + tramp: b,l .-12,r20 + depwi 0,31,2,r20 + .word _dl_runtime_resolve + .word "_dl_runtime_resolve ltp" + got: .word _DYNAMIC + .word "struct link map address" */ + if (gptr[0] == 0xea9f1fdd /* b,l .-12,r20 */ + && gptr[1] == 0xd6801c1e /* depwi 0,31,2,r20 */ + && (ElfW(Addr)) gptr[2] == elf_machine_resolve ()) + _dl_fixup ((struct link_map *) gptr[5], (ElfW(Word)) desc[1]); + + return (ElfW(Addr)) desc[0]; } Index: glibc-2.22/sysdeps/hppa/dl-lookupcfg.h =================================================================== --- glibc-2.22.orig/sysdeps/hppa/dl-lookupcfg.h +++ glibc-2.22/sysdeps/hppa/dl-lookupcfg.h @@ -31,9 +31,7 @@ rtld_hidden_proto (_dl_symbol_address) Elf32_Addr _dl_lookup_address (const void *address); -/* Clear the bottom two bits so generic code can find the fdesc entry */ -#define DL_LOOKUP_ADDRESS(addr) \ - (_dl_lookup_address ((void *)((unsigned long)addr & ~3))) +#define DL_LOOKUP_ADDRESS(addr) _dl_lookup_address ((const void *) addr) void attribute_hidden _dl_unmap (struct link_map *map);