动态库so被覆盖导致coredump

linux环境巡检日志时,发现了一个core文件。dmesg显示错误:segfault at 1836 ip 0000000000001836 sp 00007f34b0d13a18 error 14 。问了下执行的同事并检查了操作记录,才发现程序所依赖的so文件中间被cp覆盖了。由此引出两个问题。

一、为何cp覆盖进程的动态库(so)会导致coredump?

1.应用程序通过dlopen打开so的时候,kernel通过mmap把so加载到进程地址空间,对应于vma里的几个page.
2.在这个过程中loader会把so里面引用的外部符号例如malloc printf等解析成真正的虚存地址。
3.当so被cp覆盖时,确切地说是被trunc时,kernel会把so文件在虚拟内的页purge 掉。
4.当运行到so里面的代码时,因为物理内存中不再有实际的数据(仅存在于虚存空间内),会产生一次缺页中断。
5.Kernel从so文件中copy一份到内存中去,a)但是这时的全局符号表并没有经过解析,当调用到时就产生segment fault , b)如果需要的文件偏移大于新的so的地址范围,就会产生bus error.

所以,如果用相同的so去覆盖
A) 如果so 里面依赖了外部符号,coredump
B) 如果so里面没有依赖外部符号,运气不错,不会coredump

参考:https://www.xuebuyuan.com/448876.html

二、中为什么动态换bin程序不会core而换so容易core?

  Linux中, 如果一个程序正在运行中,那么要动态替换程序,cp new old, 会发现报“text file busy"。用 strace 查看cp命令输出,会发现报:open old的时候,用了 O_WRONLY|O_TRUNC,open 返回 ETXTBSY (Text file busy)。也就是说,这时候这个文件已经是不可更改的了。如果用 cp -rf 复制,检验下又会发现,其实复制得到的文件的文件虽然还是原来的名字,但是 inode 已经变了。也就是说,cp -rf 其实还是没有真正的覆盖成功。

  这些都是为什么呢?首先不得不说下linux中二进制文件执行的时候的延迟加载。也就是说如果一个bin文件并不会一次性加载进内存,而是按需逐步加载的。为了防止bin文件修改后动态按需load的时候出错,所以内核系统就会把文件锁死,使得不能随便更改。这解释了为什么会“text file busy”。同时也说明了,rm + cp方式动态替换程序的时候,或者动态删除 bin 的时候,“延迟加载”不会导致程序出core。因为文件的inode还没有释放,等于说原文件还存在。

  对于 .so 动态库文件,动态覆盖容易导致出core,是因为系统没有对so作特殊保护,不会"text file busy"之故。

参考:http://blog.sina.com.cn/s/blog_6e32babb0102w000.html

你可能感兴趣的:(动态库so被覆盖导致coredump)