1

I am using ptrace to intercept system calls. Everything seems to be working fine except for the fact I'm intercepting 16 calls to execve (8 for pre system call, and 8 post system call).

I have seen working examples without it, but I'm trying to use the flag PTRACE_O_TRACESYSGOOD.

Other answers to ptrace problems indicate I should only see one pre/post + one signal, but they're not using PTRACE_O_TRACESYSGOOD.

My output looks like:

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]
...

The rest of the output matches what strace outputs.

Every "Intercepted" and "Syscall returned" corresponds to one waitid() call. A minimalist example code to reproduce this:

#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;
}

I fear I'm misundersting execve, or PTRACE_O_TRACESYSGOOD. I'm running this on Lubuntu 16.04 with kernel version 4.10.0-37-generic.

edit: Fixed return values for system calls.

gatoWololo
  • 296
  • 4
  • 10

1 Answers1

1

Nothing's wrong. One call to execlp will typically result in multiple calls to execve, each of them (except for the last) returning ENOENT as the error code.

Despite the fact that execlp and execvp are often documented in section 2 (system calls) of the Unix and Linux manuals, they're implemented as userland functions. They look through $PATH and call execve on the concatenation of each $PATH component and the executable name, until either one execve succeeds or they all fail.

Here's some of the source from musl that illustrates what's going on:

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;
Mark Plotnick
  • 9,598
  • 1
  • 24
  • 40
  • Perfect this is just what I was looking for! Since tools like `strace` only show a single call to execve I thought I had an error. – gatoWololo Oct 31 '17 at 16:43