summaryrefslogtreecommitdiffstats
path: root/libexec/rtld-elf/amd64
diff options
context:
space:
mode:
authorkib <kib@FreeBSD.org>2011-12-14 16:47:53 +0000
committerkib <kib@FreeBSD.org>2011-12-14 16:47:53 +0000
commit3513d1ffea87c3275943419090f06df031f04dcc (patch)
tree2deca750951347f2dbf7f42e4e15affd3168c2e5 /libexec/rtld-elf/amd64
parent17652e9b65daf592693ab40df9d42e895a444c8c (diff)
downloadFreeBSD-src-3513d1ffea87c3275943419090f06df031f04dcc.zip
FreeBSD-src-3513d1ffea87c3275943419090f06df031f04dcc.tar.gz
_rtld_bind() read-locks the bind lock, and possible plt resolution
from the dispatcher would also acquire bind lock in read mode, which is the supported operation. plt is explicitely designed to allow safe multithreaded updates, so the shared lock do not cause problems. The error in r228435 is that it allows read lock acquisition after the write lock for the bind block. If we dlopened the shared object that contains IRELATIVE or jump slot which target is STT_GNU_IFUNC, then possible recursive plt resolve from the dispatcher would cause it. Postpone the resolution for irelative/ifunc right before initializers are called, and drop bind lock around calls to dispatcher. Use initlist to iterate over the objects instead of the ->next, due to drop of the bind lock in iteration. For i386/reloc.c:reloc_iresolve(), fix calculation of the dispatch function address for dso, by taking into account possible non-zero relocbase. MFC after: 3 weeks
Diffstat (limited to 'libexec/rtld-elf/amd64')
-rw-r--r--libexec/rtld-elf/amd64/reloc.c9
1 files changed, 8 insertions, 1 deletions
diff --git a/libexec/rtld-elf/amd64/reloc.c b/libexec/rtld-elf/amd64/reloc.c
index 5ae8493..3b00987 100644
--- a/libexec/rtld-elf/amd64/reloc.c
+++ b/libexec/rtld-elf/amd64/reloc.c
@@ -413,6 +413,8 @@ reloc_iresolve(Obj_Entry *obj, RtldLockState *lockstate)
const Elf_Rela *relalim;
const Elf_Rela *rela;
+ if (!obj->irelative)
+ return (0);
relalim = (const Elf_Rela *)((char *)obj->pltrela + obj->pltrelasize);
for (rela = obj->pltrela; rela < relalim; rela++) {
Elf_Addr *where, target, *ptr;
@@ -424,11 +426,14 @@ reloc_iresolve(Obj_Entry *obj, RtldLockState *lockstate)
case R_X86_64_IRELATIVE:
ptr = (Elf_Addr *)(obj->relocbase + rela->r_addend);
where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
+ lock_release(rtld_bind_lock, lockstate);
target = ((Elf_Addr (*)(void))ptr)();
+ wlock_acquire(rtld_bind_lock, lockstate);
*where = target;
break;
}
}
+ obj->irelative = false;
return (0);
}
@@ -455,13 +460,15 @@ reloc_gnu_ifunc(Obj_Entry *obj, RtldLockState *lockstate)
return (-1);
if (ELF_ST_TYPE(def->st_info) != STT_GNU_IFUNC)
continue;
+ lock_release(rtld_bind_lock, lockstate);
target = (Elf_Addr)rtld_resolve_ifunc(defobj, def);
+ wlock_acquire(rtld_bind_lock, lockstate);
reloc_jmpslot(where, target, defobj, obj, (const Elf_Rel *)rela);
break;
}
}
obj->gnu_ifunc = false;
- return 0;
+ return (0);
}
void
OpenPOWER on IntegriCloud