summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorarun <arun@FreeBSD.org>2003-03-19 21:38:27 +0000
committerarun <arun@FreeBSD.org>2003-03-19 21:38:27 +0000
commit59b094fe433df03e75ead72dc2feac3c6b20c554 (patch)
tree48b49cf655cea33bbf150155b3de32f83528c7b6
parentcfb004fe959c0ce2e32c72351c5b39514dec8042 (diff)
downloadFreeBSD-src-59b094fe433df03e75ead72dc2feac3c6b20c554.zip
FreeBSD-src-59b094fe433df03e75ead72dc2feac3c6b20c554.tar.gz
Fix for ia64/48024 - ensure function pointer equality across elf
objects. Programs such as sshd depend on two pointers to the same function being equal in a given process. However, the current ia64 implementation ensures that they're equal when both the pointers are instantiated in the same ELF object. The attached patch ensures that they're equal irrespective of where they're instantiated. Reviewed by marcel@ (mentor) and kan@
-rw-r--r--libexec/rtld-elf/ia64/reloc.c129
1 files changed, 77 insertions, 52 deletions
diff --git a/libexec/rtld-elf/ia64/reloc.c b/libexec/rtld-elf/ia64/reloc.c
index 8c63073..7db2823 100644
--- a/libexec/rtld-elf/ia64/reloc.c
+++ b/libexec/rtld-elf/ia64/reloc.c
@@ -98,11 +98,62 @@ alloc_fptr(Elf_Addr target, Elf_Addr gp)
return fptr;
}
+static struct fptr **
+alloc_fptrs(Obj_Entry *obj, bool mapped)
+{
+ struct fptr **fptrs;
+ size_t fbytes;
+
+ fbytes = obj->nchains * sizeof(struct fptr *);
+
+ /*
+ * Avoid malloc, if requested. Happens when relocating
+ * rtld itself on startup.
+ */
+ if (mapped) {
+ fptrs = mmap(NULL, fbytes, PROT_READ|PROT_WRITE,
+ MAP_ANON, -1, 0);
+ if (fptrs == MAP_FAILED)
+ fptrs = NULL;
+ } else {
+ fptrs = malloc(fbytes);
+ if (fptrs != NULL)
+ memset(fptrs, 0, fbytes);
+ }
+
+ /*
+ * This assertion is necessary to guarantee function pointer
+ * uniqueness
+ */
+ assert(fptrs != NULL);
+
+ return (obj->priv = fptrs);
+}
+
+static void
+free_fptrs(Obj_Entry *obj, bool mapped)
+{
+ struct fptr **fptrs;
+ size_t fbytes;
+
+ fptrs = obj->priv;
+ if (fptrs == NULL)
+ return;
+
+ fbytes = obj->nchains * sizeof(struct fptr *);
+ if (mapped)
+ munmap(fptrs, fbytes);
+ else
+ free(fptrs);
+ obj->priv = NULL;
+}
+
/* 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, struct fptr **fptrs)
+ SymCache *cache)
{
+ struct fptr **fptrs;
Elf_Addr *where = (Elf_Addr *) (obj->relocbase + rela->r_offset);
switch (ELF_R_TYPE(rela->r_info)) {
@@ -135,14 +186,13 @@ reloc_non_plt_obj(Obj_Entry *obj_rtld, Obj_Entry *obj, const Elf_Rela *rela,
/*
* We have to make sure that all @fptr references to
* the same function are identical so that code can
- * compare function pointers. We actually only bother
- * to ensure this within a single object. If the
- * caller's alloca failed, we don't even ensure that.
+ * compare function pointers.
*/
const Elf_Sym *def;
const Obj_Entry *defobj;
struct fptr *fptr = 0;
Elf_Addr target, gp;
+ int sym_index;
def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
false, cache);
@@ -153,15 +203,24 @@ reloc_non_plt_obj(Obj_Entry *obj_rtld, Obj_Entry *obj, const Elf_Rela *rela,
target = (Elf_Addr)(defobj->relocbase + def->st_value);
gp = (Elf_Addr)defobj->pltgot;
+ /* rtld is allowed to reference itself only */
+ assert(!obj->rtld || obj == defobj);
+ fptrs = defobj->priv;
+ if (fptrs == NULL)
+ fptrs = alloc_fptrs((Obj_Entry *) defobj,
+ obj->rtld);
+
+ sym_index = def - defobj->symtab;
+
/*
* Find the @fptr, using fptrs as a helper.
*/
if (fptrs)
- fptr = fptrs[ELF_R_SYM(rela->r_info)];
+ fptr = fptrs[sym_index];
if (!fptr) {
fptr = alloc_fptr(target, gp);
if (fptrs)
- fptrs[ELF_R_SYM(rela->r_info)] = fptr;
+ fptrs[sym_index] = fptr;
}
} else
fptr = NULL;
@@ -219,9 +278,7 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld)
const Elf_Rela *relalim;
const Elf_Rela *rela;
SymCache *cache;
- struct fptr **fptrs;
int bytes = obj->nchains * sizeof(SymCache);
- int fbytes = obj->nchains * sizeof(struct fptr *);
int r = -1;
/*
@@ -232,22 +289,6 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld)
if (cache == MAP_FAILED)
cache = NULL;
- /*
- * When relocating rtld itself, we need to avoid using malloc.
- */
- if (obj == obj_rtld) {
- fptrs = mmap(NULL, fbytes, PROT_READ|PROT_WRITE,
- MAP_ANON, -1, 0);
- if (fptrs == MAP_FAILED)
- fptrs = NULL;
- } else {
- fptrs = (struct fptr **)
- malloc(obj->nchains * sizeof(struct fptr *));
- }
- if (fptrs == NULL)
- goto done;
- memset(fptrs, 0, fbytes);
-
/* Perform relocations without addend if there are any: */
rellim = (const Elf_Rel *) ((caddr_t) obj->rel + obj->relsize);
for (rel = obj->rel; obj->rel != NULL && rel < rellim; rel++) {
@@ -256,43 +297,30 @@ 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, fptrs))
+ if (reloc_non_plt_obj(obj_rtld, obj, &locrela, cache))
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, fptrs))
+ if (reloc_non_plt_obj(obj_rtld, obj, rela, cache))
goto done;
}
- /*
- * Remember the fptrs in case of later calls to dlsym(). Don't
- * bother for rtld - we will lazily create a table in
- * make_function_pointer(). We still can't risk calling malloc()
- * in the rtld case.
- *
- * When remembering fptrs, NULL out our local fptrs variable so we
- * do not free it.
- */
- if (obj == obj_rtld) {
- obj->priv = NULL;
- } else {
- obj->priv = fptrs;
- fptrs = NULL;
- }
-
r = 0;
done:
if (cache)
munmap(cache, bytes);
- if (fptrs) {
- if (obj == obj_rtld)
- munmap(fptrs, fbytes);
- else
- free(fptrs);
- }
+
+ /*
+ * Release temporarily mapped fptrs if relocating
+ * rtld object itself. A new table will be created
+ * in make_function_pointer using malloc when needed.
+ */
+ if (obj->rtld && obj->priv)
+ free_fptrs(obj, true);
+
return (r);
}
@@ -447,10 +475,7 @@ make_function_pointer(const Elf_Sym *sym, const Obj_Entry *obj)
* dlsym("dlopen"). Actually, I'm not sure it can ever
* happen.
*/
- fptrs = (struct fptr **)
- malloc(obj->nchains * sizeof(struct fptr *));
- memset(fptrs, 0, obj->nchains * sizeof(struct fptr *));
- ((Obj_Entry*) obj)->priv = fptrs;
+ fptrs = alloc_fptrs((Obj_Entry *) obj, false);
}
if (!fptrs[index]) {
Elf_Addr target, gp;
OpenPOWER on IntegriCloud