Truth, Computing and Fail

  • Home
  • About

Examining the Linux VDSO

anomit | April 18, 2010

I have been recently looking into the sysenter/sysexit way of implementing system calls on Linux. It’s then that I came to know about the concept of VDSO (Virtual Dynamic Shared Object). It may look hacky to some but IMO, it’s quite an elegant and practical solution to overcome the incompatibilities that might be introduced if it was left to the userland libraries like libc to use the software interrupt or sysenter/sysexit mechanism. You will get more information about the VDSO here than I could ever dig into.

Even though the post linked above is very informative, it suffers from the same problems that plague most of the resources on linux kernel on the web. A couple of things are outdated there which could seriously put you off if you like to get your hands dirty along with reading such stuff.

  • It states that the VDSO is

    a shared object exposed by the kernel at a fixed address in every process’ memory

    Unfortunately, this isn’t the case anymore. It might have been true for the <2.6.15 kernels but it certainly isn't that way on my 2.6.32 kernel. To get an idea, try this command a few times:
    cat /proc/self/maps | fgrep vdso
    This will give you the memory map of the process running `cat` itself. You will see the memory address to which the vdso is mapped is different each time rather than the fixed mapping to 0xffffe000 as the post claims, which brings us to our second problem.

  • Assuming the fixed mapping at 0xffffe000, the post tells you to use dd to extract the relevant information by accessing the process' pages through /proc/self/mem.
    dd if=/proc/self/mem of=linux-gate.dso bs=4096 skip=1048574 count=1
    But things aren't the same now. You will never know the pages to skip over because the VDSO is always mapped at a different location everytime you run the `dd` command. If you don't believe me, try it out yourself.

To overcome this problem, I created this small script in python which will extracts the VDSO from its own mapping into a file and then you can use `objdump` to examine it.

"""
This script writes the VDSO to the file linux-gate.dso.1 .
Use `objdump -d linux-gate.dso.1` to examine it.
You might also want to play around more with the other objdump options and
the readelf tool :) 

LICENSE: MIT License ( http://www.opensource.org/licenses/mit-license.php )
"""
from __future__ import with_statement
import os
import re

## regex pattern for finding out the memory address range from the output line
pattern = re.compile(r'[\w\d]+-[\w\d]+')
with open('/proc/self/maps', 'r') as file:
    for line in file:
        line = line.rstrip()
        if '[vdso]' in line:
            addr_range = pattern.findall(line)[0]
            start_addr, end_addr = [int(addr, 16)
                                    for addr in addr_range.split('-')]

fd = os.open('/proc/self/mem', os.O_RDONLY)
os.lseek(fd, start_addr, os.SEEK_SET)
buf = os.read(fd, (end_addr-start_addr))

with open('linux-gate.dso.1', 'w') as file:
    file.write(buf)
    file.close()
os.close(fd)

I also created a github gist in case you need to track any further corrections to problems that might arise later on or maybe fork it.

Categories
Coding, GNU/Linux
Tags
kernel, linux, python, syscalls, system calls
Comments rss
Comments rss
Trackback
Trackback

« Symlinks in a libfs virtual file system: The Pains

10 responses

[...] This post was mentioned on Twitter by Anomit Ghosh,

Tweets that mention Truth, Computing and Fail » Examining the Linux VDSO -- Topsy.com | April 18, 2010

[...] This post was mentioned on Twitter by Anomit Ghosh, PlanetManipal. PlanetManipal said: Examining the Linux VDSO: I have been recently looking into the sysenter/sysexit way of implementing system calls … http://bit.ly/dBrTcP [...]

Great post. I've been looking for something like that for

Yago Mouriño Mendaña | May 18, 2010

Great post. I’ve been looking for something like that for weeks. Thank you.

[...] this blog post from Johan Petersson for another treatment

Stupid tricks at the userspace/kernelspace boundary, part 1 « syskblogd | July 19, 2010

[...] this blog post from Johan Petersson for another treatment of the first 3/5 of this, and this blog post from Anomit Ghosh for a Python version of [...]

