简体   繁体   中英

Why *ptraced* dup2 works different than directly called dup2?

I'm trying to redirect a tracee's stdout to a file.

For this I've:

  1. attached to tracee
  2. mmap'd some memory
  3. copied the filename to tracee's memory
  4. asked tracee to open the file

To reach these results I had to dig myself into this repository.

So far my results look good, I'm ptracing into a top command, and lsof can detect my effort (see last line):

COMMAND    PID USER   FD   TYPE DEVICE SIZE/OFF       NODE NAME
top     421762 root  cwd    DIR  179,2     4096      17528 /root
top     421762 root  rtd    DIR  179,2     4096          2 /
top     421762 root  txt    REG  179,2   124856      12493 /usr/bin/top
top     421762 root    0u   CHR  136,1      0t0          4 /dev/pts/1
top     421762 root    1u   CHR  136,1      0t0          4 /dev/pts/1
top     421762 root    2w   CHR    1,3      0t0          5 /dev/null
top     421762 root    3u   CHR  136,1      0t0          4 /dev/pts/1
top     421762 root    4r   REG   0,17        0 4026533347 /proc/stat
top     421762 root    5r   REG   0,17        0 4026533348 /proc/uptime
top     421762 root    6r   REG   0,17        0 4026533346 /proc/meminfo
top     421762 root    7r   REG   0,17        0 4026533345 /proc/loadavg
top     421762 root    8u  FIFO   0,28      0t0        827 /tmp/mystdout

And this is my command's output (just for completeness):

[+] Allocated scratch page: 7fbd357000
[+] Opened the new fd in the child: 8 (/tmp/mystdout)
[+] Saved fd 1 to -1 in the child
[+] Duplicated fd 8 to 1
[+] Freed scratch page: 7fbd357000

What I'm trying to do now is the final step, which is to dup2 the stdout of the tracee to the opened file_fd (8).

Feasibility

I wrote a very small program to test how dup2 works on the target platform (aarch64):

int i = 0;
while(1) {
    printf("helloworld %d\n", i++);
    sleep(1);
    
    if (i==5) {
        printf("Opening tmp file\n");
        int file_fd = open("/tmp/mystdout", O_RDWR | O_CREAT, 0666, 0, 0);
        printf("File opened=%d\n", file_fd);
        
        int err = dup2(file_fd, 1);
        printf("dup2 result=%d\n", err);
        
        close(file_fd);
    }
}

This test program verified that I can close the file_fd after the dup2 call and still the program will continue logging to this file by default. Even my "dup2 result=1" is printed into the file (and not onto stdout ).

Considering dup2 's return value of 1 matches with its expected behavior by its documentation:

On success, these system calls return the new file descriptor.

Trying to dup2 with ptrace

After verified dup2 is working if called directly, I'm calling dup2 now with ptrace in the tracee with arguments of file_fd (8) and orig_fd (1):

int err = do_syscall(child, dup2, file_fd, orig_fd, 0, 0, 0, 0);
debug("Duplicated fd %d to %d, return=%d", file_fd, orig_fd, err);

With this, the program's output changes to this:

[+] Allocated scratch page: 7fbd357000
[+] Opened the new fd in the child: 8 (/tmp/mystdout)
[+] Saved fd 1 to -1 in the child
[+] Duplicated fd 8 to 1, return=8 !!!
[+] Freed scratch page: 7fbd357000

As you can see, dup2 is executed successfully (positive return value), BUT it returned with 8 instead of 1 .

Again, I'm calling ptraced dup2 with this method:

int err = do_syscall(child, dup2, 8, 1, 0, 0, 0, 0);

I don't know how could I detail this method here as it's a bit too large, but for reference here is how I called openat which actually opened the desired file in tracee's process:

int file_fd = do_syscall(child, openat, AT_FDCWD, scratch_page, O_RDWR | O_CREAT, 0666, 0, 0);

(Note: scratch_page is a memory mapped in tracee's space, and "/tmp/mystdout" is copied into it before using this instruction above)

So the question is:

How can I debug the injected dup2? For example with strace ?

I wish to understand why it behaves different than when called directly from the small test application.

It turned out that on aarch64 for some reason, dup2 is not able to injected.

No matter what I've tried, it always returned with weird results.

However after I changed dup2 to dup3 everything magically started working.

I'm still wondering on why dup2 syscall can't work, but for now after days of digging and learning I'm happy with this result.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM