1

I am trying to do some very basic stuff using ptrace but I am a getting a really odd behavior.

unsigned long start=strtoul(start_text,NULL,16);

long start_data; 
 if ((start_data = ptrace(PTRACE_PEEKTEXT,child_pid,(void*)start,NULL))<0){
      free_memory(vars,registers,size);
      exit(1);
}
    

start_text is a string to a valid place in another program, the value of start is correct, the value of child_pid is also correct.

For some reason, for some values of start the call works properly, but for some it fails.

I tried to understand what causes this so I wrote this:

ptrace(PTRACE_PEEKTEXT,child_pid,(void*)start,NULL);
printf("%d",errno);

but errno is 0 every time.

Can anyone please explain what causes the problem?

EL_9
  • 404
  • 2
  • 10
  • 1
    ptrace will always set errno on an error -- but `PTRACE_PEEKTEXT` may return a negative value (if the value read is negative) without an error. To detect errors with PEEKTEXT, you need to set `errno = 0` before the ptrace call and check it afterwards. – Chris Dodd Jun 28 '20 at 22:37

1 Answers1

1

From Linux's ptrace man page:

Since the value returned by a successful PTRACE_PEEK* request may be -1, the caller must clear errno before the call, and then check it afterward to determine whether or not an error occurred.

That is, it could be that the value you're reading just happens to be -1, or in your case, some other negative number (i.e. a 64-bit value with the high bit set).

So unlike most other system call functions, you can't check for success by testing whether the returned value is negative. You should instead do

errno = 0;
start_data = ptrace(PTRACE_PEEKTEXT,child_pid,(void*)start,NULL));
if (errno != 0) {
    // handle error
}

Note the importance of setting errno = 0 first. As with other system calls, if ptrace succeeds it may leave the value of errno unchanged. So unless you clear errno first, you won't be able to tell whether a nonzero value afterward indicates that ptrace failed, or whether ptrace succeeded and the value was left over from some previous call that failed.

(My version of man page suggests that the ptrace library wrapper may actually set errno to zero upon success, but doesn't make it clear exactly when, so it is best not to rely on this behavior.)

Nate Eldredge
  • 48,811
  • 6
  • 54
  • 82
  • 1
    Nitpick: the system calls themselves have no concept of `errno`, and the `ptrace` system call reports errors like any other. This question is purely a consequence of the libc wrappers. – Joseph Sible-Reinstate Monica Jun 29 '20 at 00:02