
我們有兩個 RHEL 6 系統,運行相同版本的內核和 glibc (glibc–2.12–1.90.el6_3.6)。根據 POSIX 標準和 Linux 手冊頁,如果核心確定一個可執行檔案不是可執行格式(例如 ELF)且沒有 shebang ( #!
) 行,則函數execl
, execlp
, execle
, execv
, execvp
, 和execvpe
(但是not execve
) 將嘗試使用POSIX shell 執行該檔案,在Linux 上是/bin/sh
.
但是,在其中一個系統上,執行第一行:
使用該函數的 shell 腳本execvp
會失敗,而在另一台電腦上/bin/sh
,則按預期使用 執行腳本。具體來說,我們正在使用這些測試程式;/tmp/test_script
可執行:
xc:
#include <stdio.h> #include <unistd.h> #include <stdlib.h> 外部字元**環境; int 主函數 () { char *argv[] = { "/tmp/test_script", NULL }; char *程式名 = argv[0]; if (execvp(程式名稱, argv) == -1) { 錯誤(“execvp”); 返回-1; } }
/tmp/測試腳本:
: echo“測試腳本已呼叫” 出口0
我們在來源 RPM 中搜尋了已安裝的 glibc 版本,它確實實作了所需的行為(execvp 是 execvpe 的簡單包裝器):
posix/execvpe.c:
if (strchr(檔案, '/') != NULL) { /* 當包含斜線時不進行搜尋。 */ __execve(檔案、argv、envp); if (errno == ENOEXEC) { /* 計算參數。 */ int argc = 0; while (argv[argc++]) ; size_t len = (argc + 1) * sizeof(char *); 字元 **script_argv; 無效 *ptr = NULL; 如果 (__libc_use_alloca(len)) script_argv = alloca(len); 別的 script_argv = ptr = malloc(len); 如果(script_argv!= NULL) { script_argv(檔案、argv、argc、script_argv); __execve(script_argv[0], script_argv, envp); 自由(ptr); } } } 別的 ︙
這裡,scripts_argv
是一個簡單的函數,它添加/bin/sh
到參數列表中,並且與透過 glibc 暴露給用戶空間的函數__execve
相同。execve
還有其他人在 Linux 上遇到過這個問題嗎?在我嘗試過的所有其他系統上,該行為都是正確的。
答案1
好吧,我發現了問題所在。編譯x.c
可執行檔後,我運行ldd
它,發現有一個liboit.so
動態連結到可執行檔的庫。該庫是由ObserveIT Unix 審計員,它攔截登入使用者的所有活動,包括系統呼叫。但是,我認為僅攔截系統呼叫不會導致觀察到的行為,因為重新執行/bin/sh
是在 glibc 內部完成的。也許 ObserveIT 也模擬 POSIX 函數,但在這種情況下顯然不符合要求。