Examining the Linux VDSO
anomit | April 18, 2010I 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 toolLICENSE: 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.







[...] 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, 2010Great 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, 2010hmm, 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, 2010Updated
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, 2010Thanks 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, 2010Suresh,
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, 2010Ezra, 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, 2010Here 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
The code in the last comment did not come out
Ezra Gilbert | September 1, 2010The 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