2011-10-08 16 views
4

我想攔截在dlopen()中發生的所有文件系統訪問。起初,這看起來就LD_PRELOAD-Wl,-wrap,將是可行的解決方案,但我有麻煩做他們的工作,由於一些技術原因:如何攔截dlopen()內的文件系統訪問?

  • ld.so已經由時間LD_PRELOAD映射自己的符號是處理。攔截初始加載對我來說並不重要,但此時解決了工作人員功能,以便將來的呼叫通過它們。我認爲LD_PRELOAD爲時已晚。

  • 不知何故malloc避開了這個問題,因爲上面的ld.so內malloc()不具有的功能free(),它只是調用memset()

  • 文件系統工作者功能,例如, __libc_read(),包含在ld.so中是靜態的,所以我不能用-Wl,-wrap,__libc_read來攔截它們。

這可能都意味着我需要建立直接從源我自己ld.so而不是鏈接成一個包裝。存在的挑戰是,libcrtld-libc都是從相同的來源構建的。我知道在構建rtld-libc時定義了宏IS_IN_rtld,但是如何確保在仍然導出公共接口函數的同時只有一個靜態數據結構副本? (這是一個glibc構建系統的問題,但我還沒有找到這些細節的文檔。)

有沒有更好的方法進入dlopen()

注意:我不能使用特定於Linux的解決方案,如FUSE,因爲這適用於不支持此類操作的最小「計算節點」內核。

+0

這不是你的問題的答案,所以我沒有把它作爲一個發佈,但總的來說你不能做到這一點可靠:它可以通過直接調用系統調用而不通過動態庫接口。如果您沒有完全控制您要加載的庫的編譯方式,那麼您可能會失敗。像fakeroot這樣的程序在大多數情況下都能正常工作,並且在某些情況下會出現可怕的情況。 –

+0

也就是說,你可以通過在自己的進程中運行動態庫代碼並使用'ptrace'來截獲系統調用本身來完成這項工作。我已經取得了巨大的成功,它完全避免了所有的共享庫廢話。但它確實需要你完全重新設計你的邏輯,以便擁有一個完成ptrace內容的主進程和一個執行動態庫內容的從進程。 –

+0

嗯,我需要'dlopen' /'dlsym'才能正常工作,但要以不同的方式訪問文件系統。特別是在諸如Blue Gene等HPC環境中,涉及內核文件描述符的所有操作都是從計算節點IO節點提供的。這會導致高節點併發嚴重的爭用問題。例如,加載引用大量編譯共享庫的Python應用程序在65k內核上需要大約4個小時。毋庸置疑,人們對於耗費25萬個核心小時來加載他們的節目並不感到興奮。 – Jed

回答

3

它似乎像LD_PRELOAD或輪候冊,-wrap,將是可行的解決方案

--wrap解決方案不可能是可行的:它只能在(靜態)鏈接時,你的ld.so並且libc.so.6libdl.so.2已經全部被鏈接,所以現在使用--wrap已經太遲了。

LD_PRELOAD可以工作,只是...... ld.so認爲的事實,dlopen()電話open()內部實現細節。因此,它只是調用內部__open函數,繞過PLT,並且您可以插入open

莫名其妙的malloc規避問題

這是因爲libc支持誰實現自己的malloc(例如用於調試)的用戶。因此,呼叫例如callocdlopen確實經過PLT,並通過LD_PRELOAD插入。

這可能意味着我需要直接從源代碼構建自己的ld.so,而不是將其鏈接到包裝器中。

重建的ld.so會做什麼?我想你想要它叫__llibc_open(在libc.so.6),但這不可能的原因很明顯:它是ld.soopen s libc.so.6(在進程啓動時)。

你可以重建ld.so與以open調用替換調用__open。這將導致ld.so經過PLT,並將其暴露給LD_PRELOAD中介。

如果你走這條路線,我建議你不要用你的新副本覆蓋系統ld.so(犯錯的可能性和渲染系統無法啓動太好了)。而是將其安裝到例如/usr/local/my-ld.so,然後將您的二進制文件鏈接到-Wl,--dynamic-linker=/usr/local/my-ld.so

另一種選擇:運行時修補。這有點破解,但是你可以(一旦你獲得了主控權)只需掃描.textld.so,然後查找CALL __open指令。如果沒有剝離ld.so,則可以找到內部__open以及要修補的功能(例如open_verifydl-load.c中)。一旦你發現有趣的CALL,mprotect包含它的頁面是可寫的,並在你自己的中介層的地址(如果需要的話可以調用__libc_open)修補它,然後mprotect它回來。任何未來的dlopen()現在都會通過您的插入器。

+0

第一個想法很有用,但是在'dlopen()'中切換到'PLT'調用導致了段錯誤,所以我們將考慮第二個選項... –