2017-10-29 7 views
0

私はシステムコールを傍受するためにptraceを使用しています。 execveへの16回の呼び出しを傍受していることを除いて、すべてうまく動作しているようです(プリシステムコール8回、システムコール8回)。Ptraceがexecveのための多くのトラップをキャッチ

私はそれがない例を見ましたが、フラグPTRACE_O_TRACESYSGOODを使用しようとしています。

その他answers to ptrace problemsは、プレ/ポスト+1信号が1つしか表示されないことを示していますが、PTRACE_O_TRACESYSGOODは使用していません。

Intercepted rt_sigprocmask[14] 
Syscall returned with value 0 
Intercepted execve[59] 
Syscall returned with value -2 
Intercepted execve[59] 
Syscall returned with value -2 
Intercepted execve[59] 
Syscall returned with value -2 
Intercepted execve[59] 
Syscall returned with value -2 
Intercepted execve[59] 
Syscall returned with value -2 
Intercepted execve[59] 
Syscall returned with value -2 
Intercepted execve[59] 
Syscall returned with value -2 
Intercepted execve[59] 
Syscall returned with value 0 
Tracer: Received signal: 5 
Intercepted brk[12] 
... 

出力の残りの部分は何strace出力と一致します。

私の出力は次のようになります。

すべての「インターセプトされた」および「返されるSyscall」は、waitid()コールに対応します。私はexecve、またはPTRACE_O_TRACESYSGOODをmisunderstingよ恐れる

#include <sys/types.h> 
#include <stdint.h> 
#include <sys/types.h> 
#include <sys/user.h> 
#include <sys/vfs.h> 
#include <sys/ptrace.h> 
#include <sys/reg.h>  /* For constants ORIG_EAX, etc */ 
#include <string.h> 
#include <sys/wait.h> 
#include <sys/syscall.h> /* For SYS_write, etc */ 
#include <unistd.h> 
#include <stdio.h> 

int main(){ 
    pid_t pid = fork(); 

    // Child. 
    if(pid == 0){ 
    ptrace(PTRACE_TRACEME, 0, NULL, NULL); 

    // Wait for parent to be ready. 
    raise(SIGSTOP); 
    execlp("pwd", "pwd", NULL); 
    return 0; 
    } 
    // Tracer. 
    else{ 
    struct user_regs_struct regs; 
    bool isPre = true; 
    int status; 
    // Wait for child to stop itself. 
    waitpid(pid, &status, 0); 
    ptrace(PTRACE_SETOPTIONS, pid, NULL, PTRACE_O_TRACESYSGOOD); 

    while(true){ 
     ptrace(PTRACE_SYSCALL, pid, 0, 0); 
     pid = waitpid(pid, &status, 0); 

     // Check if tracee has exited. 
     if (WIFEXITED(status)){ 
    return 0; 
     } 

     // This is a stop caused by a system call exit-pre/exit-post. 
     if(WIFSTOPPED(status) && WSTOPSIG(status) == (SIGTRAP |0x80)){ 
     ptrace(PTRACE_GETREGS, pid, NULL, &regs); 

     if(isPre){ 
      printf("Intercepted syscall: %llu\n", regs.orig_rax); 
      isPre = ! isPre; 
     }else{ 
      printf("Done with system call!\n"); 
      isPre = ! isPre; 
     } 
     }else{ 
     printf("Tracer: Received signal: %d\n", WSTOPSIG(status)); 
     } 
    } 
    } 

    return 0; 
} 

:これを再現するミニマリストのコード例。 私はLubuntu 16.04でカーネルバージョン4.10.0-37-genericを使っています。

編集:システムコールの戻り値が修正されました。

答えて

0

何も間違っていません。 execlpを1回呼び出すと、通常はexecveが複数回呼び出されます(最後の呼び出しを除く)。エラーコードとしてENOENTが返されます。

execlpおよびexecvpは、UnixおよびLinuxマニュアルのセクション2(システムコール)によく記載されていますが、それらはユーザランド機能として実装されています。彼らは$PATHを見て、それぞれの$PATHコンポーネントと実行可能ファイル名の連結で、execveが成功するか、すべてが失敗するまで、execveを呼び出します。

if (strchr(file, '/')) 
    return execve(file, argv, envp); 

if (!path) path = "/usr/local/bin:/bin:/usr/bin"; 
... 
for(p=path; ; p=z) { 
    char b[l+k+1]; 
    z = strchr(p, ':'); 
    if (!z) z = p+strlen(p); 
    if (z-p >= l) { 
     if (!*z++) break; 
     continue; 
    } 
    memcpy(b, p, z-p); 
    b[z-p] = '/'; 
    memcpy(b+(z-p)+(z>p), file, k+1); 
    execve(b, argv, envp); 
    if (errno == EACCES) seen_eacces = 1; 
    else if (errno != ENOENT) return -1; 
    if (!*z++) break; 
} 
if (seen_eacces) errno = EACCES; 
return -1; 
+0

パーフェクトこれは私が探していただけのものです:ここでは

は何が起こっているかを示しmuslからのソースの一部です! 'strace'のようなツールはexecveへの一回の呼び出ししか表示しないので、私はエラーがあると思っていました。 – gatoWololo

関連する問題