Implement support for ELF filters in rtld. Both normal and auxillary

filters are implemented.

Filtees are loaded on demand, unless LD_LOADFLTR environment variable
is set or -z loadfltr was specified during the linking. This forces
rtld to upgrade read-locked rtld_bind_lock to write lock when it
encounters an object with filter during symbol lookup.

Consolidate common arguments of the symbol lookup functions in the
SymLook structure.  Track the state of the rtld locks in the
RtldLockState structure. Pass local RtldLockState through the rtld
symbol lookup calls to allow lock upgrades.

Reviewed by:	kan
Tested by:	Mykola Dzham <i levsha me>, nwhitehorn (powerpc)
This commit is contained in:
Konstantin Belousov 2010-12-25 08:51:20 +00:00
parent 06786ccfb3
commit 8569deaf1c
13 changed files with 764 additions and 408 deletions

View file

@ -69,23 +69,28 @@ do_copy_relocations(Obj_Entry *dstobj)
void *dstaddr;
const Elf_Sym *dstsym;
const char *name;
unsigned long hash;
size_t size;
const void *srcaddr;
const Elf_Sym *srcsym;
Obj_Entry *srcobj;
const Ver_Entry *ve;
const Obj_Entry *srcobj, *defobj;
SymLook req;
int res;
dstaddr = (void *) (dstobj->relocbase + rela->r_offset);
dstsym = dstobj->symtab + ELF_R_SYM(rela->r_info);
name = dstobj->strtab + dstsym->st_name;
hash = elf_hash(name);
size = dstsym->st_size;
ve = fetch_ventry(dstobj, ELF_R_SYM(rela->r_info));
symlook_init(&req, name);
req.ventry = fetch_ventry(dstobj, ELF_R_SYM(rela->r_info));
for (srcobj = dstobj->next; srcobj != NULL; srcobj = srcobj->next)
if ((srcsym = symlook_obj(name, hash, srcobj, ve, 0)) != NULL)
for (srcobj = dstobj->next; srcobj != NULL; srcobj = srcobj->next) {
res = symlook_obj(&req, srcobj);
if (res == 0) {
srcsym = req.sym_out;
defobj = req.defobj_out;
break;
}
}
if (srcobj == NULL) {
_rtld_error("Undefined symbol \"%s\" referenced from COPY"
@ -93,7 +98,7 @@ do_copy_relocations(Obj_Entry *dstobj)
return -1;
}
srcaddr = (const void *) (srcobj->relocbase + srcsym->st_value);
srcaddr = (const void *) (defobj->relocbase + srcsym->st_value);
memcpy(dstaddr, srcaddr, size);
}
}
@ -113,7 +118,7 @@ init_pltgot(Obj_Entry *obj)
/* Process the non-PLT relocations. */
int
reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld)
reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, RtldLockState *lockstate)
{
const Elf_Rela *relalim;
const Elf_Rela *rela;
@ -146,7 +151,7 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld)
const Obj_Entry *defobj;
def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
false, cache);
false, cache, lockstate);
if (def == NULL)
goto done;
@ -165,7 +170,7 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld)
const Obj_Entry *defobj;
def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
false, cache);
false, cache, lockstate);
if (def == NULL)
goto done;
@ -195,7 +200,7 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld)
const Obj_Entry *defobj;
def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
false, cache);
false, cache, lockstate);
if (def == NULL)
goto done;
@ -209,7 +214,7 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld)
const Obj_Entry *defobj;
def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
false, cache);
false, cache, lockstate);
if (def == NULL)
goto done;
@ -240,7 +245,7 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld)
const Obj_Entry *defobj;
def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
false, cache);
false, cache, lockstate);
if (def == NULL)
goto done;
@ -272,7 +277,7 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld)
const Obj_Entry *defobj;
def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
false, cache);
false, cache, lockstate);
if (def == NULL)
goto done;
@ -286,7 +291,7 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld)
const Obj_Entry *defobj;
def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
false, cache);
false, cache, lockstate);
if (def == NULL)
goto done;
@ -300,7 +305,7 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld)
const Obj_Entry *defobj;
def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
false, cache);
false, cache, lockstate);
if (def == NULL)
goto done;
@ -350,7 +355,7 @@ reloc_plt(Obj_Entry *obj)
/* Relocate the jump slots in an object. */
int
reloc_jmpslots(Obj_Entry *obj)
reloc_jmpslots(Obj_Entry *obj, RtldLockState *lockstate)
{
const Elf_Rela *relalim;
const Elf_Rela *rela;
@ -365,7 +370,8 @@ reloc_jmpslots(Obj_Entry *obj)
assert(ELF_R_TYPE(rela->r_info) == R_X86_64_JMP_SLOT);
where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, true, NULL);
def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, true, NULL,
lockstate);
if (def == NULL)
return -1;
target = (Elf_Addr)(defobj->relocbase + def->st_value + rela->r_addend);

View file

