stephenrkell / libsystrap

Monitor, rewrite and/or otherwise trap system calls... on Linux/x86{,-64} only, for now.
GNU General Public License v3.0
59 stars 7 forks source link

32-bit x86 misses most calls, since they are made via vDSO #13

Closed stephenrkell closed 3 years ago

stephenrkell commented 3 years ago

On x86, glibc uses Linux's vDSO for lots of syscalls, so we miss these.

We can probably get them if we can access the _dl_sysinfo field of the rtld_global_ro struct and of each thread control block, since glibc does an indirect call via these:

#if I386_USE_SYSENTER
# ifdef PIC
#  define ENTER_KERNEL call *%gs:SYSINFO_OFFSET
# else
#  define ENTER_KERNEL call *_dl_sysinfo
# endif
#else
# define ENTER_KERNEL int $0x80
#endif
SYSINFO_OFFSET          offsetof (tcbhead_t, sysinfo)

(the latter is from sysdeps/i386/nptl/tcb-offsets.sym, the former from sysdeps/unix/sysv/linux/i386/sysdep.h)

A more nuclear way to catch these is to mess with AT_SYSINFO, i.e. fake up our own vDSO. That is logically cleaner, but it can't work in general because one point of vDSO is that it has privileged mappings that only the kernel can make. Perhaps some hybrid approach is possible where we secretly make use of those mappings.

Remember that on x86 vDSO is used to minimise syscall overhead: there are multiple incompatible "fast" ways in later x86 processors do to syscalls, via sysenter or syscall, i.e. faster than int $0x80. The kernel serves these up in the vDSO so that client code like glibc doesn't need to know which specific processor it's running on.

stephenrkell commented 3 years ago

This is fixed as of 08ddc6ddfca7365e23c2a537686cc80d780a7aa6. Our approach to copying the vDSO is quite naive, so may yet give rise to bugs, but I'll save those for future issues.