vdso.cpp revision 613f8145087a763e128d58e638bc85799fb06989
1625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes/* 2625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes * Copyright (C) 2014 The Android Open Source Project 3625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes * 4625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes * Licensed under the Apache License, Version 2.0 (the "License"); 5625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes * you may not use this file except in compliance with the License. 6625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes * You may obtain a copy of the License at 7625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes * 8625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes * http://www.apache.org/licenses/LICENSE-2.0 9625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes * 10625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes * Unless required by applicable law or agreed to in writing, software 11625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes * distributed under the License is distributed on an "AS IS" BASIS, 12625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes * See the License for the specific language governing permissions and 14625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes * limitations under the License. 15625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes */ 16625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes 17625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes#include <link.h> 1805fc1d7050d5451aea08dc5f504d2670287b2d43Elliott Hughes#include <string.h> 19625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes#include <sys/auxv.h> 20625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes#include <unistd.h> 21625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes 22625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes// x86 has a vdso, but there's nothing useful to us in it. 23625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes#if defined(__aarch64__) || defined(__x86_64__) 24625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes 25625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes#if defined(__aarch64__) 26625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes#define VDSO_CLOCK_GETTIME_SYMBOL "__kernel_clock_gettime" 27625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes#define VDSO_GETTIMEOFDAY_SYMBOL "__kernel_gettimeofday" 28625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes#elif defined(__x86_64__) 29625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes#define VDSO_CLOCK_GETTIME_SYMBOL "__vdso_clock_gettime" 30625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes#define VDSO_GETTIMEOFDAY_SYMBOL "__vdso_gettimeofday" 31625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes#endif 32625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes 33613f8145087a763e128d58e638bc85799fb06989Elliott Hughes#include <errno.h> 34613f8145087a763e128d58e638bc85799fb06989Elliott Hughes#include <limits.h> 35613f8145087a763e128d58e638bc85799fb06989Elliott Hughes#include <sys/mman.h> 36625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes#include <time.h> 37625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes 38613f8145087a763e128d58e638bc85799fb06989Elliott Hughes#include "private/bionic_prctl.h" 39613f8145087a763e128d58e638bc85799fb06989Elliott Hughes#include "private/libc_logging.h" 40613f8145087a763e128d58e638bc85799fb06989Elliott Hughes 41625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughesextern "C" int __clock_gettime(int, timespec*); 42625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughesextern "C" int __gettimeofday(timeval*, struct timezone*); 43625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes 44625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughesstruct vdso_entry { 45625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes const char* name; 46625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes void* fn; 47625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes}; 48625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes 49625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughesenum { 50625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes VDSO_CLOCK_GETTIME = 0, 51625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes VDSO_GETTIMEOFDAY, 52625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes VDSO_END 53625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes}; 54625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes 55613f8145087a763e128d58e638bc85799fb06989Elliott Hughesstatic union { 56613f8145087a763e128d58e638bc85799fb06989Elliott Hughes vdso_entry entries[VDSO_END]; 57613f8145087a763e128d58e638bc85799fb06989Elliott Hughes char padding[PAGE_SIZE]; 58613f8145087a763e128d58e638bc85799fb06989Elliott Hughes} vdso __attribute__((aligned(PAGE_SIZE))) = {{ 59625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes [VDSO_CLOCK_GETTIME] = { VDSO_CLOCK_GETTIME_SYMBOL, reinterpret_cast<void*>(__clock_gettime) }, 60625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes [VDSO_GETTIMEOFDAY] = { VDSO_GETTIMEOFDAY_SYMBOL, reinterpret_cast<void*>(__gettimeofday) }, 61613f8145087a763e128d58e638bc85799fb06989Elliott Hughes}}; 62625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes 63625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughesint clock_gettime(int clock_id, timespec* tp) { 64613f8145087a763e128d58e638bc85799fb06989Elliott Hughes int (*vdso_clock_gettime)(int, timespec*) = 65613f8145087a763e128d58e638bc85799fb06989Elliott Hughes reinterpret_cast<int (*)(int, timespec*)>(vdso.entries[VDSO_CLOCK_GETTIME].fn); 66625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes return vdso_clock_gettime(clock_id, tp); 67625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes} 68625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes 69625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughesint gettimeofday(timeval* tv, struct timezone* tz) { 70613f8145087a763e128d58e638bc85799fb06989Elliott Hughes int (*vdso_gettimeofday)(timeval*, struct timezone*) = 71613f8145087a763e128d58e638bc85799fb06989Elliott Hughes reinterpret_cast<int (*)(timeval*, struct timezone*)>(vdso.entries[VDSO_GETTIMEOFDAY].fn); 72625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes return vdso_gettimeofday(tv, tz); 73625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes} 74625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes 75613f8145087a763e128d58e638bc85799fb06989Elliott Hughesstatic void __libc_init_vdso_entries() { 76625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes // Do we have a vdso? 77625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes uintptr_t vdso_ehdr_addr = getauxval(AT_SYSINFO_EHDR); 78625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes ElfW(Ehdr)* vdso_ehdr = reinterpret_cast<ElfW(Ehdr)*>(vdso_ehdr_addr); 79613f8145087a763e128d58e638bc85799fb06989Elliott Hughes if (vdso_ehdr == nullptr) { 80625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes return; 81625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes } 82625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes 83625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes // How many symbols does it have? 84625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes size_t symbol_count = 0; 85625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes ElfW(Shdr)* vdso_shdr = reinterpret_cast<ElfW(Shdr)*>(vdso_ehdr_addr + vdso_ehdr->e_shoff); 86625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes for (size_t i = 0; i < vdso_ehdr->e_shnum; ++i) { 87625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes if (vdso_shdr[i].sh_type == SHT_DYNSYM) { 88625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes symbol_count = vdso_shdr[i].sh_size / sizeof(ElfW(Sym)); 89625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes } 90625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes } 91625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes if (symbol_count == 0) { 92625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes return; 93625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes } 94625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes 95625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes // Where's the dynamic table? 96625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes ElfW(Addr) vdso_addr = 0; 97613f8145087a763e128d58e638bc85799fb06989Elliott Hughes ElfW(Dyn)* vdso_dyn = nullptr; 98625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes ElfW(Phdr)* vdso_phdr = reinterpret_cast<ElfW(Phdr)*>(vdso_ehdr_addr + vdso_ehdr->e_phoff); 99625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes for (size_t i = 0; i < vdso_ehdr->e_phnum; ++i) { 100625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes if (vdso_phdr[i].p_type == PT_DYNAMIC) { 101625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes vdso_dyn = reinterpret_cast<ElfW(Dyn)*>(vdso_ehdr_addr + vdso_phdr[i].p_offset); 102625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes } else if (vdso_phdr[i].p_type == PT_LOAD) { 103625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes vdso_addr = vdso_ehdr_addr + vdso_phdr[i].p_offset - vdso_phdr[i].p_vaddr; 104625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes } 105625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes } 106613f8145087a763e128d58e638bc85799fb06989Elliott Hughes if (vdso_addr == 0 || vdso_dyn == nullptr) { 107625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes return; 108625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes } 109625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes 110625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes // Where are the string and symbol tables? 111613f8145087a763e128d58e638bc85799fb06989Elliott Hughes const char* strtab = nullptr; 112613f8145087a763e128d58e638bc85799fb06989Elliott Hughes ElfW(Sym)* symtab = nullptr; 113625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes for (ElfW(Dyn)* d = vdso_dyn; d->d_tag != DT_NULL; ++d) { 114625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes if (d->d_tag == DT_STRTAB) { 115625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes strtab = reinterpret_cast<const char*>(vdso_addr + d->d_un.d_ptr); 116625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes } else if (d->d_tag == DT_SYMTAB) { 117625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes symtab = reinterpret_cast<ElfW(Sym)*>(vdso_addr + d->d_un.d_ptr); 118625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes } 119625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes } 120613f8145087a763e128d58e638bc85799fb06989Elliott Hughes if (strtab == nullptr || symtab == nullptr) { 121625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes return; 122625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes } 123625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes 124625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes // Are there any symbols we want? 125625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes for (size_t i = 0; i < symbol_count; ++i) { 126625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes for (size_t j = 0; j < VDSO_END; ++j) { 127613f8145087a763e128d58e638bc85799fb06989Elliott Hughes if (strcmp(vdso.entries[j].name, strtab + symtab[i].st_name) == 0) { 128613f8145087a763e128d58e638bc85799fb06989Elliott Hughes vdso.entries[j].fn = reinterpret_cast<void*>(vdso_addr + symtab[i].st_value); 129625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes } 130625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes } 131625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes } 132625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes} 133625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes 134613f8145087a763e128d58e638bc85799fb06989Elliott Hughesvoid __libc_init_vdso() { 135613f8145087a763e128d58e638bc85799fb06989Elliott Hughes __libc_init_vdso_entries(); 136613f8145087a763e128d58e638bc85799fb06989Elliott Hughes 137613f8145087a763e128d58e638bc85799fb06989Elliott Hughes // We can't use PR_SET_VMA because this isn't an anonymous region. 138613f8145087a763e128d58e638bc85799fb06989Elliott Hughes // Long-term we should be able to replace all of this with ifuncs. 139613f8145087a763e128d58e638bc85799fb06989Elliott Hughes static_assert(PAGE_SIZE == sizeof(vdso), "sizeof(vdso) too large"); 140613f8145087a763e128d58e638bc85799fb06989Elliott Hughes if (mprotect(vdso.entries, sizeof(vdso), PROT_READ) == -1) { 141613f8145087a763e128d58e638bc85799fb06989Elliott Hughes __libc_fatal("failed to mprotect PROT_READ vdso function pointer table: %s", strerror(errno)); 142613f8145087a763e128d58e638bc85799fb06989Elliott Hughes } 143613f8145087a763e128d58e638bc85799fb06989Elliott Hughes} 144613f8145087a763e128d58e638bc85799fb06989Elliott Hughes 145625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes#else 146625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes 147625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughesvoid __libc_init_vdso() { 148625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes} 149625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes 150625993dfbb085a3cde7492eda8ec1cdc1ee39a78Elliott Hughes#endif 151