vstinner/python-ptrace

process.readBytes hits EOF on /proc/<pid>/mem

Closed this issue · 4 comments

Originally reported by: gfxmonk (Bitbucket: gfxmonk, GitHub: gfxmonk)


I'm ptracing a process, and using readCString to get the filename argument for certain file-related syscalls.

Under the hood, this uses process.readBytes. In my case (linux 3.15.4, fedora 20) HAS_PTRACE_IO is False, and HAS_PROC is True - so it's using the /proc//mem method to read bytes from the process.

I copied this function into my source so I could mess with it, and I've found that in some case (I can't figure out why or when), mem.read() returns the empty string (a.k.a EOF).

When this happens, the surrounding readCString function just keeps reading empty chunks until it thinks it's hit the max_size limit, at which point it returns an empty string and claims that truncated is true. Which is itself kind of weird, it might be better if readBytes just raised EOFError when mem.read(size) returns the empty string.

But the real confusion is why I'm getting EOF on /dev/pid/mem in the first place. If I change the code of process.readBytes to include the following retry code:

try:
    mem = self.read_mem_file
    mem.seek(address)
    rv = mem.read(size)

    if not rv:
        mem = self.read_mem_file = open(self.read_mem_file.name, 'rb', 0)
        mem.seek(address)
        rv = mem.read(size)
    return rv
[ ... ]

Then bizzarely, it works - that is, even though I've just got an EOF when reading byte XYZ of /dev/pid/mem, reopening that exact same file and seeking to the same location gives me some contents.

I poked around in lsof to check that /dev/pid/mem isn't changing inode between when it was first opened and when it gives an EOF, and it doesn't seem to be.

I also attached an strace to the python process that's running the ptrace code, and saw that it really does do a:

read(5, "", 256) = 0

(5 is the FD for the pid's memory file)

So it's not python returning preemptively with an EOF, it's the OS. I can't figure out why. I had never heard of /dev/pid/mem before, so perhaps you might know why it might behave trhis way?


Original comment by gfxmonk (Bitbucket: gfxmonk, GitHub: gfxmonk):


Sorry about that - I just double checked, and I don't remember how (or have any code which would) reproduce. Fingers crossed the code is fixed with your rewrite, thanks for your work!

Original comment by Victor Stinner (Bitbucket: haypo, GitHub: haypo):


No feedback from the original poster, I close the bug. Sorry :-(

Original comment by Victor Stinner (Bitbucket: haypo, GitHub: haypo):


How can I reproduce the issue? I rewrote readBytes() in python-ptrace 0.8 to better handle errors, you may retry with this version.

Original comment by gfxmonk (Bitbucket: gfxmonk, GitHub: gfxmonk):


Logging the preceeeding system calls, I notice that this bug happens after the process I'm tracing does:

execve
brk
mmap
access
open

open is the first one which tries to read the process memory. So perhaps the mem file is somehow different and needs to be reopened after an execve?