Skip to content

Instantly share code, notes, and snippets.

@Chubek
Last active July 13, 2023 08:25
Show Gist options
  • Save Chubek/3baffe48e8d57524d4924c75429a9eff to your computer and use it in GitHub Desktop.
Save Chubek/3baffe48e8d57524d4924c75429a9eff to your computer and use it in GitHub Desktop.
vDSO Parser
#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