Wednesday, January 04, 2012

Some knowledge about vdso

As we can learn about linux gate or virtual dynamic shared object (VDSO) or linux-gate.so.1 or linux-vdso.so.1 by following page :
http://www.trilithium.com/johan/2005/08/linux-gate/
A lot of things explained in the above page, but when tried things, I faced some issues and solved as following :

1. Looking at ELF Auxiliary Vector
     --> One can see all the ELF Auxiliary vectors on say 'true' binary as :
              LD_SHOW_AUXV=1 /bin/true
          This will actually execute the binary, and will show its ELF Auxilliary vector values.
2. It states that
a shared object exposed by the kernel at a fixed address in every process’ memory
Unfortunately, its no longer the case. When I tried getting the maps of vdso a couple of times :
cat /proc/self/maps | grep vdso
I always got the different address

3. Getting vdso segment.
     As the above link says, dumping vdso can be done as :
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.
(Note that 0xffffe000/4096 = 1048574)

dd if=/proc/self/mem of=linux-gate.dso bs=4096 skip=1048574 count=1

but you will be surprised to get the following errors :
-- reading /proc/self/mem : I/O error
 And no output..
Well, the reason of this error is stated beautifully in the following link :
http://unix.stackexchange.com/questions/6301/how-do-i-read-from-proc-pid-mem-under-linux
A good point made here is :
" since the first page in a process is never mapped (so that dereferencing a NULL pointer fails cleanly rather than unintendedly accessing actual memory), reading the first byte of /proc/$pid/mem always yield an I/O error."

Now then how should we dump vdso.... I then googled around ... found out the following post facing and solved  the same issue I am facing :
http://anomit.com/2010/04/18/examining-the-linux-vdso/
He has actually created the following python script to get the vdso map of the current process, and seek to it in /proc/self/mem, and write down the required bytes to new file . Following is the script :
---------

#! /usr/bin/env python from __future__ import with_statement import re import os ## 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('-')] break file.close() 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)
------------------------

Another way to dump vdso, is to seek to address specified by ELF auxiliary vector AT_SYSINFO_EHDR, and dump 1 page (4096 bytes). Something like this :
-----------

#include 
#include 
#include 
#include 

static void *getsys(char **envp) 
{
   Elf64_auxv_t *auxv;
   
   /* walk past all env pointers */
   while (*envp++ != NULL);

   /* and find ELF auxiliary vectors (if this was an ELF binary) */
   auxv = (Elf64_auxv_t *) envp;
   
   for ( ; auxv->a_type != AT_NULL; auxv++)
     if (auxv->a_type == AT_SYSINFO_EHDR)
       return (void *)auxv->a_un.a_val;
   
   fprintf(stderr, "no AT_SYSINFO_EHDR auxv entry found\n");
   exit(1);
}

int main(int argc, char *argv[], char **envp)
{
   unsigned char buffer[4096];
   void *p;
   
   p=getsys(envp);
   fprintf(stderr, "AT_SYSINFO_EHDR at %p\n",p);
   memcpy(buffer, p, 4096);
   write(1, buffer, 4096);
}

0 comments: