about summary refs log tree commit diff
path: root/src/ldso/dynlink.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/ldso/dynlink.c')
-rw-r--r--src/ldso/dynlink.c33
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);