2016-06-19 17 views
1

LD_PRELOADを使用してexecve()システムコールをオーバーライドしたい場合があり、その理由を理解できないことがあります。execve()をLD_PRELOADでオーバーライドする場合のみ動作する

はexecveをオーバーライドし、この非常に簡単なコード()(あなたが好きならば、あなたはそれを試すことができますので、私は完全にそれをしておこう)考えてみましょう:

#define _GNU_SOURCE 
#include <unistd.h> 
#include <dlfcn.h> 
typedef ssize_t (*execve_func_t)(const char* filename, char* const argv[], char* const envp[]); 
static execve_func_t old_execve = NULL; 
int execve(const char* filename, char* const argv[], char* const envp[]) { 
    printf("Running hook\n"); 
    old_execve = dlsym(RTLD_NEXT, "execve"); 
    return old_execve(filename, argv, envp); 
} 

(とコンパイル:gcc -std=c99 -o exec.so -shared exec.c -Wall -Wfatal-errors -fPIC -g -ldl

と、この非常に簡単なテストプログラム:私は私のシェルでexport LD_PRELOAD=/path/to/exec.soを行う際

#define _GNU_SOURCE 
#include <unistd.h> 
#include <dlfcn.h> 
int main() { 
    char* args[] = {"ls", "/usr", NULL}; 
    char* envp[] = {"LD_PRELOAD=/path/to/exec.so", NULL}; 
    execve("/usr/bin/ls", args, envp); 
    return 0; 
} 

は今、私は私が最初にフックを実行するために実行するすべてのバイナリを期待します。それは私を混乱させる、すでに真実ではありません:編集:OK、この部分は今や明らかです。以下の問題はまだ解決されていません。ご覧のとおり

» strace -f -e trace=execve ./test 
execve("./test", ["./test"], [/* 58 vars */]) = 0 
Running hook 
execve("/usr/bin/ls", ["ls", "/usr"], [/* 1 var */]) = 0 
arm-none-eabi avr bin games include lib lib32 lib64 libexec local python sbin share src usr x86_64-pc-linux-gnu 
+++ exited with 0 +++ 

、フックだけではない最初のために、第二はexecveのために実行されます。

まだ不明: 何いくつかのケースでは、コードがないでも子プロセスのために、これまでにプリロードされていないということであっても、よりしかし私を混乱させる。例えば、Pythonのsubprocessモジュールでls /usrを実行している場合、この問題が発生した:

» strace -f -e trace=execve /usr/bin/python -c "import subprocess; subprocess.Popen(['ls', '/usr'])" 
execve("/usr/bin/python", ["/usr/bin/python", "-c", "import subprocess; subprocess.Po"...], [/* 58 vars */]) = 0 
strace: Process 8350 attached 
[pid 8350] execve("/usr/local/sbin/ls", ["ls", "/usr"], [/* 58 vars */]) = -1 ENOENT (No such file or directory) 
[pid 8350] execve("/usr/local/bin/ls", ["ls", "/usr"], [/* 58 vars */]) = -1 ENOENT (No such file or directory) 
[pid 8350] execve("/usr/bin/ls", ["ls", "/usr"], [/* 58 vars */]) = 0 
arm-none-eabi avr bin games include lib lib32 lib64 libexec local python sbin share src usr x86_64-pc-linux-gnu 
[pid 8350] +++ exited with 0 +++ 
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=8350, si_uid=1000, si_status=0, si_utime=0, si_stime=0} --- 
+++ exited with 0 +++ 

方法が可能ということでしょうか?呼び出し元プロセスとまったく同じ環境では全く同じシステムコールですが、それは異なるものです。私はこれについてのどんな指針についても満足しています。

+0

'。/ test'を実行するための' execve'呼び出しは、既存のシェルによって行われます。シェルはその時点で既にロードされており、LD_PRELOADはそれに影響しません。それは別の方法で見てください。 ''/* '/ test'が正しく実行される前に' 'char * envp [] = {" LD_PRELOAD =/path/to/exec.so "、NULL} – kaylum

+0

はい、そうです、それは私の愚かでした。これを指摘してくれてありがとう。しかし、2番目の問題は残念ながら残念です。 –

+1

Pythonは他のライブラリ関数(たとえば 'execvp')を呼び出し、ライブラリラッパーを経由せずに直接' execve'システムコールを実行する可能性があります。 – melpomene

答えて

0

解決策は実際には非常に簡単です。Pythonはexecveではなくexecvを呼び出します。印刷された標準出力はプロセスを呼び出すコードによって取り込まれ、端末には出力されません。そのため、実際には機能しないように見えます。

関連する問題