hmm, why not dd if=/proc/self/mem of=vdso skip=$((0x`cat /proc/self/maps |

Suresh Kumar | July 21, 2010

hmm, why not
dd if=/proc/self/mem of=vdso skip=$((0x`cat /proc/self/maps | grep vdso | cut -d'-' -f1`/0x1000)) count=1 bs=$((0x1000))

Updated Seem to have missed objdump dd if=/proc/self/mem of=- skip=$((0x`cat /proc/self/maps |

Suresh Kumar | July 21, 2010

Updated

Seem to have missed objdump


dd if=/proc/self/mem of=- skip=$((0x`cat /proc/self/maps | grep vdso | cut -d'-' -f1`/0x1000)) count=1 bs=$((0x1000)) | objdump -d --start-address=0xffffe000 -

Thanks for posting this article. I read the original

Ezra Gilbert | September 1, 2010

Thanks for posting this article. I read the original posting and was stuck on these very same issues. But when I try to run your script I get error:

[root@asm-99 ~]# ./vdso.py
File “./vdso.py”, line 20
with open(‘/proc/self/maps’, ‘r’) as file:
^
SyntaxError: invalid syntax

Do I need a particular version of python ? I am using 2.4.3.

Thanks

Suresh, Your dd 1-liner gives me the following error: dd if=/proc/self/mem of=vdso

Ezra Gilbert | September 1, 2010

Suresh,

Your dd 1-liner gives me the following error:

dd if=/proc/self/mem of=vdso skip=$((0x`cat /proc/self/maps | grep vdso | cut -d’-’ -f1`/0×1000)) count=1 bs=$((0×1000))
dd: reading `/proc/self/mem’: Input/output error
0+0 records in
0+0 records out
0 bytes (0 B) copied, 0.000162585 seconds, 0.0 kB/s

Do I need to do something to make /proc/self/mem readable? I am on 2.6.18 kernel.

Thanks.

Ezra, you need Python version 2.5 and above to support

anomit | September 1, 2010

Ezra, you need Python version 2.5 and above to support the context manager concept used by the `with’ statement. More here: http://docs.python.org/release/2.5.2/lib/typecontextmanager.html

Sorry for that. You can create just a simple file object using the normal open() and work with it :) .

Here is a version of the python script that works

Ezra Gilbert | September 1, 2010

Here is a version of the python script that works with python 2.4.3 (maybe 2.4.x). I basically removed the un-supported “with” statements and replaced os.SEEK_SET with 0 (per http://docs.python.org/library/os.html)

Also, I think the reason Suresh’s 1-line script does not work is because the address read for vdso is for process ‘cat’ and it is not a valid address when process ‘dd’ tries to read from /proc/self/mem. For it to work, the same process that reads the vdso address from /proc/self/maps needs to read linux-gate.so from /proc/self/mem.

-Ezra

#!/usr/bin/python

"""
http://anomit.com/2010/04/18/examining-the-linux-vdso/
http://gist.github.com/369785

This script writes the VDSO to the file linux-gate.dso.1 .
Use `objdump -d linux-gate.dso.1` to examine it.
You might also want to play around more with the other objdump options and
the readelf tool :) 

LICENSE: MIT License ( http://www.opensource.org/licenses/mit-license.php )
"""
#from __future__ import with_statement
import os
import re

## regex pattern for finding out the memory address range from the output line
pattern = re.compile(r'[\w\d]+-[\w\d]+')
file = open('/proc/self/maps', 'r')
for line in file:
    line = line.rstrip()
    if '[vdso]' in line:
        addr_range = pattern.findall(line)[0]
        start_addr, end_addr = [int(addr, 16)
                                for addr in addr_range.split('-')]
        break

fd = os.open('/proc/self/mem', os.O_RDONLY)
os.lseek(fd, start_addr, 0)
buf = os.read(fd, (end_addr-start_addr))

file = open('linux-gate.dso.1', 'w')
file.write(buf)
file.close()
os.close(fd)

The code in the last comment did not come out

Ezra Gilbert | September 1, 2010

The code in the last comment did not come out very well. Here is a link to a fork of anomit’s gist above that works with python 2.4.3: http://gist.github.com/560719

Leave a comment

You can use these tags : <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

What’s in

  • Examining the Linux VDSO
  • Symlinks in a libfs virtual file system: The Pains
  • Small rant on the FUSE API reference
  • Kernel module debugging: a simple technique
  • Vim/Cscope quickie

Blogroll

  • Akshay Kothari
  • Ankur Shrivastav (OS)
  • Ankur Sinha
  • Harsh J
  • Hullap
  • LUG manipal
  • Swap

Tags

aircrack airfail airtel assembly blues build c Coding college country cryptography dean faculty file systems fuckery gnuplot hacking India kernel linux mangalore manipal mpd music NASM plugin politicians pub culture python rant rock sam scheduler simulation SSFNet stupidity supernatural suppression syscall syscalls system calls unix vim xchat xml

Archives

  • April 2010
  • January 2010
  • December 2009
  • November 2009
  • October 2009
  • September 2009
  • July 2009
  • June 2009
  • May 2009
  • April 2009
  • March 2009
  • January 2009
  • November 2008
  • September 2008
  • August 2008
  • July 2008
  • June 2008
  • May 2008
  • April 2008
  • March 2008
  • February 2008
  • January 2008
  • October 2007
  • September 2007
  • July 2007
  • June 2007
  • May 2007
  • April 2007
  • March 2007

License

Creative Commons License
This work by Anomit Ghosh is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 2.5 India License.
rss Comments rss valid xhtml 1.1 design by jide powered by Wordpress get firefox