Example #1
0
int
_dl_md_reloc_got(elf_object_t *object, int lazy)
{
	extern void _dl_bind_start(void);	/* XXX */
	int	fails = 0;
	Elf_Addr *pltgot = (Elf_Addr *)object->Dyn.info[DT_PLTGOT];
	int i, num;
	Elf_RelA *rel;

	if (pltgot == NULL)
		return (0); /* it is possible to have no PLT/GOT relocations */

	if (object->Dyn.info[DT_PLTREL] != DT_RELA)
		return (0);

	if (object->traced)
		lazy = 1;

	if (__predict_false(!lazy)) {
		fails = _dl_md_reloc(object, DT_JMPREL, DT_PLTRELSZ);
	} else {
		pltgot[1] = (Elf_Addr)object;
		pltgot[2] = (Elf_Addr)&_dl_bind_start;

		rel = (Elf_RelA *)(object->Dyn.info[DT_JMPREL]);
		num = (object->Dyn.info[DT_PLTRELSZ]);
		for (i = 0; i < num/sizeof(Elf_RelA); i++, rel++) {
			Elf_Addr *where;
			where = (Elf_Addr *)(rel->r_offset + object->obj_base);
			*where += object->obj_base;
		}
	}

	/* mprotect the GOT */
	_dl_protect_segment(object, 0, "__got_start", "__got_end", PROT_READ);

	return (fails);
}
Example #2
0
/*
 *	Relocate the Global Offset Table (GOT).
 */
