关于vdso

学习《网络渗透技术》,按着书里的代码敲,gdb后发现结果与书上的不一样。自己也不知道哪里出现了问题。就一步步找,看到了一个vdso的东东,没见过,从网上找了两篇博文,半知半解的读了。留存一下,待后查。
Starting program: /home/***/test/simple_overflow 
*** stack smashing detected ***: /home/***/test/simple_overflow terminated
======= Backtrace: =========
/lib/libc.so.6(__fortify_fail+0x50)[0x214980]
/lib/libc.so.6(+0xe592a)[0x21492a]
/home/***/test/simple_overflow[0x8048450]
/lib/libc.so.6(__libc_start_main+0x0)[0x145c00]
======= Memory map: ========
00110000-0012c000 r-xp 00000000 08:07 655353     /lib/ld-2.12.1.so
0012c000-0012d000 r--p 0001b000 08:07 655353     /lib/ld-2.12.1.so
0012d000-0012e000 rw-p 0001c000 08:07 655353     /lib/ld-2.12.1.so
0012e000-0012f000 r-xp 00000000 00:00 0          [vdso]
0012f000-00286000 r-xp 00000000 08:07 655377     /lib/libc-2.12.1.so
00286000-00287000 ---p 00157000 08:07 655377     /lib/libc-2.12.1.so
00287000-00289000 r--p 00157000 08:07 655377     /lib/libc-2.12.1.so
00289000-0028a000 rw-p 00159000 08:07 655377     /lib/libc-2.12.1.so
0028a000-0028d000 rw-p 00000000 00:00 0 
0028d000-002a7000 r-xp 00000000 08:07 655411     /lib/libgcc_s.so.1
002a7000-002a8000 r--p 00019000 08:07 655411     /lib/libgcc_s.so.1
002a8000-002a9000 rw-p 0001a000 08:07 655411     /lib/libgcc_s.so.1
08048000-08049000 r-xp 00000000 08:07 561482     /home/***/test/simple_overflow
08049000-0804a000 r--p 00000000 08:07 561482     /home/***/test/simple_overflow
0804a000-0804b000 rw-p 00001000 08:07 561482     /home/***/test/simple_overflow
0804b000-0806c000 rw-p 00000000 00:00 0          [heap]
b7fef000-b7ff0000 rw-p 00000000 00:00 0 
b7ffe000-b8000000 rw-p 00000000 00:00 0 
bffdf000-c0000000 rw-p 00000000 00:00 0          [stack]

Program received signal SIGABRT, Aborted.
0x0012e416 in __kernel_vsyscall ()
------------------------------------------------------------------------------------

第一篇:http://www.byvoid.com/blog/linux-kernel-and-glibc/

Linux内核与glibc

轉自[Fedora 中文郵件列表] 作者microcai@fedoraproject.org

