TPOM

Melting clock


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:

```python

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).

How it works

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:

The 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

Notes