int
_dl_md_reloc_got(elf_object_t *object, int lazy)
{
	int	fails = 0;
	Elf_Addr *pltgot;
	extern void _dl_bind_start(void);	/* XXX */
	Elf_Addr ooff;
	Elf_Addr plt_addr;
	const Elf_Sym *this;


	pltgot = (Elf_Addr *)object->Dyn.info[DT_PLTGOT];

	object->got_addr = 0;
	object->got_size = 0;
	this = NULL;
	ooff = _dl_find_symbol("__got_start", &this,
	    SYM_SEARCH_OBJ|SYM_NOWARNNOTFOUND|SYM_PLT, NULL, object, NULL);
	if (this != NULL)
		object->got_addr = ooff + this->st_value;

	this = NULL;
	ooff = _dl_find_symbol("__got_end", &this,
	    SYM_SEARCH_OBJ|SYM_NOWARNNOTFOUND|SYM_PLT, NULL, object, NULL);
	if (this != NULL)
		object->got_size = ooff + this->st_value  - object->got_addr;

	plt_addr = 0;
	object->plt_size = 0;
	this = NULL;
	ooff = _dl_find_symbol("__plt_start", &this,
	    SYM_SEARCH_OBJ|SYM_NOWARNNOTFOUND|SYM_PLT, NULL, object, NULL);
	if (this != NULL)
		plt_addr = ooff + this->st_value;

	this = NULL;
	ooff = _dl_find_symbol("__plt_end", &this,
	    SYM_SEARCH_OBJ|SYM_NOWARNNOTFOUND|SYM_PLT, NULL, object, NULL);
	if (this != NULL)
		object->plt_size = ooff + this->st_value  - plt_addr;

	if (object->got_addr == 0)
		object->got_start = 0;
	else {
		object->got_start = ELF_TRUNC(object->got_addr, _dl_pagesz);
		object->got_size += object->got_addr - object->got_start;
		object->got_size = ELF_ROUND(object->got_size, _dl_pagesz);
	}
	if (plt_addr == 0)
		object->plt_start = 0;
	else {
		object->plt_start = ELF_TRUNC(plt_addr, _dl_pagesz);
		object->plt_size += plt_addr - object->plt_start;
		object->plt_size = ELF_ROUND(object->plt_size, _dl_pagesz);
	}

	if (object->obj_type == OBJTYPE_LDR || !lazy || pltgot == NULL) {
		fails = _dl_md_reloc(object, DT_JMPREL, DT_PLTRELSZ);
	} else {
		if (object->obj_base != 0) {
			int i, size;
			Elf_Addr *addr;
			Elf_RelA *rela;

			size = object->Dyn.info[DT_PLTRELSZ] /
			    sizeof(Elf_RelA);
			rela = (Elf_RelA *)(object->Dyn.info[DT_JMPREL]);

			for (i = 0; i < size; i++) {
				addr = (Elf_Addr *)(object->obj_base +
				    rela[i].r_offset);
				*addr += object->obj_base;
			}
		}
	}
	if (pltgot != NULL) {
		pltgot[2] = (Elf_Addr)_dl_bind_start;
		pltgot[3] = (Elf_Addr)object;
	}
	if (object->got_size != 0)
		_dl_mprotect((void*)object->got_start, object->got_size,
		    PROT_READ);
	if (object->plt_size != 0)
		_dl_mprotect((void*)object->plt_start, object->plt_size,
		    PROT_READ|PROT_EXEC);

	return (fails);
}
int
_dl_md_reloc_got(elf_object_t *object, int lazy)
{
	Elf_RelA *rela;
	Elf_Addr  ooff;
	int	i, numrela, fails = 0;
	const Elf_Sym *this;

	if (object->dyn.pltrel != DT_RELA)
		return (0);

	object->got_addr = 0;
	object->got_size = 0;
	this = NULL;
	ooff = _dl_find_symbol("__got_start", &this,
	    SYM_SEARCH_OBJ|SYM_NOWARNNOTFOUND|SYM_PLT, NULL, object, NULL );
	if (this != NULL)
		object->got_addr = ooff + this->st_value;

	this = NULL;
	ooff = _dl_find_symbol("__got_end", &this,
	    SYM_SEARCH_OBJ|SYM_NOWARNNOTFOUND|SYM_PLT, NULL, object, NULL);
	if (this != NULL)
		object->got_size = ooff + this->st_value  - object->got_addr;

	if (object->got_addr == 0)
		object->got_start = 0;
	else {
		object->got_start = ELF_TRUNC(object->got_addr, _dl_pagesz);
		object->got_size += object->got_addr - object->got_start;
		object->got_size = ELF_ROUND(object->got_size, _dl_pagesz);
	}

	if (object->traced)
		lazy = 1;

	if (!lazy) {
		fails = _dl_md_reloc(object, DT_JMPREL, DT_PLTRELSZ);
	} else {
		register Elf_Addr ltp __asm ("%r19");
		Elf_Addr *got = NULL;

		rela = (Elf_RelA *)(object->dyn.jmprel);
		numrela = object->dyn.pltrelsz / sizeof(Elf_RelA);
		ooff = object->obj_base;

		/*
		 * Find the PLT stub by looking at all the
		 * relocations.  The PLT stub should be at the end of
		 * the .plt section so we start with the last
		 * relocation, since the linker should have emitted
		 * them in order.
		 */
		for (i = numrela - 1; i >= 0; i--) {
			got = (Elf_Addr *)(ooff + rela[i].r_offset +
			    PLT_ENTRY_SIZE + PLT_STUB_SIZE);
			if (got[-2] == PLT_STUB_MAGIC1 ||
			    got[-1] == PLT_STUB_MAGIC2)
				break;
			got = NULL;
		}
		if (got == NULL)
			return (1);

		/*
		 * Patch up the PLT stub such that it doesn't clobber
		 * %r22, which is used to pass on the errno values
		 * from failed system calls to __cerrno() in libc.
		 */
		got[-7] = PLT_STUB_INSN1;
		got[-6] = PLT_STUB_INSN2;
		__asm volatile("fdc 0(%0)" :: "r" (&got[-7]));
		__asm volatile("fdc 0(%0)" :: "r" (&got[-6]));
		__asm volatile("sync");
		__asm volatile("fic 0(%%sr0,%0)" :: "r" (&got[-7]));
		__asm volatile("fic 0(%%sr0,%0)" :: "r" (&got[-6]));
		__asm volatile("sync");

		/*
		 * Fill in the PLT stub such that it invokes the
		 * _dl_bind_start() trampoline to fix up the
		 * relocation.
		 */
		got[1] = (Elf_Addr)object;
		got[-2] = (Elf_Addr)&_dl_bind_start;
		got[-1] = ltp;
		/*
		 * Even though we didn't modify any instructions it
		 * seems we still need to syncronize the caches.
		 * There may be instructions in the same cache line
		 * and they end up being corrupted otherwise.
		 */
		__asm volatile("fdc 0(%0)" :: "r" (&got[-2]));
		__asm volatile("fdc 0(%0)" :: "r" (&got[-1]));
		__asm volatile("sync");
		__asm volatile("fic 0(%%sr0,%0)" :: "r" (&got[-2]));
		__asm volatile("fic 0(%%sr0,%0)" :: "r" (&got[-1]));
		__asm volatile("sync");
		for (i = 0; i < numrela; i++, rela++) {
			Elf_Addr *r_addr = (Elf_Addr *)(ooff + rela->r_offset);

			if (ELF_R_TYPE(rela->r_info) != RELOC_IPLT) {
				_dl_printf("unexpected reloc 0x%x\n",
				    ELF_R_TYPE(rela->r_info));
				return (1);
			}

			if (ELF_R_SYM(rela->r_info)) {
				r_addr[0] = (Elf_Addr)got - PLT_STUB_GOTOFF;
				r_addr[1] = (Elf_Addr) (rela -
				    (Elf_RelA *)object->dyn.jmprel);
			} else {
				r_addr[0] = ooff + rela->r_addend;
				r_addr[1] = (Elf_Addr)object->dyn.pltgot;
			}
		}
	}
	if (object->got_size != 0)
		_dl_mprotect((void *)object->got_start, object->got_size,
		    GOT_PERMS|PROT_EXEC);

	return (fails);
}
Example #4
0
/*
 *	Relocate the Global Offset Table (GOT).
 *	This is done by calling _dl_md_reloc on DT_JMPREL for DL_BIND_NOW,
 *	otherwise the lazy binding plt initialization is performed.
 */