往往内核添加了一个功能, glibc 要花很久才会用上。本来linux 那边为这个功能是否进入内核已经吵半天了,glibc这边又要为是否使用这个内核新特性再次吵架半天 (glibc 不是 Linux 专有的,还得考虑 BSD (虽然人家也不用 glibc),SysV Windows(诶,这没办法),还有 sun 那消亡的 solaris , 还有, 自家的 Hurd。然后,总之,这样新特性让人的接受上。。。 太慢了。

说近点的,fnotify glibc还没有对应的包装函数呢,futex 和 NPTL 又是花了许久才进入主流的。libc 是 app和内核的桥梁,libc 理应快速跟上内核的接口变化。但是 glibc 和内核不是一块开发的,所以,这只是理想罢了。glibc 还要去兼容不同版本的内核呢!

而内核也要去兼容不同版本的 glibc . 双方都背负了太多的历史包袱。glibc 至今保留 LinuxThreads 兼容2.4版本的古老内核。Linux对已经没用,甚至有bug(接口的问题导致一些bug是必须的)的系统调用也必须保留,谁知道用户会用哪个版本的glibc呢?虽然新的glibc会使用新的调用,但是提供和老的调用一致的 API 来兼容,但是,用户只升级内核而不升级 glibc 是常有的事情。就算升级了glibc ,你新版本的 glibc 一定就用上内核的新接口?还是再等几年等 glibc 的开发者吵架结束吧。

于是乎,Linux 的大牛们再次使出绝招: 让 libc 变成 VDSO 进驻内核。

这里普及一下 VDSO 这个小知识,知道的人跳过,不知道的人读一下
VDSO 就是 Virtual Dynamic Shared Object ,就是内核提供的虚拟的 .so , 这个 .so 文件不在磁盘上,而是在内核里头。
内核把包含某 .so 的内存页在程序启动的时候映射入其内存空间,对应的程序就可以当普通的 .so 来使用里头的函数。比如 syscall()
这个函数就是在 linux-vdso.so.1 里头的,但是磁盘上并没有对应的文件. 可以通过 ldd /bin/bash 看看

这样,随内核发行的 libc 就唯一的和一个特定版本的内核绑定到一起了。注意,VDSO只是随内核发行,没有在内核空间运行,这个不会导致内核膨胀。这样内核和libc都不需要为兼容多个不同版本的对方而写太多的代码,引入太多的 bug 了。

当然, libc 不单单有到内核的接口,还有很多常用的函数,这些函数不需要特别的为不同版本的内核小心编写,所以,我估计Linux上会出现两个 libc , 一个 libc 在内核,只是系统调用的包裹,另一个libc 还是普通的 libc ,只是这个 libc 再也不需要花精力去配合如此繁多的 kernel 了。

姑且一个叫kernellibc, 一个叫 glibc : printf() 这些的还在 glibc。open() , read() , write(), socket() 这些却不再是 glibc 的了,他们在kernellibc。

第二篇:http://www.cppblog.com/hex108/archive/2010/11/22/134313.html

linux下的vdso与vsyscall

传统的系统调用是怎样的?    —— int 0x80的时代

....             ;通过寄存器传参
mov $n ,eax      ;将系统调用号放到eax中int 0x80


sysenter/sysexit的出场

        在一个Kernel.org的邮件列表中,有一封邮件讨论了“"Intel P6 vs P7 system call performance”,最后得出的结论是采用传统的int 0x80的系统调用浪费了很多时间(具体原因可以看参考资料1),而sysenter/sysexit可以弥补这个缺点,所以决定在linux内核中用后都替换前者(最终在2.6版本的内核中才加入了此功能,即采用sysenter/sysexit)。

        在替换之前首先需要知道满足如下条件的ntel机器才会有sysenter/sysexit指令对:Family >= 6,Model >= 3,Stepping >= 3

        如何用替换sysenter/sysexit替换以前的int 0x80呢?linux kenerl 需要考虑到这点:有的机器并不支持sysenter/sysexit  , 于是它跟glibc说好了,“你以后调用系统调用的时候就从我给你的这个地址调用,这个地址指向的内容要么是int 0x80调用方式,要么是sysenter/sysexit调用方式,我会根据机器来选择其中一个”(kernel与glibc的配合是如此的默契),这个地址便是vsyscall的首地址。

         可以将vdso看成一个shared objdect file(这个文件实际上不存在),内核将其映射到某个地址空间,被所有程序所共享。(我觉得这里用到了一个技术:多个虚拟页面映射到同一个物理页面。即内核把vdso映射到某个物理页面上,然后所有程序都会有一个页表项指向它,以此来共享,这样每个程序的vdso地址就可以不相同了)

hex108@ubuntu:~/program$ uname -a
Linux ubuntu 2.6.35-22-generic #33-Ubuntu SMP Sun Sep 19 20:34:50 UTC 2010 i686 GNU/Linux
hex108@ubuntu:~/program$ sudo sysctl -w kernel.randomize_va_space=0     //这个是必须的,否则vdso的地址是随机的(vsyscall的地址也会相应
                                                                        // 地发生变化 ),在下面dd的时候就会出现错误
                                                                        //dd: reading `/proc/self/mem': Input/output error
                                                                         kernel.randomize_va_space = 0
hex108@ubuntu:~/program$ cat /proc/self/maps 
00110000-0012c000 r-xp 00000000 08:01 260639     /lib/ld-2.12.1.so
0012c000-0012d000 r--p 0001b000 08:01 260639     /lib/ld-2.12.1.so
0012d000-0012e000 rw-p 0001c000 08:01 260639     /lib/ld-2.12.1.so
0012e000-0012f000 r-xp 00000000 00:00 0          [vdso]
0012f000-00286000 r-xp 00000000 08:01 260663     /lib/libc-2.12.1.so
00286000-00287000 ---p 00157000 08:01 260663     /lib/libc-2.12.1.so
00287000-00289000 r--p 00157000 08:01 260663     /lib/libc-2.12.1.so
00289000-0028a000 rw-p 00159000 08:01 260663     /lib/libc-2.12.1.so
0028a000-0028d000 rw-p 00000000 00:00 0 
08048000-08051000 r-xp 00000000 08:01 130326     /bin/cat
08051000-08052000 r--p 00008000 08:01 130326     /bin/cat
08052000-08053000 rw-p 00009000 08:01 130326     /bin/cat
08053000-08074000 rw-p 00000000 00:00 0          [heap]
b7df0000-b7ff0000 r--p 00000000 08:01 660864     /usr/lib/locale/locale-archive
b7ff0000-b7ff1000 rw-p 00000000 00:00 0 
b7ffd000-b7ffe000 r--p 002a1000 08:01 660864     /usr/lib/locale/locale-archive
b7ffe000-b8000000 rw-p 00000000 00:00 0 
bffdf000-c0000000 rw-p 00000000 00:00 0          [stack]
hex108@ubuntu:~/program$ dd if=/proc/self/mem of=gate.so bs=4096 skip=$[0x12e] count=1
dd: `/proc/self/mem': cannot skip to specified offset
1+0 records in
1+0 records out
4096 bytes (4.1 kB) copied, 0.00176447 s, 2.3 MB/s
hex108@ubuntu:~/program$ file gate.so 
gate.so: ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), dynamically linked, stripped
hex108@ubuntu:~/program$ objdump -d gate.so 

gate.so:     file format elf32-i386


Disassembly of section .text:

ffffe400 <__kernel_sigreturn>:
ffffe400:	58                   	pop    %eax
ffffe401:	b8 77 00 00 00       	mov    $0x77,%eax
ffffe406:	cd 80                	int    $0x80
ffffe408:	90                   	nop
ffffe409:	8d 76 00             	lea    0x0(%esi),%esi

ffffe40c <__kernel_rt_sigreturn>:
ffffe40c:	b8 ad 00 00 00       	mov    $0xad,%eax
ffffe411:	cd 80                	int    $0x80
ffffe413:	90                   	nop

ffffe414 <__kernel_vsyscall>:
ffffe414:	cd 80                	int    $0x80
ffffe416:	c3                   	ret
 

syscall 才是最后的赢家?

         x86 64位从AMD引进了syscall指令(我在x86 64的机器上,看到的结果是syscall取代了sysenter/sysexit(所有的系统调用用的都是syscall)),但是vdso,vsyscall的机制依旧未变,只是kernel决定只在遇到以下几个系统调用gettimeofday,time和getcpu(通过内核里vsyscall.h中enum vsyscall_num的声明看出来,或者在glibc源代码中搜索“VSYSCALL_ADDR_”(

#define VSYSCALL_ADDR_vgettimeofday    0xffffffffff600000

#define VSYSCALL_ADDR_vtime            0xffffffffff600400

#define VSYSCALL_ADDR_vgetcpu          0xffffffffff600800

))时才采用vdso机制(间接调用syscall,具体可以参看资料2),其他系统调用直接用指令syscall,原因是:


 

         "快速系统调用指令"比起中断指令来说,其消耗时间必然会少一些,但是随着 CPU 设计的发展,将来应该不会再出现类似 Intel Pentium4 这样悬殊的差距。而"快速系统调用指令"比起中断方式的系统调用方式,还存在一定局限,例如无法在一个系统调用处理过程中再通过"快速系统调用指令"调用别的系统调用。因此,并不一定每个系统调用都需要通过"快速系统调用指令"来实现。比如,对于复杂的系统调用例如 fork,两种系统调用方式的时间差和系统调用本身运行消耗的时间来比,可以忽略不计,此处采取"快速系统调用指令"方式没有什么必要。而真正应该使用"快速系统调用指令"方式的,是那些本身运行时间很短,对时间精确性要求高的系统调用,例如 getuid、gettimeofday 等等。因此,采取灵活的手段,针对不同的系统调用采取不同的方式,才能得到最优化的性能和实现最完美的功能。      ----引自参考资料1


ps:文中的内核版本为2.6.36,glibc版本为2.11

参考资料:

1.  Linux 2.6 对新型 CPU 快速系统调用的支持http://www.ibm.com/developerworks/cn/linux/kernel/l-k26ncpu/index.html  (这篇我觉得最好)

2. System Calls : http://www.win.tue.nl/~aeb/linux/lk/lk-4.html(里面有程序可以用来搜索vsyscall等的地址,很直接)

3. What is linux-gate.so.1 : http://www.trilithium.com/johan/2005/08/linux-gate/

4. Intel手册,里面有各种资料,手册还是很重要的,也是最基本的

转载于:https://my.oschina.net/orion/blog/16013

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值