天天看點

關于so檔案cp覆寫導緻調用者core的研究

先說cp好mv/rm的差別:

cp from to,則被覆寫檔案 to的inode依舊不變(屬性也不變),内容變為from的;

mv from to,則to的inode變為from的,相應的,to的屬性也成了from的;rm類似;

問題,假如程式 main.out依賴的so檔案libtest.so被cp掉,會發生什麼?

strace cp test2 test  2>&1 | grep open.*test
open("test2", O_RDONLY|O_LARGEFILE)     = 3
open("test", O_WRONLY|O_TRUNC|O_LARGEFILE) = 4      

  cp的實作邏輯不是“rm + open(O_CREAT)”,而上面的實作方式才是最可靠的(保證了時序安全和目标檔案的屬性)。這解釋了為什麼cp的目标檔案會繼承被覆寫檔案的屬性而非源檔案。

Linux由于Demand Paging機制的關系,必須確定正在運作中的程式鏡像(注意,并非檔案本身)不被意外修改,是以核心在啟動程式後會綁定 記憶體頁 到這個so的inode,而一旦此inode檔案被open函數O_TRUNC掉,則kernel會把so檔案對應在虛存的頁清空,這樣當運作到so裡面的代碼時,因為實體記憶體中不再有實際的資料(僅存在于虛存空間内),會産生一次缺頁中斷。Kernel從so檔案中copy一份到記憶體中去,a)但是這時的全局符号表并沒有經過解析,當調用到時就産生segment fault , b)如果需要的檔案偏移大于新的so的位址範圍,就會産生bus error。

備注:如果用相同的so去cp覆寫

A) 如果so 裡面依賴了外部符号(如标準庫),coredump

B) 如果so裡面沒有依賴外部符号,運氣不錯,不會coredump

不必說,先rm再cp的話,新檔案的inode其實已經改變了,原inode并沒有被真正删除,直到核心釋放對它的引用(引用舊SO的程序退出,而新程序當然呈現的就是新so的效果了,新程序和core無關啦)。同理,mv隻是改變了檔案名,其inode不變,新檔案使用了新的inode。

參考: 

[1]http://www.piao2010.com/%E4%B8%BA%E4%BD%95cp%E8%A6%86%E7%9B%96%E8%BF%9B%E7%A8%8B%E7%9A%84%E5%8A%A8%E6%80%81%E5%BA%93so%E4%BC%9A%E5%AF%BC%E8%87%B4coredump

[2]http://blog.csdn.net/wei_yongtao/article/details/40145891