@ -36,31 +36,39 @@ do_copy_relocations(Obj_Entry *dstobj)
void *dstaddr;
const Elf_Sym *dstsym;
const char *name;
unsigned long hash;
size_t size;
const void *srcaddr;
const Elf_Sym *srcsym;
Obj_Entry *srcobj;
const Ver_Entry *ve;
const Obj_Entry *srcobj, *defobj;
SymLook req;
int res;
dstaddr = (void *) (dstobj->relocbase + rel->r_offset);
dstsym = dstobj->symtab + ELF_R_SYM(rel->r_info);
name = dstobj->strtab + dstsym->st_name;
hash = elf_hash(name);
size = dstsym->st_size;
ve = fetch_ventry(dstobj, ELF_R_SYM(rel->r_info));
for (srcobj = dstobj->next; srcobj != NULL; srcobj = srcobj->next)
if ((srcsym = symlook_obj(name, hash, srcobj, ve, 0)) != NULL)
symlook_init(&req, name);
req.ventry = fetch_ventry(dstobj,
ELF_R_SYM(rel->r_info));
for (srcobj = dstobj->next; srcobj != NULL;
srcobj = srcobj->next) {
res = symlook_obj(&req, srcobj);
if (res == 0) {
srcsym = req.sym_out;
defobj = req.defobj_out;
break;
}
}
if (srcobj == NULL) {
_rtld_error("Undefined symbol \"%s\" referenced from COPY"
" relocation in %s", name, dstobj->path);
return -1;
_rtld_error(
"Undefined symbol \"%s\" referenced from COPY relocation in %s",
name, dstobj->path);
return (-1);
}
srcaddr = (const void *) (srcobj->relocbase + srcsym->st_value);
srcaddr = (const void *)(defobj->relocbase +
srcsym->st_value);
memcpy(dstaddr, srcaddr, size);
}
}
@ -123,7 +131,8 @@ store_ptr(void *where, Elf_Addr val)
}
static int
reloc_nonplt_object(Obj_Entry *obj, const Elf_Rel *rel, SymCache *cache)
reloc_nonplt_object(Obj_Entry *obj, const Elf_Rel *rel, SymCache *cache,
RtldLockState *lockstate)
{
Elf_Addr *where;
const Elf_Sym *def;
@ -149,7 +158,8 @@ reloc_nonplt_object(Obj_Entry *obj, const Elf_Rel *rel, SymCache *cache)
if (addend & 0x00800000)
addend |= 0xff000000;
def = find_symdef(symnum, obj, &defobj, false, cache);
def = find_symdef(symnum, obj, &defobj, false, cache,
lockstate);
if (def == NULL)
return -1;
tmp = (Elf_Addr)obj->relocbase + def->st_value
@ -175,7 +185,8 @@ reloc_nonplt_object(Obj_Entry *obj, const Elf_Rel *rel, SymCache *cache)
case R_ARM_ABS32: /* word32 B + S + A */
case R_ARM_GLOB_DAT: /* word32 B + S */
def = find_symdef(symnum, obj, &defobj, false, cache);
def = find_symdef(symnum, obj, &defobj, false, cache,
lockstate);
if (def == NULL)
return -1;
if (__predict_true(RELOC_ALIGNED_P(where))) {
@ -240,7 +251,7 @@ reloc_nonplt_object(Obj_Entry *obj, const Elf_Rel *rel, SymCache *cache)
* * Process non-PLT relocations
* */
int
reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld)
reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, RtldLockState *lockstate)
{
const Elf_Rel *rellim;
const Elf_Rel *rel;
@ -259,7 +270,7 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld)
rellim = (const Elf_Rel *)((caddr_t)obj->rel + obj->relsize);
for (rel = obj->rel; rel < rellim; rel++) {
if (reloc_nonplt_object(obj, rel, cache) < 0)
if (reloc_nonplt_object(obj, rel, cache, lockstate) < 0)
goto done;
}
r = 0;
@ -296,7 +307,7 @@ reloc_plt(Obj_Entry *obj)
* * LD_BIND_NOW was set - force relocation for all jump slots
* */
int
reloc_jmpslots(Obj_Entry *obj)
reloc_jmpslots(Obj_Entry *obj, RtldLockState *lockstate)
{
const Obj_Entry *defobj;
const Elf_Rel *rellim;
@ -310,7 +321,7 @@ reloc_jmpslots(Obj_Entry *obj)
assert(ELF_R_TYPE(rel->r_info) == R_ARM_JUMP_SLOT);
where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj,
true, NULL);
true, NULL, lockstate);
if (def == NULL) {
dbg("reloc_jmpslots: sym not found");
return (-1);

View file

@ -70,23 +70,28 @@ do_copy_relocations(Obj_Entry *dstobj)
void *dstaddr;
const Elf_Sym *dstsym;
const char *name;
unsigned long hash;
size_t size;
const void *srcaddr;
const Elf_Sym *srcsym;
const Ver_Entry *ve;
Obj_Entry *srcobj;
const Obj_Entry *srcobj, *defobj;
SymLook req;
int res;
dstaddr = (void *) (dstobj->relocbase + rel->r_offset);
dstsym = dstobj->symtab + ELF_R_SYM(rel->r_info);
name = dstobj->strtab + dstsym->st_name;
hash = elf_hash(name);
size = dstsym->st_size;
ve = fetch_ventry(dstobj, ELF_R_SYM(rel->r_info));
symlook_init(&req, name);
req.ventry = fetch_ventry(dstobj, ELF_R_SYM(rel->r_info));
for (srcobj = dstobj->next; srcobj != NULL; srcobj = srcobj->next)
if ((srcsym = symlook_obj(name, hash, srcobj, ve, 0)) != NULL)
for (srcobj = dstobj->next; srcobj != NULL; srcobj = srcobj->next) {
res = symlook_obj(&req, srcobj);
if (res == 0) {
srcsym = req.sym_out;
defobj = req.defobj_out;
break;
}
}
if (srcobj == NULL) {
_rtld_error("Undefined symbol \"%s\" referenced from COPY"
@ -94,7 +99,7 @@ do_copy_relocations(Obj_Entry *dstobj)
return -1;
}
srcaddr = (const void *) (srcobj->relocbase + srcsym->st_value);
srcaddr = (const void *) (defobj->relocbase + srcsym->st_value);
memcpy(dstaddr, srcaddr, size);
}
}
@ -114,7 +119,7 @@ init_pltgot(Obj_Entry *obj)
/* Process the non-PLT relocations. */
int
reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld)
reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, RtldLockState *lockstate)
{
const Elf_Rel *rellim;
const Elf_Rel *rel;
@ -146,7 +151,7 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld)
const Obj_Entry *defobj;
def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj,
false, cache);
false, cache, lockstate);
if (def == NULL)
goto done;
@ -165,7 +170,7 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld)
const Obj_Entry *defobj;
def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj,
false, cache);
false, cache, lockstate);
if (def == NULL)
goto done;
@ -195,7 +200,7 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld)
const Obj_Entry *defobj;
def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj,
false, cache);
false, cache, lockstate);
if (def == NULL)
goto done;
@ -213,7 +218,7 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld)
const Obj_Entry *defobj;
def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj,
false, cache);
false, cache, lockstate);
if (def == NULL)
goto done;
@ -243,7 +248,7 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld)
const Obj_Entry *defobj;
def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj,
false, cache);
false, cache, lockstate);
if (def == NULL)
goto done;
@ -257,7 +262,7 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld)
const Obj_Entry *defobj;
def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj,
false, cache);
false, cache, lockstate);
if (def == NULL)
goto done;
@ -301,7 +306,7 @@ reloc_plt(Obj_Entry *obj)
/* Relocate the jump slots in an object. */
int
reloc_jmpslots(Obj_Entry *obj)
reloc_jmpslots(Obj_Entry *obj, RtldLockState *lockstate)
{
const Elf_Rel *rellim;
const Elf_Rel *rel;
@ -316,7 +321,8 @@ reloc_jmpslots(Obj_Entry *obj)
assert(ELF_R_TYPE(rel->r_info) == R_386_JMP_SLOT);
where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj, true, NULL);
def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj, true, NULL,
lockstate);
if (def == NULL)
return -1;
target = (Elf_Addr)(defobj->relocbase + def->st_value);

