Crates.io | tpom |
lib.rs | tpom |
version | 0.1.0 |
source | src |
created_at | 2022-12-02 17:33:48.803437 |
updated_at | 2022-12-02 17:33:48.803437 |
description | Allows overriding the system clock; useful for testing |
homepage | |
repository | |
max_upload_size | |
id | 728519 |
size | 39,954 |
This library hijacks time-related functions in the vDSO (1, 2) and allows replacing them with user-provided functions.
As an example, embedded into a Python project:
>>> import datetime
>>> datetime.datetime.now()
datetime.datetime(2022, 12, 1, 13, 47, 15, 574866)
>>> import tpom
>>> tpom.curse_me()
>>> datetime.datetime.now()
my clockgettime was called!
datetime.datetime(1970, 1, 1, 1, 1, 51)
Inspired by libfaketime, the main difference is no need to LD_PRELOAD
any shared object (and to re-exec afterwards).
To speed up frequently called syscalls, the kernel exposes them via the vDSO, which is a mechanism to map kernel functions to user memory space.
The vDSO memory area contains an ELF blob, which can be scanned for dynamic symbols, such as:
DYNAMIC SYMBOL TABLE:
0000000000000c10 w DF .text 0000000000000005 LINUX_2.6 clock_gettime
0000000000000bd0 g DF .text 0000000000000005 LINUX_2.6 __vdso_gettimeofday
0000000000000c20 w DF .text 0000000000000060 LINUX_2.6 clock_getres
0000000000000c20 g DF .text 0000000000000060 LINUX_2.6 __vdso_clock_getres
0000000000000bd0 w DF .text 0000000000000005 LINUX_2.6 gettimeofday
0000000000000be0 g DF .text 0000000000000029 LINUX_2.6 __vdso_time
0000000000000be0 w DF .text 0000000000000029 LINUX_2.6 time
0000000000000c10 g DF .text 0000000000000005 LINUX_2.6 __vdso_clock_gettime
Each of these symbols is just a function that can be called.
This is user-space memory, each process has full control over it, and this is what TPOM does:
jmp
as first instruction on each symbol's address, targetting a trampoline which ends up calling the user-provided functionThe vDSO before:
0000000000000c10 <__vdso_clock_gettime@@LINUX_2.6>:
c10: e9 9b fb ff ff jmp 7b0 <LINUX_2.6@@LINUX_2.6+0x7b0>
c15: 66 66 2e 0f 1f 84 00 data16 cs nop WORD PTR [rax+rax*1+0x0]
c1c: 00 00 00 00
the vDSO after:
0000000000000c10 <__vdso_clock_gettime@@LINUX_2.6>:
c10: 48 b8 50 5b 7e 2c 37 movabs rax,0x56372c7e5b50
c17: 56 00 00
c1a: ff e0 jmp rax
c1c: 90 nop
c1d: 90 nop
c1e: 90 nop
c1f: 90 nop
x86_64
, on Linux.LD_PRELOAD