linux-kernelsystem-callsstracevdso

Capture vDSO in strace


I was wondering if there is a way to capture (in other words observe) vDSO calls like gettimeofday in strace.

Also, is there a way to execute a binary without loading linux-vdso.so.1 (a flag or env variable)?

And lastly, what if I write a program that delete the linux-vdso.so.1 address from the auxiliary vector and then execve my program? Has anyone ever tried that?


Solution

  • You can capture calls to system calls which have been implemented via the vDSO by using ltrace instead of strace. This is because calls to system calls implemented via the vDSO work differently than "normal" system calls and the method strace uses to trace system calls does not work with vDSO-implemented system calls. To learn more about how strace works, check out this blog post I wrote about strace. And, to learn more about how ltrace works, check out this other blog post I wrote about ltrace.

    No, it is not possible to execute a binary without loading linux-vdso.so.1. At least, not on my version of libc on Ubuntu precise. It is certainly possible that newer versions of libc/eglibc/etc have added this as a feature but it seems very unlikely. See the next answer for why.

    If you delete the address from the auxillary vector, your binary will probably crash. libc has a piece of code which will first attempt to walk the vDSO ELF object, and if this fails, will fall back to a hardcoded vsyscall address. The only way it will avoid this is if you've compiled glibc with the vDSO disabled.

    There is another workaround, though, if you really, really don't want to use the vDSO. You can try using glibc's syscall function and pass in the syscall number for gettimeofday. This will force glibc to call gettimeofday via the kernel instead of the vDSO.

    I've included a sample program below illustrating this. You can read more about how system calls work by reading my syscall blog post.

    #include <sys/time.h>
    #include <stdio.h>
    
    #define _GNU_SOURCE
    #include <unistd.h>
    #include <sys/syscall.h>
    
    int
    main(int argc, char *argv[]) {
        struct timeval tv;
        syscall(SYS_gettimeofday, &tv);
    
        return 0;
    }
    

    Compile with gcc -o test test.c and strace with strace -ttTf ./test 2>&1 | grep gettimeofday:

    09:57:32.651876 gettimeofday({1467305852, 651888}, {420, 140735905220705}) = 0 <0.000006>