View file

@ -151,7 +151,7 @@ free_fptrs(Obj_Entry *obj, bool mapped)
/* Relocate a non-PLT object with addend. */
static int
reloc_non_plt_obj(Obj_Entry *obj_rtld, Obj_Entry *obj, const Elf_Rela *rela,
SymCache *cache)
SymCache *cache, RtldLockState *lockstate)
{
struct fptr **fptrs;
Elf_Addr *where = (Elf_Addr *) (obj->relocbase + rela->r_offset);
@ -172,7 +172,7 @@ reloc_non_plt_obj(Obj_Entry *obj_rtld, Obj_Entry *obj, const Elf_Rela *rela,
Elf_Addr target;
def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
false, cache);
false, cache, lockstate);
if (def == NULL)
return -1;
@ -195,7 +195,7 @@ reloc_non_plt_obj(Obj_Entry *obj_rtld, Obj_Entry *obj, const Elf_Rela *rela,
int sym_index;
def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
true, cache);
true, cache, lockstate);
if (def == NULL) {
/*
* XXX r_debug_state is problematic and find_symdef()
@ -254,7 +254,7 @@ reloc_non_plt_obj(Obj_Entry *obj_rtld, Obj_Entry *obj, const Elf_Rela *rela,
Elf_Addr target, gp;
def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
false, cache);
false, cache, lockstate);
if (def == NULL)
return -1;
@ -277,7 +277,7 @@ reloc_non_plt_obj(Obj_Entry *obj_rtld, Obj_Entry *obj, const Elf_Rela *rela,
const Obj_Entry *defobj;
def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
false, cache);
false, cache, lockstate);
if (def == NULL)
return -1;
@ -290,7 +290,7 @@ reloc_non_plt_obj(Obj_Entry *obj_rtld, Obj_Entry *obj, const Elf_Rela *rela,
const Obj_Entry *defobj;
def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
false, cache);
false, cache, lockstate);
if (def == NULL)
return -1;
@ -303,7 +303,7 @@ reloc_non_plt_obj(Obj_Entry *obj_rtld, Obj_Entry *obj, const Elf_Rela *rela,
const Obj_Entry *defobj;
def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
false, cache);
false, cache, lockstate);
if (def == NULL)
return -1;
@ -342,7 +342,7 @@ reloc_non_plt_obj(Obj_Entry *obj_rtld, Obj_Entry *obj, const Elf_Rela *rela,
/* Process the non-PLT relocations. */
int
reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld)
reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, RtldLockState *lockstate)
{
const Elf_Rel *rellim;
const Elf_Rel *rel;
@ -368,14 +368,15 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld)
locrela.r_info = rel->r_info;
locrela.r_offset = rel->r_offset;
locrela.r_addend = 0;
if (reloc_non_plt_obj(obj_rtld, obj, &locrela, cache))
if (reloc_non_plt_obj(obj_rtld, obj, &locrela, cache,
lockstate))
goto done;
}
/* Perform relocations with addend if there are any: */
relalim = (const Elf_Rela *) ((caddr_t) obj->rela + obj->relasize);
for (rela = obj->rela; obj->rela != NULL && rela < relalim; rela++) {
if (reloc_non_plt_obj(obj_rtld, obj, rela, cache))
if (reloc_non_plt_obj(obj_rtld, obj, rela, cache, lockstate))
goto done;
}
@ -436,7 +437,7 @@ reloc_plt(Obj_Entry *obj)
/* Relocate the jump slots in an object. */
int
reloc_jmpslots(Obj_Entry *obj)
reloc_jmpslots(Obj_Entry *obj, RtldLockState *lockstate)
{
if (obj->jmpslots_done)
return 0;
@ -455,7 +456,7 @@ reloc_jmpslots(Obj_Entry *obj)
assert(ELF_R_TYPE(rel->r_info) == R_IA_64_IPLTLSB);
where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
def = find_symdef(ELF_R_SYM(rel->r_info), obj,
&defobj, true, NULL);
&defobj, true, NULL, lockstate);
if (def == NULL)
return -1;
reloc_jmpslot(where,
@ -476,7 +477,7 @@ reloc_jmpslots(Obj_Entry *obj)
where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
def = find_symdef(ELF_R_SYM(rela->r_info), obj,
&defobj, true, NULL);
&defobj, true, NULL, lockstate);
if (def == NULL)
return -1;
reloc_jmpslot(where,

View file

@ -238,7 +238,8 @@ _mips_rtld_bind(Obj_Entry *obj, Elf_Size reloff)
const Obj_Entry *defobj;
Elf_Addr target;
def = find_symdef(reloff, obj, &defobj, SYMLOOK_IN_PLT, NULL);
def = find_symdef(reloff, obj, &defobj, SYMLOOK_IN_PLT, NULL,
NULL);
if (def == NULL)
_rtld_error("bind failed no symbol");
@ -253,7 +254,7 @@ _mips_rtld_bind(Obj_Entry *obj, Elf_Size reloff)
}
int
reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld)
reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, RtldLockState *lockstate)
{
const Elf_Rel *rel;
const Elf_Rel *rellim;
@ -312,7 +313,8 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld)
* to 0 if there are non-PLT references, but older
* versions of GNU ld do not do this.
*/
def = find_symdef(i, obj, &defobj, false, NULL);
def = find_symdef(i, obj, &defobj, false, NULL,
lockstate);
if (def == NULL)
return -1;
*got = def->st_value + (Elf_Addr)defobj->relocbase;
@ -353,7 +355,8 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld)
}
} else {
/* TODO: add cache here */
def = find_symdef(i, obj, &defobj, false, NULL);
def = find_symdef(i, obj, &defobj, false, NULL,
lockstate);
if (def == NULL) {
dbg("Warning4, cant find symbole %d", i);
return -1;
@ -487,7 +490,7 @@ reloc_plt(Obj_Entry *obj)
* LD_BIND_NOW was set - force relocation for all jump slots
*/
int
reloc_jmpslots(Obj_Entry *obj)
reloc_jmpslots(Obj_Entry *obj, RtldLockState *lockstate)
{
/* Do nothing */
obj->jmpslots_done = true;

View file

@ -75,12 +75,12 @@ do_copy_relocations(Obj_Entry *dstobj)
void *dstaddr;
const Elf_Sym *dstsym;
const char *name;
unsigned long hash;
size_t size;
const void *srcaddr;
const Elf_Sym *srcsym = NULL;
Obj_Entry *srcobj;
const Ver_Entry *ve;
const Obj_Entry *srcobj, *defobj;
SymLook req;
int res;
if (ELF_R_TYPE(rela->r_info) != R_PPC_COPY) {
continue;
@ -89,14 +89,16 @@ do_copy_relocations(Obj_Entry *dstobj)
dstaddr = (void *) (dstobj->relocbase + rela->r_offset);
dstsym = dstobj->symtab + ELF_R_SYM(rela->r_info);
name = dstobj->strtab + dstsym->st_name;
hash = elf_hash(name);
size = dstsym->st_size;
ve = fetch_ventry(dstobj, ELF_R_SYM(rela->r_info));
symlook_init(&req, name);
req.ventry = fetch_ventry(dstobj, ELF_R_SYM(rela->r_info));
for (srcobj = dstobj->next; srcobj != NULL;
srcobj = srcobj->next) {
if ((srcsym = symlook_obj(name, hash, srcobj, ve, 0))
!= NULL) {
res = symlook_obj(&req, srcobj);
if (res == 0) {
srcsym = req.sym_out;
defobj = req.defobj_out;
break;
}
}
@ -108,7 +110,7 @@ do_copy_relocations(Obj_Entry *dstobj)
return (-1);
}
srcaddr = (const void *) (srcobj->relocbase+srcsym->st_value);
srcaddr = (const void *) (defobj->relocbase+srcsym->st_value);
memcpy(dstaddr, srcaddr, size);
dbg("copy_reloc: src=%p,dst=%p,size=%d\n",srcaddr,dstaddr,size);
}
@ -157,7 +159,7 @@ reloc_non_plt_self(Elf_Dyn *dynp, Elf_Addr relocbase)
*/
static int
reloc_nonplt_object(Obj_Entry *obj_rtld, Obj_Entry *obj, const Elf_Rela *rela,
SymCache *cache)
SymCache *cache, RtldLockState *lockstate)
{
Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
const Elf_Sym *def;
@ -172,7 +174,7 @@ reloc_nonplt_object(Obj_Entry *obj_rtld, Obj_Entry *obj, const Elf_Rela *rela,
case R_PPC_ADDR32: /* word32 S + A */
case R_PPC_GLOB_DAT: /* word32 S + A */
def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
false, cache);
false, cache, lockstate);
if (def == NULL) {
return (-1);
}
@ -219,7 +221,7 @@ reloc_nonplt_object(Obj_Entry *obj_rtld, Obj_Entry *obj, const Elf_Rela *rela,
case R_PPC_DTPMOD32:
def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
false, cache);
false, cache, lockstate);
if (def == NULL)
return (-1);
@ -230,7 +232,7 @@ reloc_nonplt_object(Obj_Entry *obj_rtld, Obj_Entry *obj, const Elf_Rela *rela,
case R_PPC_TPREL32:
def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
false, cache);
false, cache, lockstate);
if (def == NULL)
return (-1);
@ -259,7 +261,7 @@ reloc_nonplt_object(Obj_Entry *obj_rtld, Obj_Entry *obj, const Elf_Rela *rela,
case R_PPC_DTPREL32:
def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
false, cache);
false, cache, lockstate);
if (def == NULL)
return (-1);
@ -283,7 +285,7 @@ reloc_nonplt_object(Obj_Entry *obj_rtld, Obj_Entry *obj, const Elf_Rela *rela,
* Process non-PLT relocations
*/
int
reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld)
reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, RtldLockState *lockstate)
{
const Elf_Rela *relalim;
const Elf_Rela *rela;
@ -307,7 +309,8 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld)
*/
relalim = (const Elf_Rela *)((caddr_t)obj->rela + obj->relasize);
for (rela = obj->rela; rela < relalim; rela++) {
if (reloc_nonplt_object(obj_rtld, obj, rela, cache) < 0)
if (reloc_nonplt_object(obj_rtld, obj, rela, cache, lockstate)
< 0)
goto done;
}
r = 0;
@ -401,7 +404,7 @@ reloc_plt(Obj_Entry *obj)
* LD_BIND_NOW was set - force relocation for all jump slots
*/
int
reloc_jmpslots(Obj_Entry *obj)
reloc_jmpslots(Obj_Entry *obj, RtldLockState *lockstate)
{
const Obj_Entry *defobj;
const Elf_Rela *relalim;
@ -415,7 +418,7 @@ reloc_jmpslots(Obj_Entry *obj)
assert(ELF_R_TYPE(rela->r_info) == R_PPC_JMP_SLOT);
where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
true, NULL);
true, NULL, lockstate);
if (def == NULL) {
dbg("reloc_jmpslots: sym not found");
return (-1);

View file

@ -69,12 +69,12 @@ do_copy_relocations(Obj_Entry *dstobj)
void *dstaddr;
const Elf_Sym *dstsym;
const char *name;
unsigned long hash;
size_t size;
const void *srcaddr;
const Elf_Sym *srcsym = NULL;
Obj_Entry *srcobj;
const Ver_Entry *ve;
const Obj_Entry *srcobj, *defobj;
SymLook req;
int res;
if (ELF_R_TYPE(rela->r_info) != R_PPC_COPY) {
continue;
@ -83,14 +83,16 @@ do_copy_relocations(Obj_Entry *dstobj)
dstaddr = (void *) (dstobj->relocbase + rela->r_offset);
dstsym = dstobj->symtab + ELF_R_SYM(rela->r_info);
name = dstobj->strtab + dstsym->st_name;
hash = elf_hash(name);
size = dstsym->st_size;
ve = fetch_ventry(dstobj, ELF_R_SYM(rela->r_info));
symlook_init(&req, name);
req.ventry = fetch_ventry(dstobj, ELF_R_SYM(rela->r_info));
for (srcobj = dstobj->next; srcobj != NULL;
srcobj = srcobj->next) {
if ((srcsym = symlook_obj(name, hash, srcobj, ve, 0))
!= NULL) {
res = symlook_obj(&req, srcobj);
if (res == 0) {
srcsym = req.sym_out;
defobj = req.defobj_out;
break;
}
}
@ -102,7 +104,7 @@ do_copy_relocations(Obj_Entry *dstobj)
return (-1);
}
srcaddr = (const void *) (srcobj->relocbase+srcsym->st_value);
srcaddr = (const void *) (defobj->relocbase+srcsym->st_value);
memcpy(dstaddr, srcaddr, size);
dbg("copy_reloc: src=%p,dst=%p,size=%zd\n",srcaddr,dstaddr,size);
}
@ -151,7 +153,7 @@ reloc_non_plt_self(Elf_Dyn *dynp, Elf_Addr relocbase)
*/
static int
reloc_nonplt_object(Obj_Entry *obj_rtld, Obj_Entry *obj, const Elf_Rela *rela,
SymCache *cache)
SymCache *cache, RtldLockState *lockstate)
{
Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
const Elf_Sym *def;
@ -166,7 +168,7 @@ reloc_nonplt_object(Obj_Entry *obj_rtld, Obj_Entry *obj, const Elf_Rela *rela,
case R_PPC64_ADDR64: /* doubleword64 S + A */
case R_PPC_GLOB_DAT:
def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
false, cache);
false, cache, lockstate);
if (def == NULL) {
return (-1);
}
@ -213,7 +215,7 @@ reloc_nonplt_object(Obj_Entry *obj_rtld, Obj_Entry *obj, const Elf_Rela *rela,
case R_PPC64_DTPMOD64:
def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
false, cache);
false, cache, lockstate);
if (def == NULL)
return (-1);
@ -224,7 +226,7 @@ reloc_nonplt_object(Obj_Entry *obj_rtld, Obj_Entry *obj, const Elf_Rela *rela,
case R_PPC64_TPREL64:
def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
false, cache);
false, cache, lockstate);
if (def == NULL)
return (-1);
@ -253,7 +255,7 @@ reloc_nonplt_object(Obj_Entry *obj_rtld, Obj_Entry *obj, const Elf_Rela *rela,
case R_PPC64_DTPREL64:
def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
false, cache);
false, cache, lockstate);
if (def == NULL)
return (-1);
@ -277,7 +279,7 @@ reloc_nonplt_object(Obj_Entry *obj_rtld, Obj_Entry *obj, const Elf_Rela *rela,
* Process non-PLT relocations
*/
int
reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld)
reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, RtldLockState *lockstate)
{
const Elf_Rela *relalim;
const Elf_Rela *rela;
@ -304,7 +306,8 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld)
*/
relalim = (const Elf_Rela *)((caddr_t)obj->rela + obj->relasize);
for (rela = obj->rela; rela < relalim; rela++) {
if (reloc_nonplt_object(obj_rtld, obj, rela, cache) < 0)
if (reloc_nonplt_object(obj_rtld, obj, rela, cache, lockstate)
< 0)
goto done;
}
r = 0;
@ -376,7 +379,7 @@ reloc_plt(Obj_Entry *obj)
* LD_BIND_NOW was set - force relocation for all jump slots
*/
int
reloc_jmpslots(Obj_Entry *obj)
reloc_jmpslots(Obj_Entry *obj, RtldLockState *lockstate)
{
const Obj_Entry *defobj;
const Elf_Rela *relalim;
@ -390,7 +393,7 @@ reloc_jmpslots(Obj_Entry *obj)
assert(ELF_R_TYPE(rela->r_info) == R_PPC_JMP_SLOT);
where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
true, NULL);
true, NULL, lockstate);
if (def == NULL) {
dbg("reloc_jmpslots: sym not found");
return (-1);

View file

@ -221,6 +221,14 @@ If set,
.Nm
will log events such as the loading and unloading of shared objects via
.Xr utrace 2 .
.Pp
.It Ev LD_LOADFLTR
If set,
.Nm
will process the filtee dependencies of the loaded objects immediately,
instead of postponing it until required.
Normally, the filtees are opened at the time of the first symbol resolution
from the filter object.
.El
.Sh FILES
.Bl -tag -width ".Pa /var/run/ld-elf32.so.hints" -compact

File diff suppressed because it is too large Load diff

View file

@ -34,6 +34,7 @@
#include <elf-hints.h>
#include <link.h>
#include <setjmp.h>
#include <stddef.h>
#include "rtld_lock.h"
@ -197,6 +198,8 @@ typedef struct Struct_Obj_Entry {
char *rpath; /* Search path specified in object */
Needed_Entry *needed; /* Shared objects needed by this one (%) */
Needed_Entry *needed_filtees;
Needed_Entry *needed_aux_filtees;
STAILQ_HEAD(, Struct_Name_Entry) names; /* List of names for this object we
know about. */
@ -219,10 +222,12 @@ typedef struct Struct_Obj_Entry {
bool z_origin : 1; /* Process rpath and soname tokens */
bool z_nodelete : 1; /* Do not unload the object and dependencies */
bool z_noopen : 1; /* Do not load on dlopen */
bool z_loadfltr : 1; /* Immediately load filtees */
bool ref_nodel : 1; /* Refcount increased to prevent dlclose */
bool init_scanned: 1; /* Object is already on init list. */
bool on_fini_list: 1; /* Object is already on fini list. */
bool dag_inited : 1; /* Object has its DAG initialized. */
bool filtees_loaded : 1; /* Filtees loaded */
struct link_map linkmap; /* For GDB and dlinfo() */
Objlist dldags; /* Object belongs to these dlopened DAGs (%) */
@ -246,6 +251,8 @@ typedef struct Struct_Obj_Entry {
#define RTLD_LO_NOLOAD 0x01 /* dlopen() specified RTLD_NOLOAD. */
#define RTLD_LO_DLOPEN 0x02 /* Load_object() called from dlopen(). */
#define RTLD_LO_TRACE 0x04 /* Only tracing. */
#define RTLD_LO_NODELETE 0x08 /* Loaded object cannot be closed. */
#define RTLD_LO_FILTEES 0x10 /* Loading filtee. */
/*
* Symbol cache entry used during relocation to avoid multiple lookups
@ -256,6 +263,34 @@ typedef struct Struct_SymCache {
const Obj_Entry *obj; /* Shared object which defines it */
} SymCache;
/*
* This structure provides a reentrant way to keep a list of objects and
* check which ones have already been processed in some way.
*/
typedef struct Struct_DoneList {
const Obj_Entry **objs; /* Array of object pointers */
unsigned int num_alloc; /* Allocated size of the array */
unsigned int num_used; /* Number of array slots used */
} DoneList;
struct Struct_RtldLockState {
int lockstate;
jmp_buf env;
};
/*
* The pack of arguments and results for the symbol lookup functions.
*/
typedef struct Struct_SymLook {
const char *name;
unsigned long hash;
const Ver_Entry *ventry;
int flags;
const Obj_Entry *defobj_out;
const Elf_Sym *sym_out;
struct Struct_RtldLockState *lockstate;
} SymLook;
extern void _rtld_error(const char *, ...) __printflike(1, 2);
extern Obj_Entry *map_object(int, const char *, const struct stat *);
extern void *xcalloc(size_t);
@ -274,14 +309,14 @@ extern void dump_Elf_Rela (Obj_Entry *, const Elf_Rela *, u_long);
*/
unsigned long elf_hash(const char *);
const Elf_Sym *find_symdef(unsigned long, const Obj_Entry *,
const Obj_Entry **, int, SymCache *);
const Obj_Entry **, int, SymCache *, struct Struct_RtldLockState *);
void init_pltgot(Obj_Entry *);
void lockdflt_init(void);
void obj_free(Obj_Entry *);
Obj_Entry *obj_new(void);
void _rtld_bind_start(void);
const Elf_Sym *symlook_obj(const char *, unsigned long, const Obj_Entry *,
const Ver_Entry *, int);
void symlook_init(SymLook *, const char *);
int symlook_obj(SymLook *, const Obj_Entry *);
void *tls_get_addr_common(Elf_Addr** dtvp, int index, size_t offset);
void *allocate_tls(Obj_Entry *, void *, size_t, size_t);
void free_tls(void *, size_t, size_t);
@ -294,9 +329,9 @@ const Ver_Entry *fetch_ventry(const Obj_Entry *obj, unsigned long);
* MD function declarations.
*/
int do_copy_relocations(Obj_Entry *);
int reloc_non_plt(Obj_Entry *, Obj_Entry *);
int reloc_non_plt(Obj_Entry *, Obj_Entry *, struct Struct_RtldLockState *);
int reloc_plt(Obj_Entry *);
int reloc_jmpslots(Obj_Entry *);
int reloc_jmpslots(Obj_Entry *, struct Struct_RtldLockState *);
void allocate_initial_tls(Obj_Entry *);
#endif /* } */

View file

@ -43,7 +43,6 @@
*/
#include <sys/param.h>
#include <signal.h>
#include <stdlib.h>
#include <time.h>
@ -183,44 +182,88 @@ rtld_lock_t rtld_bind_lock = &rtld_locks[0];
rtld_lock_t rtld_libc_lock = &rtld_locks[1];
rtld_lock_t rtld_phdr_lock = &rtld_locks[2];
int
rlock_acquire(rtld_lock_t lock)
#define print_ebp(str) do {register long ebp asm("ebp"); printf("%s 0x%0lx\n", str, ebp);} while (0)
void
rlock_acquire(rtld_lock_t lock, RtldLockState *lockstate)
{
if (lockstate == NULL)
return;
if (thread_mask_set(lock->mask) & lock->mask) {
dbg("rlock_acquire: recursed");
return (0);
dbg("rlock_acquire: recursed");
lockstate->lockstate = RTLD_LOCK_UNLOCKED;
return;
}
lockinfo.rlock_acquire(lock->handle);
return (1);
lockstate->lockstate = RTLD_LOCK_RLOCKED;
}
int
wlock_acquire(rtld_lock_t lock)
void
wlock_acquire(rtld_lock_t lock, RtldLockState *lockstate)
{
if (lockstate == NULL)
return;
if (thread_mask_set(lock->mask) & lock->mask) {
dbg("wlock_acquire: recursed");
return (0);
dbg("wlock_acquire: recursed");
lockstate->lockstate = RTLD_LOCK_UNLOCKED;
return;
}
lockinfo.wlock_acquire(lock->handle);
return (1);
lockstate->lockstate = RTLD_LOCK_WLOCKED;
}
void
rlock_release(rtld_lock_t lock, int locked)
lock_release(rtld_lock_t lock, RtldLockState *lockstate)
{
if (locked == 0)
return;
thread_mask_clear(lock->mask);
lockinfo.lock_release(lock->handle);
if (lockstate == NULL)
return;
switch (lockstate->lockstate) {
case RTLD_LOCK_UNLOCKED:
break;
case RTLD_LOCK_RLOCKED:
case RTLD_LOCK_WLOCKED:
thread_mask_clear(lock->mask);
lockinfo.lock_release(lock->handle);
break;
default:
assert(0);
}
}
void
wlock_release(rtld_lock_t lock, int locked)
lock_upgrade(rtld_lock_t lock, RtldLockState *lockstate)
{
if (locked == 0)
return;
thread_mask_clear(lock->mask);
lockinfo.lock_release(lock->handle);
if (lockstate == NULL)
return;
lock_release(lock, lockstate);
wlock_acquire(lock, lockstate);
}
void
lock_restart_for_upgrade(RtldLockState *lockstate)
{
if (lockstate == NULL)
return;
switch (lockstate->lockstate) {
case RTLD_LOCK_UNLOCKED:
case RTLD_LOCK_WLOCKED:
break;
case RTLD_LOCK_RLOCKED:
longjmp(lockstate->env, 1);
break;
default:
assert(0);
}
}
void
@ -322,15 +365,24 @@ _rtld_thread_init(struct RtldLockInfo *pli)
void
_rtld_atfork_pre(int *locks)
{
RtldLockState ls[2];
locks[2] = wlock_acquire(rtld_phdr_lock);
locks[0] = rlock_acquire(rtld_bind_lock);
wlock_acquire(rtld_phdr_lock, &ls[0]);
rlock_acquire(rtld_bind_lock, &ls[1]);
/* XXXKIB: I am really sorry for this. */
locks[0] = ls[1].lockstate;
locks[2] = ls[0].lockstate;
}
void
_rtld_atfork_post(int *locks)
{
RtldLockState ls[2];
rlock_release(rtld_bind_lock, locks[0]);
wlock_release(rtld_phdr_lock, locks[2]);
bzero(ls, sizeof(ls));
ls[0].lockstate = locks[2];
ls[1].lockstate = locks[0];
lock_release(rtld_bind_lock, &ls[1]);
lock_release(rtld_phdr_lock, &ls[0]);
}

View file

@ -57,10 +57,18 @@ extern rtld_lock_t rtld_bind_lock;
extern rtld_lock_t rtld_libc_lock;
extern rtld_lock_t rtld_phdr_lock;
int rlock_acquire(rtld_lock_t);
int wlock_acquire(rtld_lock_t);
void rlock_release(rtld_lock_t, int);
void wlock_release(rtld_lock_t, int);
#define RTLD_LOCK_UNLOCKED 0
#define RTLD_LOCK_RLOCKED 1
#define RTLD_LOCK_WLOCKED 2
struct Struct_RtldLockState;
typedef struct Struct_RtldLockState RtldLockState;
void rlock_acquire(rtld_lock_t, RtldLockState *);
void wlock_acquire(rtld_lock_t, RtldLockState *);
void lock_release(rtld_lock_t, RtldLockState *);
void lock_upgrade(rtld_lock_t, RtldLockState *);
void lock_restart_for_upgrade(RtldLockState *);
#endif /* IN_RTLD */

View file

@ -193,7 +193,7 @@ static const long reloc_target_bitmask[] = {
__asm __volatile("flush %0 + %1" : : "r" (va), "I" (offs));
static int reloc_nonplt_object(Obj_Entry *obj, const Elf_Rela *rela,
SymCache *cache);
SymCache *cache, RtldLockState *lockstate);
static void install_plt(Elf_Word *pltgot, Elf_Addr proc);
extern char _rtld_bind_start_0[];
@ -206,13 +206,13 @@ do_copy_relocations(Obj_Entry *dstobj)
const Elf_Rela *rela;
const Elf_Sym *dstsym;
const Elf_Sym *srcsym;
const Ver_Entry *ve;
void *dstaddr;
const void *srcaddr;
Obj_Entry *srcobj;
unsigned long hash;
const Obj_Entry *srcobj, *defobj;
SymLook req;
const char *name;
size_t size;
int res;
assert(dstobj->mainprog); /* COPY relocations are invalid elsewhere */
@ -222,16 +222,20 @@ do_copy_relocations(Obj_Entry *dstobj)
dstaddr = (void *)(dstobj->relocbase + rela->r_offset);
dstsym = dstobj->symtab + ELF_R_SYM(rela->r_info);
name = dstobj->strtab + dstsym->st_name;
hash = elf_hash(name);
size = dstsym->st_size;
ve = fetch_ventry(dstobj, ELF_R_SYM(rela->r_info));
symlook_init(&req, name);
req.ventry = fetch_ventry(dstobj,
ELF_R_SYM(rela->r_info));
for (srcobj = dstobj->next; srcobj != NULL;
srcobj = srcobj->next)
if ((srcsym = symlook_obj(name, hash, srcobj,
ve, 0)) != NULL)
srcobj = srcobj->next) {
res = symlook_obj(&req, srcobj);
if (res == 0) {
srcsym = req.sym_out;
defobj = req.defobj_out;
break;
}
}
if (srcobj == NULL) {
_rtld_error("Undefined symbol \"%s\""
"referenced from COPY relocation"
@ -239,7 +243,7 @@ do_copy_relocations(Obj_Entry *dstobj)
return (-1);
}
srcaddr = (const void *)(srcobj->relocbase +
srcaddr = (const void *)(defobj->relocbase +
srcsym->st_value);
memcpy(dstaddr, srcaddr, size);
}
@ -249,7 +253,7 @@ do_copy_relocations(Obj_Entry *dstobj)
}
int
reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld)
reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, RtldLockState *lockstate)
{
const Elf_Rela *relalim;
const Elf_Rela *rela;
@ -268,7 +272,7 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld)
relalim = (const Elf_Rela *)((caddr_t)obj->rela + obj->relasize);
for (rela = obj->rela; rela < relalim; rela++) {
if (reloc_nonplt_object(obj, rela, cache) < 0)
if (reloc_nonplt_object(obj, rela, cache, lockstate) < 0)
goto done;
}
r = 0;
@ -279,7 +283,8 @@ done:
}
static int
reloc_nonplt_object(Obj_Entry *obj, const Elf_Rela *rela, SymCache *cache)
reloc_nonplt_object(Obj_Entry *obj, const Elf_Rela *rela, SymCache *cache,
RtldLockState *lockstate)
{
const Obj_Entry *defobj;
const Elf_Sym *def;
@ -333,7 +338,7 @@ reloc_nonplt_object(Obj_Entry *obj, const Elf_Rela *rela, SymCache *cache)
/* Find the symbol */
def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
false, cache);
false, cache, lockstate);
if (def == NULL)
return (-1);
@ -416,7 +421,7 @@ reloc_plt(Obj_Entry *obj)
assert(ELF64_R_TYPE_ID(rela->r_info) == R_SPARC_JMP_SLOT);
where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
true, NULL);
true, NULL, lockstate);
value = (Elf_Addr)(defobj->relocbase + def->st_value);
*where = value;
}
@ -446,7 +451,7 @@ reloc_plt(Obj_Entry *obj)
#define LOVAL(v) ((v) & 0x000003ff)
int
reloc_jmpslots(Obj_Entry *obj)
reloc_jmpslots(Obj_Entry *obj, RtldLockState *lockstate)
{
const Obj_Entry *defobj;
const Elf_Rela *relalim;
@ -460,7 +465,7 @@ reloc_jmpslots(Obj_Entry *obj)
assert(ELF64_R_TYPE_ID(rela->r_info) == R_SPARC_JMP_SLOT);
where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
true, NULL);
true, NULL, lockstate);
if (def == NULL)
return -1;
target = (Elf_Addr)(defobj->relocbase + def->st_value);