int
_dl_md_reloc_got(elf_object_t *object, int lazy)
{
	extern void _dl_bind_start(void);	/* XXX */
	int	fails = 0;
	Elf_Addr *pltgot = (Elf_Addr *)object->Dyn.info[DT_PLTGOT];
	Elf_Addr ooff;
	const Elf_Sym *this;

	if (pltgot == NULL)
		return (0);

	pltgot[1] = (Elf_Addr)object;
	pltgot[2] = (Elf_Addr)_dl_bind_start;

	if (object->Dyn.info[DT_PLTREL] != DT_RELA)
		return (0);

	object->got_addr = 0;
	object->got_size = 0;
	this = NULL;
	ooff = _dl_find_symbol("__got_start", &this,
	    SYM_SEARCH_OBJ|SYM_NOWARNNOTFOUND|SYM_PLT, NULL, object, NULL);
	if (this != NULL)
		object->got_addr = ooff + this->st_value;

	this = NULL;
	ooff = _dl_find_symbol("__got_end", &this,
	    SYM_SEARCH_OBJ|SYM_NOWARNNOTFOUND|SYM_PLT, NULL, object, NULL);
	if (this != NULL)
		object->got_size = ooff + this->st_value  - object->got_addr;

#if 0
	plt_addr = 0;
	object->plt_size = 0;
	this = NULL;
	ooff = _dl_find_symbol("__plt_start", &this,
	    SYM_SEARCH_OBJ|SYM_NOWARNNOTFOUND|SYM_PLT, NULL, object, NULL);
	if (this != NULL)
		plt_addr = ooff + this->st_value;

	this = NULL;
	ooff = _dl_find_symbol("__plt_end", &this,
	    SYM_SEARCH_OBJ|SYM_NOWARNNOTFOUND|SYM_PLT, NULL, object, NULL);
	if (this != NULL)
		object->plt_size = ooff + this->st_value  - plt_addr;
#endif

	if (object->got_addr == 0)
		object->got_start = 0;
	else {
		object->got_start = ELF_TRUNC(object->got_addr, _dl_pagesz);
		object->got_size += object->got_addr - object->got_start;
		object->got_size = ELF_ROUND(object->got_size, _dl_pagesz);
	}
#if 0
	if (plt_addr == 0)
		object->plt_start = 0;
	else {
		object->plt_start = ELF_TRUNC(plt_addr, _dl_pagesz);
		object->plt_size += plt_addr - object->plt_start;
		object->plt_size = ELF_ROUND(object->plt_size, _dl_pagesz);
	}
#endif

	if (object->traced)
		lazy = 1;

	if (!lazy) {
		fails = _dl_md_reloc(object, DT_JMPREL, DT_PLTRELSZ);
	} else {
		if (object->obj_base != 0) {
			int i, size;
			Elf_Addr *addr;
			Elf_RelA *rela;

			size = object->Dyn.info[DT_PLTRELSZ] / sizeof(Elf_RelA);
			rela = (Elf_RelA *)object->Dyn.info[DT_JMPREL];

			for (i = 0; i < size; i++) {
				addr = (Elf_Addr *)(object->obj_base +
				    rela[i].r_offset);
				*addr += object->obj_base;
			}
		}
	}
	if (object->got_size != 0) {
		_dl_mprotect((void*)object->got_start, object->got_size,
		    PROT_READ);
	}
	/* PLT is already RO, no point in mprotecting it, just do GOT */
#if 0
	if (object->plt_size != 0)
		_dl_mprotect((void*)object->plt_start, object->plt_size,
		    PROT_READ|PROT_EXEC);
#endif

	return (fails);
}