title: Why does this sendmsg() call I injected via ptrace not work?
body: <p>I am trying to inject commands into a process I own - specifically, I'm currently trying to pass a file descriptor of the ptraced process to the ptracing process. I successfully created a unix domain socket and connected it (as far as I can see) like this:</p>
  
  <pre><code>#define stack_pointer(regs) regs.uregs[13]
  #define jumpback_pointer(regs) regs.uregs[14]
  #define ip(regs) regs.uregs[15]
  #define arg0(regs) regs.uregs[0]
  #define arg1(regs) regs.uregs[1]
  #define arg2(regs) regs.uregs[2]
  #define arg3(regs) regs.uregs[3]
  
  #define ROUND_SIZE_TO_WORD(n) ((((n) - 1) / 4 + 1) * 4)
  
    // create a socket on the other side
    jumpback_pointer(regs) = 0; // please crash after completion
    ip(regs) = libc_offset + 0x0000cfd4/*socket*/;
    arg0(regs) = PF_UNIX;
    arg1(regs) = SOCK_STREAM;
    arg2(regs) = 0;
    ptrace(PTRACE_SETREGS, pid, NULL, &amp;regs);
    assert(ptrace(PTRACE_CONT, pid, NULL, 0) == 0);
    int waitpid_result;
    assert(waitpid(pid, &amp;waitpid_result, 0) == pid);
    assert(WIFSTOPPED(waitpid_result));
    printf("child was killed with signal %i, we expected it to be killed with SIGSEGV (%i)\n", WSTOPSIG(waitpid_result), SIGSEGV);
    struct pt_regs after_socket_regs;
    assert(ptrace(PTRACE_GETREGS, pid, NULL, &amp;after_socket_regs) == 0);
    int remote_socket_id = arg0(after_socket_regs);
    printf("remote socket created, id=%i\n", remote_socket_id);
  
    // create a socket on our side and bind it
    int attacker_unix_socket = socket(PF_UNIX, SOCK_STREAM, 0);
    printf("local socket created, id=%i\n", attacker_unix_socket);
    int sockaddr_un_size_r = ROUND_SIZE_TO_WORD(sizeof(struct sockaddr_un)); // round up to words
    if ((sockaddr_un_size_r / 4) * 4 != sockaddr_un_size_r) {
      puts("struct sockaddr_un not properly sized");
      exit(1);
    }
    struct sockaddr_un *sockaddr = malloc(sockaddr_un_size_r);
    sockaddr-&gt;sun_family = AF_UNIX;
    strcpy(sockaddr-&gt;sun_path, "/tmp/ownage");
    unlink(sockaddr-&gt;sun_path);
    assert(bind(attacker_unix_socket, (struct sockaddr *) sockaddr, sizeof(struct sockaddr_un)) == 0);
    assert(listen(attacker_unix_socket, 5) == 0);
  
    // connect the victim socket
    int child_pid;
    if ((child_pid = fork())) {
      // the parent process takes care of running commands on the victim
      // side - the child isn't allowed to do this
      regs = orig_regs;
      stack_pointer(regs) -= sockaddr_un_size_r; // prepare stack push
      masspoke(pid, sockaddr, stack_pointer(regs), sockaddr_un_size_r); // stack push
      jumpback_pointer(regs) = 0;
      ip(regs) = libc_offset + 0x0000d030/*connect*/;
      arg0(regs) /*sockfd*/ = remote_socket_id;
      arg1(regs) /*addr*/ = stack_pointer(regs);
      arg2(regs) /*addr_len*/ = sizeof(struct sockaddr_un);
      assert(ptrace(PTRACE_SETREGS, pid, NULL, &amp;regs) == 0);
      assert(ptrace(PTRACE_CONT, pid, NULL, 0) == 0);
      assert(waitpid(pid, NULL, 0) == pid);
      struct pt_regs after_connect_regs;
      assert(ptrace(PTRACE_GETREGS, pid, NULL, &amp;after_connect_regs) == 0);
      if (arg0(after_connect_regs)) {
        printf("remote socket connect() failed with return value %li\n", arg0(after_connect_regs));
        exit(1);
      }
      printf("remote socket connected\n");
  </code></pre>
  
  <p>However, actually sending a file descriptor with the following code, which is a modified form of <a href="http://fossies.org/unix/misc/lftp-4.3.7.tar.gz%3at/lftp-4.3.7/lib/passfd.c" rel="nofollow">this</a>, which works, fails:</p>
  
  <pre><code>  regs = orig_regs;
  
    int fd = 10;
    char byte = 0;
    struct iovec iov;
    struct msghdr msg;
    struct cmsghdr *cmsg;
    char buf[CMSG_SPACE (sizeof fd)];
  
    /* send at least one char */
    memset (&amp;msg, 0, sizeof msg);
    iov.iov_base = &amp;byte;
    iov.iov_len = 1;
    msg.msg_iov = &amp;iov;
    msg.msg_iovlen = 1;
    msg.msg_name = NULL;
    msg.msg_namelen = 0;
  
    msg.msg_control = buf;
    msg.msg_controllen = sizeof buf;
    cmsg = (struct cmsghdr *) buf;
    cmsg-&gt;cmsg_level = SOL_SOCKET;
    cmsg-&gt;cmsg_type = SCM_RIGHTS;
    cmsg-&gt;cmsg_len = CMSG_LEN (sizeof fd);
    /* Initialize the payload: */
    memcpy (CMSG_DATA (cmsg), &amp;fd, sizeof fd);
  
    // copy structs over
    long r_buf = stack_pointer(regs) -= ROUND_SIZE_TO_WORD(sizeof(buf));
    masspoke(pid, buf, r_buf, sizeof(buf));
    msg.msg_control = (char **) r_buf;
  
    long r_byte = stack_pointer(regs) -= ROUND_SIZE_TO_WORD(sizeof(byte));
    masspoke(pid, &amp;byte, r_byte, sizeof(byte));
    iov.iov_base = (char *) r_byte;
  
    long r_iov = stack_pointer(regs) -= ROUND_SIZE_TO_WORD(sizeof(iov));
    masspoke(pid, &amp;iov, r_iov, sizeof(iov));
    msg.msg_iov = (struct iovec *) r_iov;
  
    long r_msg = stack_pointer(regs) -= ROUND_SIZE_TO_WORD(sizeof(msg));
    masspoke(pid, &amp;msg, r_msg, sizeof(msg));
  
    // call it
    jumpback_pointer(regs) = 0;
    ip(regs) = libc_offset + 0x0000d188;
    arg0(regs) = remote_socket_id;
    arg1(regs) = r_msg;
    arg2(regs) = 0;
    ptrace(PTRACE_SETREGS, pid, NULL, &amp;regs);
    assert(ptrace(PTRACE_CONT, pid, NULL, 0) == 0);
    assert(waitpid(pid, NULL, 0) == pid);
    struct pt_regs after_sendmsg_regs;
    assert(ptrace(PTRACE_GETREGS, pid, NULL, &amp;after_sendmsg_regs) == 0);
  
    if (arg0(after_sendmsg_regs) != iov.iov_len) {
      printf("sendmsg() failed (returned %li)\n", arg0(after_sendmsg_regs));
      exit(1);
    }
    printf("successfully called sendmsg() on the other side!\n");
  </code></pre>
  
  <p><code>sendmsg()</code> always fails with <code>-1</code>. So, my question is, does anyone know why this doesn't work or is at least able to tell me how I could try to find the errno to get some clues about the error? I tried this to find the errno, but <code>PTRACE_PEEKDATA</code> always fails:</p>
  
  <pre><code>void print_error(int pid, struct pt_regs regs, unsigned int libc_offset) {
    // call __errno to get a pointer to the errno
    jumpback_pointer(regs) = 0; // crash afterwards
    ip(regs) = libc_offset + LIBC_ERRNO;
    ptrace(PTRACE_SETREGS, pid, NULL, &amp;regs);
    assert(ptrace(PTRACE_CONT, pid, NULL, 0) == 0);
    int waitpid_result;
    assert(waitpid(pid, &amp;waitpid_result, 0) == pid);
    struct pt_regs after___errno_regs;
    assert(ptrace(PTRACE_GETREGS, pid, NULL, &amp;after___errno_regs) == 0);
    long errno_fn_addr = arg0(after___errno_regs);
    long child_errno = ptrace(PTRACE_PEEKDATA, pid, errno_fn_addr, NULL);
    int peek_errno = errno;
    printf("ERROR IN PTRACED PROCESS: %s (errno@%lx=%li), peek errno: %s\n", strerror(child_errno), errno_fn_addr, child_errno, strerror(peek_errno));
  }
  </code></pre>