diff options
| -rw-r--r-- | src/ldso/dynlink.c | 33 | 
1 files changed, 31 insertions, 2 deletions
| diff --git a/src/ldso/dynlink.c b/src/ldso/dynlink.c index 226e174f..d8f641ae 100644 --- a/src/ldso/dynlink.c +++ b/src/ldso/dynlink.c @@ -298,7 +298,7 @@ static struct dso *load_library(const char *name)  				if (!libc->prev) {  					tail->next = libc;  					libc->prev = tail; -					tail = libc; +					tail = libc->next ? libc->next : libc;  				}  				return libc;  			} @@ -440,12 +440,15 @@ void *__dynlink(int argc, char **argv, size_t *got)  	size_t *auxv, aux[AUX_CNT] = {0};  	size_t app_dyn[DYN_CNT] = {0};  	size_t lib_dyn[DYN_CNT] = {0}; +	size_t vdso_dyn[DYN_CNT] = {0};  	size_t i;  	Phdr *phdr;  	Ehdr *ehdr; -	static struct dso builtin_dsos[2]; +	static struct dso builtin_dsos[3];  	struct dso *const app = builtin_dsos+0;  	struct dso *const lib = builtin_dsos+1; +	struct dso *const vdso = builtin_dsos+2; +	size_t vdso_base=0;  	/* Find aux vector just past environ[] */  	for (i=argc+1; argv[i]; i++) @@ -455,6 +458,13 @@ void *__dynlink(int argc, char **argv, size_t *got)  	decode_vec(auxv, aux, AUX_CNT); +	for (i=0; auxv[i]; i+=2) { +		if (auxv[i]==AT_SYSINFO_EHDR) { +			vdso_base = auxv[i+1]; +			break; +		} +	} +  	/* Only trust user/env if kernel says we're not suid/sgid */  	if ((aux[0]&0x7800)!=0x7800 || aux[AT_UID]!=aux[AT_EUID]  	  || aux[AT_GID]!=aux[AT_EGID]) { @@ -495,6 +505,25 @@ void *__dynlink(int argc, char **argv, size_t *got)  		.relocated = 1  	}; +	if (vdso_base) { +		ehdr = (void *)vdso_base; +		phdr = (void *)(vdso_base + ehdr->e_phoff); +		for (i=ehdr->e_phnum; i; i--, phdr=(void *)((char *)phdr + ehdr->e_phentsize)) { +			if (phdr->p_type == PT_DYNAMIC) +				vdso->dynv = (void *)(vdso_base + phdr->p_offset); +			if (phdr->p_type == PT_LOAD) +				vdso->base = (void *)(vdso_base - phdr->p_vaddr + phdr->p_offset); +		} +		decode_vec(vdso->dynv, vdso_dyn, DYN_CNT); +		vdso->syms = (void *)(vdso->base + vdso_dyn[DT_SYMTAB]); +		vdso->hashtab = (void *)(vdso->base + vdso_dyn[DT_HASH]); +		vdso->strings = (void *)(vdso->base + vdso_dyn[DT_STRTAB]); +		vdso->name = "linux-gate.so.1"; + +		vdso->prev = lib; +		lib->next = vdso; +	} +  	/* Relocate the dynamic linker/libc */  	do_relocs((void *)aux[AT_BASE], (void *)(aux[AT_BASE]+lib_dyn[DT_REL]),  		lib_dyn[DT_RELSZ], 2, lib->syms, lib->strings, app); | 
