odin-lang / Odin

Odin Programming Language
https://odin-lang.org
BSD 3-Clause "New" or "Revised" License
6.93k stars 611 forks source link

`linux.ptrace(linux.PTRACE_CONT, ...)` returns `EIO` every time #4259

Closed eseft closed 1 month ago

eseft commented 1 month ago

Context

It looks like the ptrace syscall with request types ptrace_cont, ptrace_singlestep, ptrace_syscall, ptrace_sysemu and ptrace_sysemu_singlestep expecting to get Signal as a 4th parameter according to ptrace man page.

        Odin:    dev-2024-09:6ef779cd5
        OS:      Arch Linux, Linux 6.10.10-arch1-1
        CPU:     AMD Ryzen 5 5600G with Radeon Graphics         
        RAM:     31460 MiB
        Backend: LLVM 18.1.8

Expected Behavior

When tracer waits for tracee to stop and do ptrace(linux.PTRACE_CONT,...) no errors should occur.

Current Behavior

Whenever ptrace(linux.PTRACE_CONT,...) called it returns EIO error.

Failure Information (for bugs)

Steps to Reproduce

  1. Run following code snippet
    
    package main

import "core:fmt" import "core:os" import "core:sys/linux"

main :: proc() { pid, err := linux.fork() assert(err == nil)

if pid == 0 {
    err_ptrace := linux.ptrace(linux.PTRACE_TRACEME)
    assert(err_ptrace == nil)

    err_exec := os.execvp("/bin/ls", {})
    assert(err_exec == nil)

} else {
    status: u32
    rusage: linux.RUsage
    linux.wait4(pid, &status, {}, &rusage)
    assert(linux.WIFSTOPPED(status))

    err := linux.ptrace(linux.PTRACE_CONT, pid, nil)
    fmt.println("ptrace_cont: ", err)
}

}

2. You will get:

ptrace_cont: EIO ....

`strace` output for the `ptrace` call above:

ptrace(PTRACE_CONT, 13337, NULL, 459103680) = -1 EIO (Input/output error)


Last parameter is different every run of the program.
eseft commented 1 month ago

Also, there is something about ptrace_peek request type I found in man page. It's expecting fourth parameter to be something like ^uint to fill data from specified address

   C library/kernel differences
       At the system call level, the PTRACE_PEEKTEXT, PTRACE_PEEKDATA,
       and PTRACE_PEEKUSER operations have a different API: they store
       the result at the address specified by the data parameter, and
       the return value is the error flag.  The glibc wrapper function
       provides the API given in DESCRIPTION above, with the result
       being returned via the function return value.
flysand7 commented 1 month ago

Not sure how this went over my mind, turns out the signal was passed in the addr parameter, and the data parameter was ignored. According to the documentation data contains the signal and addr is ignored.

I'll submit a PR that fixes this issue shortly.

flysand7 commented 1 month ago

If the signal is not a valid signal number, the function would return EIO (https://elixir.bootlin.com/linux/v6.11/source/kernel/ptrace.c#L827), so I guess you really had to be lucky for some uninitialized data to have been a valid signal number haha