Last active
July 13, 2023 08:25
-
-
Save Chubek/3baffe48e8d57524d4924c75429a9eff to your computer and use it in GitHub Desktop.
vDSO Parser
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <elf.h> | |
#include <errno.h> | |
#include <limits.h> | |
#include <stdint.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <sys/types.h> | |
#define SIZEOF_ADDR sizeof(uintptr_t) | |
#define ARENA_NUM 4096 | |
#define ARENA_SIZE (ARENA_NUM * SIZEOF_ADDR) | |
#define MAX_FUNCNAME 16 | |
#define CLOCK_REALTIME 0 | |
#define ATTRS_LOADED 1 | |
#define ____STR(IDENT) #IDENT | |
#define ____VDSO(IDENT) __vdso_##IDENT | |
#define STR(IDENT) ____STR(IDENT) | |
#define VDSO(IDENT) ____VDSO(IDENT) | |
#define X64_SYSCALL_CLOCK_GETTIME clock_gettime | |
#define X64_SYSCALL_GETCPU getcpu | |
#define X64_SYSCALL_GETTIMEOFDAY gettimeofday | |
#define X64_SYSCALL_TIME time | |
#ifdef GET_NONVDSO_FUNCS | |
#define X64_VDSO_CLOCK_GETTIME STR(X64_SYSCALL_CLOCK_GETTIME) | |
#define X64_VDSO_GET_CPU STR(X64_SYSCALL_GETCPU) | |
#define X64_VDSO_GETTIMEOFDAY STR(X64_SYSCALL_GETTIMEOFDAY) | |
#define X64_VDSO_TIME STR(X64_SYSCALL_TIME) | |
#else | |
#define X64_VDSO_CLOCK_GETTIME STR(VDSO(X64_SYSCALL_CLOCK_GETTIME)) | |
#define X64_VDSO_GET_CPU STR(VDSO(X64_SYSCALL_GETCPU)) | |
#define X64_VDSO_GETTIMEOFDAY STR(VDSO(X64_SYSCALL_GETTIMEOFDAY)) | |
#define X64_VDSO_TIME STR(VDSO(X64_SYSCALL_TIME)) | |
#endif | |
typedef long int time_t; | |
typedef long int suseconds_t; | |
typedef int clockid_t; | |
typedef struct { | |
uintptr_t memBlock_arena[ARENA_NUM]; | |
uintptr_t memAddr_arena_top; | |
uintptr_t memAddr_arena_sectstrtab; | |
uintptr_t memAddr_arena_symstrtab; | |
uintptr_t memAddr_arena_dynsymtab; | |
uintptr_t memMapAddr_vdso_img; | |
uintptr_t memBlock_environ; | |
uintptr_t memBlock_auxvals; | |
uintptr_t memAddr_elf_header; | |
uintptr_t memAddr_prog_header; | |
uintptr_t memAddr_sect_header; | |
uint32_t memOffs_prog_header; | |
uint32_t memOffs_sect_header; | |
uint32_t idxNum_prog_header; | |
uint32_t idxNum_sect_header; | |
uint32_t idxOffs_stab_header; | |
uint32_t memSize_elf_header; | |
uint32_t memSize_prog_header; | |
uint32_t memSize_sect_header; | |
size_t fileSize_vdso_img; | |
uint64_t sentinel; | |
} vDSOAttrs_Val, *vDSOAttrs_Addr, **vDSOAttrs_AddrPtr; | |
typedef enum { | |
ClockGettime, | |
GetCPU, | |
GetTimeOfDay, | |
Time, | |
None, | |
} vDSOSysCall_Enum; | |
typedef struct { | |
time_t tv_sec; | |
long tv_nsec; | |
} timespec_t; | |
typedef struct { | |
time_t tv_sec; | |
suseconds_t tv_usec; | |
} timeval_t; | |
typedef struct getcpu_cache deprecated_t; | |
typedef struct { | |
int tz_minuteswest; | |
int tz_dsttime; | |
} timezone_t; | |
typedef int (*clock_gettime)(clockid_t, timespec_t *); | |
typedef int (*getcpu)(unsigned *, unsigned *, deprecated_t *); | |
typedef int (*gettimeofday)(timeval_t *, const timezone_t *); | |
typedef time_t (*time)(time_t *); | |
static inline vDSOSysCall_Enum __attribute__((always_inline)) | |
get_vdso_function_name_enumeration(char *name) { | |
vDSOSysCall_Enum enumVal_vdso_func; | |
if (!strncmp(name, X64_VDSO_CLOCK_GETTIME, MAX_FUNCNAME)) | |
enumVal_vdso_func = ClockGettime; | |
else if (!strncmp(name, X64_VDSO_GET_CPU, MAX_FUNCNAME)) | |
enumVal_vdso_func = GetCPU; | |
else if (!strncmp(name, X64_VDSO_GETTIMEOFDAY, MAX_FUNCNAME)) | |
enumVal_vdso_func = GetTimeOfDay; | |
else if (!strncmp(name, X64_VDSO_TIME, MAX_FUNCNAME)) | |
enumVal_vdso_func = Time; | |
else | |
enumVal_vdso_func = None; | |
return enumVal_vdso_func; | |
} | |
static inline uint64_t __attribute__((always_inline, flatten)) | |
load_first_quad_word(void *address) { | |
return *((uint64_t *)memmove(address, address, sizeof(uint64_t))); | |
} | |
static inline void __attribute__((always_inline)) | |
initialize_vdso_attrs(vDSOAttrs_Addr vdso_attrs) { | |
extern char **environ; | |
vdso_attrs->memAddr_arena_top = (uintptr_t)(&vdso_attrs->memBlock_arena[0]); | |
vdso_attrs->memBlock_environ = (uintptr_t)(environ); | |
memset(&vdso_attrs->memBlock_arena[0], 0, ARENA_SIZE); | |
vdso_attrs->sentinel = 0; | |
} | |
static inline void __attribute__((always_inline)) | |
get_auxillary_vectors_address(vDSOAttrs_Addr vdso_attrs) { | |
uintptr_t memAddr_dst, | |
*memAddr_src = (uintptr_t *)(vdso_attrs->memBlock_environ); | |
do { | |
memmove(&memAddr_dst, ++memAddr_src, SIZEOF_ADDR); | |
} while (memAddr_dst); | |
vdso_attrs->memBlock_auxvals = (uintptr_t)(memAddr_src); | |
} | |
static inline void __attribute__((always_inline)) | |
get_vdso_elfheader_address(vDSOAttrs_Addr vdso_attrs) { | |
Elf64_auxv_t memVal_elf_auxv, *memAddr_dst = &memVal_elf_auxv; | |
uintptr_t *memAddr_src = (void *)(vdso_attrs->memBlock_auxvals); | |
do { | |
memmove(memAddr_dst, ++memAddr_src, sizeof(Elf64_auxv_t)); | |
} while (memVal_elf_auxv.a_type != AT_SYSINFO_EHDR); | |
vdso_attrs->memAddr_elf_header = (uintptr_t)(memVal_elf_auxv.a_un.a_val); | |
} | |
static inline void __attribute__((always_inline)) | |
get_vdso_address_offsets(vDSOAttrs_Addr vdso_attrs) { | |
Elf64_Ehdr *memAddr_elf_header = (Elf64_Ehdr *)vdso_attrs->memAddr_elf_header; | |
vdso_attrs->memOffs_prog_header = memAddr_elf_header->e_phoff; | |
vdso_attrs->memOffs_sect_header = memAddr_elf_header->e_shoff; | |
} | |
static inline void __attribute__((always_inline)) | |
apply_vdso_address_offsets(vDSOAttrs_Addr vdso_attrs) { | |
vdso_attrs->memAddr_prog_header = vdso_attrs->memAddr_elf_header; | |
vdso_attrs->memAddr_sect_header = vdso_attrs->memAddr_elf_header; | |
vdso_attrs->memAddr_prog_header += vdso_attrs->memOffs_prog_header; | |
vdso_attrs->memAddr_sect_header += vdso_attrs->memOffs_sect_header; | |
} | |
static inline void __attribute__((always_inline)) | |
get_vdso_entry_sizes(vDSOAttrs_Addr vdso_attrs) { | |
Elf64_Ehdr *memAddr_elf_header = (Elf64_Ehdr *)vdso_attrs->memAddr_elf_header; | |
vdso_attrs->memSize_elf_header = memAddr_elf_header->e_ehsize; | |
vdso_attrs->memSize_prog_header = memAddr_elf_header->e_phentsize; | |
vdso_attrs->memSize_sect_header = memAddr_elf_header->e_shentsize; | |
} | |
static inline void __attribute__((always_inline)) | |
get_vdso_entry_numbers(vDSOAttrs_Addr vdso_attrs) { | |
Elf64_Ehdr *memAddr_elf_header = (Elf64_Ehdr *)vdso_attrs->memAddr_elf_header; | |
vdso_attrs->idxNum_prog_header = memAddr_elf_header->e_phnum; | |
vdso_attrs->idxNum_sect_header = memAddr_elf_header->e_shnum; | |
vdso_attrs->idxOffs_stab_header = memAddr_elf_header->e_shstrndx; | |
} | |
static inline void __attribute__((always_inline)) | |
get_vdso_image_size(vDSOAttrs_Addr vdso_attrs) { | |
Elf64_Ehdr *memAddr_elf_header = (Elf64_Ehdr *)vdso_attrs->memAddr_elf_header; | |
vdso_attrs->fileSize_vdso_img = (size_t)(vdso_attrs->memOffs_sect_header + | |
(vdso_attrs->idxNum_sect_header * | |
vdso_attrs->memSize_sect_header) * | |
CHAR_BIT); | |
} | |
static inline void __attribute__((always_inline)) | |
copy_vdso_sections_string_table(vDSOAttrs_Addr vdso_attrs) { | |
char *memAddr_arena_top = (char *)vdso_attrs->memAddr_arena_top; | |
uintptr_t *memAddr_arena_top_addr = | |
(uintptr_t *)&vdso_attrs->memAddr_arena_top; | |
Elf64_Shdr *memAddr_sect_header = | |
(Elf64_Shdr *)vdso_attrs->memAddr_sect_header; | |
Elf64_Shdr memStruct_sectstrtab_header = {0}; | |
uintptr_t memAddr_sectstr_table; | |
vdso_attrs->memAddr_arena_sectstrtab = (uintptr_t)(memAddr_arena_top); | |
memStruct_sectstrtab_header = | |
memAddr_sect_header[vdso_attrs->idxOffs_stab_header]; | |
memAddr_sectstr_table = vdso_attrs->memAddr_elf_header; | |
memAddr_sectstr_table += memStruct_sectstrtab_header.sh_offset; | |
memmove(memAddr_arena_top, (void *)(memAddr_sectstr_table), | |
memStruct_sectstrtab_header.sh_size); | |
memAddr_arena_top += memStruct_sectstrtab_header.sh_size + sizeof(uintptr_t); | |
memmove(memAddr_arena_top, &vdso_attrs->sentinel, sizeof(uint64_t)); | |
*memAddr_arena_top_addr = (uintptr_t)memAddr_arena_top; | |
} | |
static inline void __attribute__((always_inline)) | |
copy_vdso_symbols_string_table(vDSOAttrs_Addr vdso_attrs) { | |
char *memAddr_arena_top = (char *)vdso_attrs->memAddr_arena_top; | |
uintptr_t *memAddr_arena_top_addr = | |
(uintptr_t *)&vdso_attrs->memAddr_arena_top; | |
Elf64_Shdr *memAddr_sect_header = | |
(Elf64_Shdr *)vdso_attrs->memAddr_sect_header; | |
Elf64_Shdr memStruct_symstrtab_header = {0}; | |
uintptr_t memAddr_symstr_table; | |
do { | |
memStruct_symstrtab_header = *(++memAddr_sect_header); | |
} while (memStruct_symstrtab_header.sh_type != SHT_STRTAB); | |
vdso_attrs->memAddr_arena_symstrtab = (uintptr_t)(memAddr_arena_top); | |
memAddr_symstr_table = vdso_attrs->memAddr_elf_header; | |
memAddr_symstr_table += (uintptr_t)(memStruct_symstrtab_header.sh_offset); | |
memmove(memAddr_arena_top, (void *)(memAddr_symstr_table), | |
memStruct_symstrtab_header.sh_size); | |
memAddr_arena_top += memStruct_symstrtab_header.sh_size + sizeof(uintptr_t); | |
memmove(memAddr_arena_top, &vdso_attrs->sentinel, sizeof(uint64_t)); | |
*memAddr_arena_top_addr = (uintptr_t)memAddr_arena_top; | |
} | |
static inline void __attribute__((always_inline)) | |
copy_vdso_dynamic_symbol_table(vDSOAttrs_Addr vdso_attrs) { | |
char *memAddr_arena_top = (char *)vdso_attrs->memAddr_arena_top; | |
uintptr_t *memAddr_arena_top_addr = | |
(uintptr_t *)&vdso_attrs->memAddr_arena_top; | |
Elf64_Shdr *memAddr_sect_header = | |
(Elf64_Shdr *)vdso_attrs->memAddr_sect_header; | |
Elf64_Shdr memStruct_dynsym_header; | |
uintptr_t memAddr_symbol_header; | |
do { | |
memStruct_dynsym_header = *(++memAddr_sect_header); | |
} while (memStruct_dynsym_header.sh_type != SHT_DYNSYM); | |
vdso_attrs->memAddr_arena_dynsymtab = (uintptr_t)(memAddr_arena_top); | |
memAddr_symbol_header = vdso_attrs->memAddr_elf_header; | |
memAddr_symbol_header += (uintptr_t)(memStruct_dynsym_header.sh_offset); | |
memAddr_symbol_header += sizeof(Elf64_Sym); | |
memmove(memAddr_arena_top, (void *)(memAddr_symbol_header), | |
memStruct_dynsym_header.sh_size); | |
memAddr_arena_top += memStruct_dynsym_header.sh_size + sizeof(uintptr_t); | |
memmove(memAddr_arena_top + sizeof(uintptr_t), &vdso_attrs->sentinel, | |
sizeof(uint64_t)); | |
*memAddr_arena_top_addr = (uintptr_t)memAddr_arena_top; | |
} | |
static inline void __attribute__((always_inline)) | |
finalize_vdso_attrs(vDSOAttrs_Addr vdso_attrs) { | |
vdso_attrs->sentinel = ATTRS_LOADED; | |
} | |
static inline void __attribute__((always_inline)) | |
get_vdso_attrs_from_memory(char **memAddr_arena_symstrtab, | |
Elf64_Sym **memAddr_arena_dynsymtab, | |
Elf64_Ehdr **memAddr_elf_header) { | |
static vDSOAttrs_Val vdso_attrs = {0}; | |
if (!vdso_attrs.sentinel) { | |
initialize_vdso_attrs(&vdso_attrs); | |
get_auxillary_vectors_address(&vdso_attrs); | |
get_vdso_elfheader_address(&vdso_attrs); | |
get_vdso_entry_sizes(&vdso_attrs); | |
get_vdso_entry_numbers(&vdso_attrs); | |
get_vdso_address_offsets(&vdso_attrs); | |
apply_vdso_address_offsets(&vdso_attrs); | |
get_vdso_image_size(&vdso_attrs); | |
copy_vdso_sections_string_table(&vdso_attrs); | |
copy_vdso_symbols_string_table(&vdso_attrs); | |
copy_vdso_dynamic_symbol_table(&vdso_attrs); | |
finalize_vdso_attrs(&vdso_attrs); | |
} | |
*memAddr_arena_symstrtab = (char *)vdso_attrs.memAddr_arena_symstrtab; | |
*memAddr_arena_dynsymtab = (Elf64_Sym *)vdso_attrs.memAddr_arena_dynsymtab; | |
*memAddr_elf_header = (Elf64_Ehdr *)vdso_attrs.memAddr_elf_header; | |
} | |
static inline void *__attribute__((always_inline, hot)) | |
load_system_call(vDSOSysCall_Enum wanted_syscall) { | |
char *memAddr_symstrtab_entry; | |
Elf64_Sym *memAddr_dynsymtab_header; | |
Elf64_Ehdr *memAddr_elf_header; | |
get_vdso_attrs_from_memory(&memAddr_symstrtab_entry, | |
&memAddr_dynsymtab_header, &memAddr_elf_header); | |
uintptr_t memAddr_current_vsyscall; | |
Elf64_Sym memStruct_current_sym = {0}; | |
char *memAddr_current_name; | |
vDSOSysCall_Enum current_syscall; | |
do { | |
memStruct_current_sym = *memAddr_dynsymtab_header++; | |
if (ELF64_ST_TYPE(memStruct_current_sym.st_info) == STT_FUNC) { | |
memAddr_current_name = | |
&memAddr_symstrtab_entry[memStruct_current_sym.st_name]; | |
memAddr_current_vsyscall = (uintptr_t)(((uintptr_t)memAddr_elf_header) + | |
memStruct_current_sym.st_value); | |
current_syscall = | |
get_vdso_function_name_enumeration(memAddr_current_name); | |
if (current_syscall == wanted_syscall) { | |
return (void *)memAddr_current_vsyscall; | |
} | |
} | |
} while (load_first_quad_word(&memStruct_current_sym)); | |
return NULL; | |
} | |
#ifdef TEST | |
int main(int argc, char **argv) { | |
clock_gettime clock_gettime_syscall = | |
(clock_gettime)load_system_call(ClockGettime); | |
getcpu getcpu_syscall = (getcpu)load_system_call(GetCPU); | |
gettimeofday gettimeofday_syscall = | |
(gettimeofday)load_system_call(GetTimeOfDay); | |
time time_syscall = (time)load_system_call(Time); | |
time_t tloc, ctime = time_syscall(&tloc); | |
} | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment