調試系統問題並進行快速修訂
一種調試 glibc 函數的好方法是用您自己的版本覆蓋所關注的函數。在沒有 root 許可權和不必重新編譯 libc 源代碼的情況下就可以完成這個任務。想象一下編寫您自己的 open() 版本該有多激動啊!
如果您沒有應用程序的源代碼並且由於 C 的 GNU 庫(glibc)函數正將某些錯誤信息返回給該應用程序而使它失敗,那麼您該怎麼辦?因為 glibc 是開放源碼,所以您當然可以獲得其源代碼、對它進行更改、重新構建和安裝。然而,這不適合那些膽怯的人,因為雖然 API 有很好的文檔說明,但 GNU C 庫的內部組織卻沒有。查找正確的函數原型只是眾多挑戰中的第一個。它還是一個很大的包,所以第一次編譯時,它將花一些時間(glibc 2.2.2 有 8552 個文件和 1775440 行代碼,包括注釋)。
更好的方法
比重新構建 glibc 更好的方法是選擇性地覆蓋一個函數。許多現代的 Unix 都支持預裝入用戶定義庫這一概念。這些庫可以是完整的替代(即,glibc 的專用版本)也可以是子集 — 甚至是一個函數。首先,通過設置 LD_LIBRARY_PATH 來包含庫的專用版本,您可以使用 glibc 的專用版本。可通過使用 LD_PRELOAD 環境值來使用您編寫的庫例程的子集。LD_LIBRARY_PATH 和 LD_PRELOAD 都是由動態 ELF 鏈接器/裝入器控制的。它使用第一個匹配來滿足任何符號名。通過預裝入您自己的庫或函數版本,您“短路”了正常路徑,這樣就允許您覆蓋它。
這裡是一個示例 makefile,它覆蓋 glibc 函數 setresgid():
覆蓋 setresgid() 的 Makefile
#
# Makefile
#
all: libs setresgid-tester
#
# Make a shared Library
#
libs: libfuncs.c
gcc -shared -Wl,-soname,libfuncs.so.1 -o libfuncs.so.1.0 libfuncs.c
ln -s libfuncs.so.1.0 libfuncs.so.1
ln -s libfuncs.so.1 libfuncs.so
#
# Here is a program that calls setresgid() for testing
#
setresgid-tester: setresgid-tester.c
gcc -o setresgid-tester setresgid-tester.c
文件 libfuncs.c 包含我的 setresgid() 專用版本。實現它以支持與原始 setresgid() 相同的參數數目時要小心,並在其它方面完成與原始 setresgid() 相同的操作,盡管我的版本欺騙該應用程序並始終返回 0。
關注的第二個文件是 setresgid-tester.c。它通過調用 setresgid() 試驗新函數。
這是動態庫的源代碼:
替換庫
/*
Put all the functions you want to override here
*/
#include
#include
#include
int errno;
int
setresgid(rgid, egid, sgid)
gid_t rgid,egid,sgid;
{
errno=1;
printf("It me the shim, Hi there!\n");
return(0);
}
您還需要一個簡單方法來測試您的 setresgid() 專用版本。可以使用 strace 或 ltrace 來監視進程運行。這是普通測試示例的源代碼:
普通測試示例
/*
setresgid() system/library call tester
*/
#include
#include
main(){
setresgid(0,0,0);
}
現在,編譯該庫,設置 LD_PRELOAD shell 變量,然後運行測試應用程序。您可能還需要設置 LD_LIBRARY_PATH。
運行測試應用程序
eXPort LD_PRELOAD=libfuncs.so
export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH
./setresgid-tester
It's me the shim, Hi there!
還可以通過使用 ldd 列出動態鏈接庫來確認是否正在使用專用庫:
確認專用庫的使用
[jay@prion ld_preload]$ ldd setresgid-tester
libfuncs.so => libfuncs.so (0x40018000)
libc.so.6 => /lib/libc.so.6 (0x40022000)
/lib/ld-Linux.so.2 => /lib/ld-linux.so.2 (0x40000000)
結束語
編寫 GNU C 庫函數的專用版本是調試系統問題或進行快速修正的好方法。使用 LD_PRELOAD shell 變量,可以選擇性地用您自己的專用版本來覆蓋系統 C 庫函數。這種技術可用於 Linux 和 Solaris 環境。
關於作者
Jay Allen 是 IBM Linux for Service Providers Lab(LSPL)的程序員。可以通過
[email protected] 與 Jay 聯系。