diff --git a/libc/bionic/vdso.cpp b/libc/bionic/vdso.cpp index a2406634d..d4aea986b 100644 --- a/libc/bionic/vdso.cpp +++ b/libc/bionic/vdso.cpp @@ -30,8 +30,14 @@ #define VDSO_GETTIMEOFDAY_SYMBOL "__vdso_gettimeofday" #endif +#include +#include +#include #include +#include "private/bionic_prctl.h" +#include "private/libc_logging.h" + extern "C" int __clock_gettime(int, timespec*); extern "C" int __gettimeofday(timeval*, struct timezone*); @@ -46,28 +52,33 @@ enum { VDSO_END }; -static vdso_entry vdso_entries[] = { +static const vdso_entry vdso_entries_template[] = { [VDSO_CLOCK_GETTIME] = { VDSO_CLOCK_GETTIME_SYMBOL, reinterpret_cast(__clock_gettime) }, [VDSO_GETTIMEOFDAY] = { VDSO_GETTIMEOFDAY_SYMBOL, reinterpret_cast(__gettimeofday) }, }; +static vdso_entry* vdso_entries; + int clock_gettime(int clock_id, timespec* tp) { - static int (*vdso_clock_gettime)(int, timespec*) = + int (*vdso_clock_gettime)(int, timespec*) = reinterpret_cast(vdso_entries[VDSO_CLOCK_GETTIME].fn); return vdso_clock_gettime(clock_id, tp); } int gettimeofday(timeval* tv, struct timezone* tz) { - static int (*vdso_gettimeofday)(timeval*, struct timezone*) = + int (*vdso_gettimeofday)(timeval*, struct timezone*) = reinterpret_cast(vdso_entries[VDSO_GETTIMEOFDAY].fn); return vdso_gettimeofday(tv, tz); } -void __libc_init_vdso() { +static void __libc_init_vdso_entries() { + // Set up the defaults in case we don't have a vdso or can't find everything we're looking for. + memcpy(vdso_entries, vdso_entries_template, sizeof(vdso_entries_template)); + // Do we have a vdso? uintptr_t vdso_ehdr_addr = getauxval(AT_SYSINFO_EHDR); ElfW(Ehdr)* vdso_ehdr = reinterpret_cast(vdso_ehdr_addr); - if (vdso_ehdr == NULL) { + if (vdso_ehdr == nullptr) { return; } @@ -85,7 +96,7 @@ void __libc_init_vdso() { // Where's the dynamic table? ElfW(Addr) vdso_addr = 0; - ElfW(Dyn)* vdso_dyn = NULL; + ElfW(Dyn)* vdso_dyn = nullptr; ElfW(Phdr)* vdso_phdr = reinterpret_cast(vdso_ehdr_addr + vdso_ehdr->e_phoff); for (size_t i = 0; i < vdso_ehdr->e_phnum; ++i) { if (vdso_phdr[i].p_type == PT_DYNAMIC) { @@ -94,13 +105,13 @@ void __libc_init_vdso() { vdso_addr = vdso_ehdr_addr + vdso_phdr[i].p_offset - vdso_phdr[i].p_vaddr; } } - if (vdso_addr == 0 || vdso_dyn == NULL) { + if (vdso_addr == 0 || vdso_dyn == nullptr) { return; } // Where are the string and symbol tables? - const char* strtab = NULL; - ElfW(Sym)* symtab = NULL; + const char* strtab = nullptr; + ElfW(Sym)* symtab = nullptr; for (ElfW(Dyn)* d = vdso_dyn; d->d_tag != DT_NULL; ++d) { if (d->d_tag == DT_STRTAB) { strtab = reinterpret_cast(vdso_addr + d->d_un.d_ptr); @@ -108,7 +119,7 @@ void __libc_init_vdso() { symtab = reinterpret_cast(vdso_addr + d->d_un.d_ptr); } } - if (strtab == NULL || symtab == NULL) { + if (strtab == nullptr || symtab == nullptr) { return; } @@ -122,6 +133,20 @@ void __libc_init_vdso() { } } +void __libc_init_vdso() { + static_assert(PAGE_SIZE >= sizeof(vdso_entries_template), "vdso_entries_template too large"); + vdso_entries = reinterpret_cast(mmap(nullptr, sizeof(vdso_entries_template), PROT_READ|PROT_WRITE, + MAP_ANONYMOUS|MAP_PRIVATE, -1, 0)); + if (vdso_entries == MAP_FAILED) { + __libc_fatal("failed to allocate vdso function pointer table: %s", strerror(errno)); + } + __libc_init_vdso_entries(); + if (mprotect(vdso_entries, sizeof(vdso_entries_template), PROT_READ) == -1) { + __libc_fatal("failed to mprotect PROT_READ vdso function pointer table: %s", strerror(errno)); + } + prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, vdso_entries, sizeof(vdso_entries_template), "vdso function pointer table"); +} + #else void __libc_init_vdso() {