Creating a vDSO: the Colonel's Other Chicken


Compiling, Linking and Running

Wait, is that all there is to adding a vDSO? Um, yes. Of course, if the function was something supported by the C library (glibc, in our case), you can hack that to do the detection of vDSO and then the actual call. However, I mentioned we wouldn't be hacking glibc. And, you don't need to anyway, because getting the code to work is pretty simple. With the chunks described above all in place, it's time to start building. Just configure and compile your kernel as you typically would:

make menuconfig
make bzImage
make modules
make modules_install

Now, install and boot your new modified vDSO kernel. Once that is up and running, it's time to test a few things, mainly the vDSO stuff you just added. Let's compile a test case to exercise the vDSO call:

/* notb.c */
#include <stdio.h>

int main(void)
    int notb = number_of_the_beast();
    printf("His number is %d\n", notb);

    return 0;

Then, compile the code above as:

gcc notb.c -o notb

The file you link against is, which provides the symbol resolution needed to make the kernel call. The kernel version of number_of_the_beast() is called, even if the code for that function is completely different in Where is located? It's located in the kernel build directory after building the kernel: linux-2.6.37/arch/x86/vdso/

At runtime, when a program executes number_of_the_beast, the kernel code is called and not the version of number_of_the_beast() in the file. If you modify the kernel and, say, have number_of_the_beast() return 42, then unless you load that kernel, you still will get 666. Even if you compile the test example above with the newer modified-to-42

Another way of getting the file is by writing a program that extracts the vDSO memory from a running executable. Numerous sources on-line explain how to do this, but I briefly describe it here. The vDSO page, which is mapped into the memory of every running process, can be in a non-deterministic memory range of your executing process, thanks to Linux's address space layout randomization (ASLR). To get this address, a running program can find its memory information from the file /proc/self/maps. In there, a line with the text [vdso] exists. That line contains the address range in the executing process of the vDSO page. For example, you could run cat /proc/self/maps.

Note that running this command multiple times produces different address ranges for [vdso] thanks to (if your kernel supports it) address space layout randomization.

The output should look something similar to:

7fff40d71000-7fff40d72000 r-xp 00000000 00:00 0 [vdso]

The above range is showing for the cat process you just executed that the address range for the vDSO page is located starting at 7fff40d71000 and ending at 7fff40d7200. Subtracting the start and end range, you get 0x1000 or 4096 bytes. 4096 is the page size often used in the kernel. Listing 1 shows code for extracting the vDSO from a running kernel, and it is based on code from the "Examining the Linux VDSO" article listed in Resources.

A simple dumping of the dynamic object symbols can be conducted via:

objdump -T

Because a shared library is also an elf, the readelf tool also can be used on

Listing 1. Extracting the vDSO from a Running Kernel

/* extract_vdso.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char **argv)
    char        buf[256], *mem;
    const char *range_name;
    FILE       *rd, *wr;
    long long   start_addr, end_addr;

    /* Open file for writing the vdso data to */
    if (argc != 3)
                "Usage: %s <file> <string>\n"
                "\t<file>:   File to write the vdso data to.\n"
                "\t<string>: Name of the mapped in region, e.g. vdso\n",


    range_name = argv[2];

    if (!(wr = fopen(argv[1], "w")))
        perror("Error: fopen() - output file");

    /* Get this process' memory layout */
    if (!(rd = fopen("/proc/self/maps", "r")))
        perror("Error: fopen() - /proc/self/maps");

    /* Find the line in /proc/self/maps that contains 
       the substring [vdso] * */
    while (fgets(buf, sizeof(buf), rd))
        if (strstr(buf, range_name))


    /* Locate the end memory range for [vdso] */
    end_addr = strtoll((strchr(buf, '-') + 1), NULL, 16);

    /* Terminate the string so we can get the start 
       address really easily * */
    *(strchr(buf, '-')) = '\0';
    start_addr = strtoll(buf, NULL, 16);

    /* Open up the memory page and extract the vdso */
    if (!(rd = fopen("/proc/self/mem", "r")))
        perror("Error: fopen() - /proc/self/mem");

    /* Hop to the vdso portion */
    fseek(rd, start_addr, SEEK_SET);

    /* Copy the memory locally and then move it to the file */
    mem = malloc(end_addr - start_addr);
    if (!fread(mem, 1, end_addr - start_addr, rd))
        perror("Error: read() - /proc/self/mem");

    /* Write the data to the specified output file */
    if (!fwrite(mem, 1, end_addr - start_addr, wr))
        perror("Error: fwrite() - output file");


    printf("Start: %p\nEnd:   %p\nBytes: %d\n",
            (void *)start_addr, (void *)end_addr, (int)(end_addr -

    return 0;

Security Implication

Anytime you dabble with the kernel, you should consider the security implications. If you think you can "own" someone by creating your own vDSO calls, you might want to think again. Because adding a vDSO requires users to bake their own kernels, the only people they could be compromising is their system and the users on their system. Of course, any dabbling with kernel resources should be done with much consideration. Remember, playing with vDSO goodies occurs in userland; however, your vDSOs can access kernel data. And, your kernel can read vDSO data. That can be a concern, but I'll leave that up to you as an exercise for finding anything exploitable.

Finally, this article is just a little one-two on how to cook up your own vDSO. Now go make yourself a smoking kernel.


GNU/Linux Kernel. 2.6.37:

"6.30 Declaring Attributes of Functions" (GCC Manual):

"Weak Symbol" (Wikipedia):

"Examining the Linux VDSO" (Truth, Computing and Fail):

Johan Peterson's "What is":

Matt Davis' "Linux syscall, vsyscall, and vDSO...Oh My!":


Matt Davis is a software engineer on leave from his job in the US to pursue a PhD from the Computer Science Department at the University of Melbourne, where he is focusing his hackery toward the compiler field.


Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.


bdso8f9sa's picture

----- -----

Hi,Dear Ladies and Gentlemen,
1. sport shoes : Jordan ,Nike, adidas, Puma, Gucci, LV, UGG , etc. including women shoes and kids shoes.
2. T-Shirts : BBC T-Shirts, Bape T-Shirts, Armani T-Shirts, Polo T-Shirts,etc.
3. Hoodies : Bape hoody, hoody, AFF hoody, GGG hoody, ED hoody ,etc.
4. Jeans : Levis jeans , Gucci jeans, jeans, Bape jeans , DG jeans ,etc.
----- -----
----- -----

Service is our Lift.

enjoy yourself.

thank you!!


Good content, I trust this is

Pryanka's picture

Good content, I trust this is a good weblog about Wish to see refreshing content material next time. Thanks for sharing this publish with us. Keep it up.
hebergement audiotel voyance

Re : Creating a vDSO: the Colonel's Other Chicken

Sedot WC's picture

script code is my weakness and it is difficult for me to learn
but in this tutorial I will try hard to understand
thank you

why x86(32bit) does not have gettimeofday vdso

Fredrick's picture

Very nice article. Thanks for explaining vdso concept.
Why x86(32bit) does not have gettimeofday vdso?
Only 64bit x86 has this call implemented. Why?
Does x86 32bit have limitations?

Geek Guide
The DevOps Toolbox

Tools and Technologies for Scale and Reliability
by Linux Journal Editor Bill Childers

Get your free copy today

Sponsored by IBM

Upcoming Webinar
8 Signs You're Beyond Cron

Scheduling Crontabs With an Enterprise Scheduler
11am CDT, April 29th
Moderated by Linux Journal Contributor Mike Diehl

Sign up now

Sponsored by Skybot