Giter Site home page Giter Site logo

vstinner / python-ptrace Goto Github PK

View Code? Open in Web Editor NEW
183.0 16.0 49.0 902 KB

python-ptrace is a Python binding of ptrace library.

Home Page: http://python-ptrace.readthedocs.io/

License: GNU General Public License v2.0

Python 98.08% Makefile 0.23% C 1.68%

python-ptrace's People

Contributors

andreas-schwab avatar anthonygelibert avatar catb0t avatar duanev avatar fab1ano avatar hamarituc avatar jopereira avatar jwilk avatar krenair avatar mewmew avatar michawe avatar p-e-w avatar skitt avatar smattr avatar spoutn1k avatar tavy14t avatar vstinner avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

python-ptrace's Issues

license clarifications

Hi! 👋

On Arch Linux we have recently switched to becoming more specific about the licenses upstreams are using. For this we rely on SPDX license identifiers.
https://rfc.archlinux.page/0016-spdx-license-identifiers/

This project carries a GPL-2.0 license file but does not state whether this is GPL-2.0-only or GPL-2.0-or-later.
Usually, if there are no additional infos one would err on the side of caution and default to GPL-2.0-only, but maybe there is some discussion or piece of information I am missing.

I'd be happy about further input from your side on this topic! :)

cc @anthraxx (package maintainer)

How to properly detach?

I can't figure out how to detach from a process, preventing me from later re-attaching:

Python 2.7.12 (default, Nov 19 2016, 06:48:10) 
[GCC 5.4.0 20160609] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import ptrace.debugger
>>> debugger = ptrace.debugger.PtraceDebugger()
>>> process = debugger.addProcess(485, False)
>>> process.readBytes(0x00673364, 4)
';\xaa4\x1d'
>>> debugger.deleteProcess(process)
>>> debugger.quit()
>>> process = debugger.addProcess(485, False)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python2.7/dist-packages/ptrace/debugger/debugger.py", line 74, in addProcess
    process = PtraceProcess(self, pid, is_attached, parent=parent)
  File "/usr/lib/python2.7/dist-packages/ptrace/debugger/process.py", line 167, in __init__
    self.attach()
  File "/usr/lib/python2.7/dist-packages/ptrace/debugger/process.py", line 184, in attach
    ptrace_attach(self.pid)
  File "/usr/lib/python2.7/dist-packages/ptrace/binding/func.py", line 157, in ptrace_attach
    ptrace(PTRACE_ATTACH, pid)
  File "/usr/lib/python2.7/dist-packages/ptrace/binding/func.py", line 150, in ptrace
    raise PtraceError(message, errno=errno, pid=pid)
ptrace.error.PtraceError: ptrace(cmd=16, pid=485, 0, 0) error #1: Operation not permitted

strace.py -f breaks with system calls's siginal

when I use "strace.py -f " to tracing ansible apt module, it throw me a bug that system call breaks. I used gdb to debug but couldn't attach on the proess. Using ps to check process I found that python-ptrace was still monitoring the ansible module, So I killed the forks, and the ptrace received an interrupt siginal.
I am curious about why adding the argument "-f " may lead the python-ptrace program getting stuck?

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

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?


ptrace not works on linux 3.x kernels.

Originally reported by: Felipe Prenholato (Bitbucket: chronossc, GitHub: chronossc)


I have a install of pythonbrew with Python 2.6.8 (without SSLv2 support) for running old applications.

This install runs Django 1.2.1.

When trying to run Django 1.2.1 server or shell, I ends with a error "UNKNOW OS!".

I checked and that happens because ptrace.os_tools don't recognize linux3 platform as Linux.

To make it work I changed code in following way:

#!diff
--- os_tools.py_original        2012-08-04 01:29:03.985275595 -0300
+++ os_tools.py 2012-08-04 01:28:55.305275224 -0300
@@ -17,7 +17,7 @@
 RUNNING_PYTHON3 = version_info[0] == 3
 RUNNING_PYPY = ("pypy" in version.lower())
 RUNNING_WINDOWS = (platform == 'win32')
-RUNNING_LINUX = (platform == 'linux2')
+RUNNING_LINUX = (platform in ('linux2', 'linux3'))
 RUNNING_FREEBSD = (platform.startswith('freebsd')
                    or platform.startswith('gnukfreebsd'))
 RUNNING_OPENBSD = platform.startswith('openbsd')

Missing prototypes

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


Hi

Many syscalls (rt_sigreturn, pread64, pwrite64, mremap) lack of their prototype in the SYSCALL_PROTOTYPES list.

Is there any reason for this lacking?

If not, can I provide you a whole list of prototypes to add in prototypes.py?
Any hints to properly populate it?


Cannot be attached to an existing process

Hi, I'm trying to track the process containerd, but I always get no output.

I used the following command, which did not produce any output:

sudo python3 strace.py -f -p 1363

I also tried the example in the documentation and rewrote it to:

import signal

import ptrace.debugger


def debugger_example(pid):
    debugger = ptrace.debugger.PtraceDebugger()

    print("Attach the running process %s" % pid)
    process = debugger.addProcess(pid, False)
    # process is a PtraceProcess instance
    print("IP before: %#x" % process.getInstrPointer())

    print("Execute a single step")
    process.singleStep()
    # singleStep() gives back control to the process. We have to wait
    # until the process is trapped again to retrieve the control on the
    # process.
    process.waitSignals(signal.SIGTRAP)
    print("IP after: %#x" % process.getInstrPointer())

    process.detach()
    debugger.quit()


def main():
    debugger_example(1363)


if __name__ == "__main__":
    main()

The error obtained is the following,

/home/zzc/Desktop/zzc/python3.6_sudo.sh /home/zzc/Desktop/zzc/python-ptrace/zzc-test.py
Attach the running process 1363
Traceback (most recent call last):
  File "/home/zzc/Desktop/zzc/python-ptrace/zzc-test.py", line 30, in <module>
    main()
  File "/home/zzc/Desktop/zzc/python-ptrace/zzc-test.py", line 26, in main
    debugger_example(1363)
  File "/home/zzc/Desktop/zzc/python-ptrace/zzc-test.py", line 10, in debugger_example
    process = debugger.addProcess(pid, False)
  File "/home/zzc/Desktop/zzc/python-ptrace/ptrace/debugger/debugger.py", line 83, in addProcess
    parent=parent, is_thread=is_thread)
  File "/home/zzc/Desktop/zzc/python-ptrace/ptrace/debugger/process.py", line 172, in __init__
    self.attach()
  File "/home/zzc/Desktop/zzc/python-ptrace/ptrace/debugger/process.py", line 189, in attach
    ptrace_attach(self.pid)
  File "/home/zzc/Desktop/zzc/python-ptrace/ptrace/binding/func.py", line 177, in ptrace_attach
    ptrace(PTRACE_ATTACH, pid)
  File "/home/zzc/Desktop/zzc/python-ptrace/ptrace/binding/func.py", line 168, in ptrace
    raise PtraceError(message, errno=errno, pid=pid)
ptrace.error.PtraceError: ptrace(cmd=16, pid=1363, 0, 0) error #1: Operation not permitted

Process finished with exit code 1

I want to know what I should do.

readBytes() failed on forked process

Originally reported by: Peter Saveliev (Bitbucket: svinota, GitHub: svinota)


readBytes() returns an empty string, when operates on a forked process.

How reproducible: always

How to reproduce:

add readBytes() to strace.py and run a bash script

$ diff /usr/bin/strace.py ./strace.py 
187c187,198
<             self.displaySyscall(syscall)

---
>             if syscall.name in ('recvmsg', 'sendmsg'):
>                 # get msghdr
>                 addr = syscall.arguments[1].value
>                 # read at some bytes
>                 # actually, we should read struct msghdr, but
>                 # for the testcase it is enough to read at least one
>                 length = 1
>                 data = process.readBytes(addr, length)
>                 if not data:
>                     print "read failed -- starting debugger"
>                     import pdb
>                     pdb.set_trace()
$ cat test.sh 
#!/bin/bash

ip ad
$ python ./strace.py -f ./test.sh
execve(/home/peet/Projects/pyroute2/test.sh, ['/home/peet/Projects/pyroute2/test.sh'], [/* 40 vars */]) = 5669
*** New process 5670 ***
*** New process 5671 ***
[5671] exit_group(0)
*** Process 5671 exited normally ***
------------------------------------------------------------
PID: 5670
Signal: SIGCHLD
Child process 5671 exited normally
Signal sent by user 1000
------------------------------------------------------------
[5670] exit_group(0)
*** Process 5670 exited normally ***
------------------------------------------------------------
PID: 5669
Signal: SIGCHLD
Child process 5670 exited normally
Signal sent by user 1000
------------------------------------------------------------
*** New process 5672 ***
*** New process 5673 ***
[5673] exit_group(0)
*** Process 5673 exited normally ***
------------------------------------------------------------
PID: 5672
Signal: SIGCHLD
Child process 5673 exited normally
Signal sent by user 1000
------------------------------------------------------------
[5672] exit_group(0)
*** Process 5672 exited normally ***
------------------------------------------------------------
PID: 5669
Signal: SIGCHLD
Child process 5672 exited normally
Signal sent by user 1000
------------------------------------------------------------
*** New process 5674 ***
*** New process 5675 ***
[5675] exit_group(0)
*** Process 5675 exited normally ***
------------------------------------------------------------
PID: 5674
Signal: SIGCHLD
Child process 5675 exited normally
Signal sent by user 1000
------------------------------------------------------------
[5674] exit_group(0)
*** Process 5674 exited normally ***
------------------------------------------------------------
PID: 5669
Signal: SIGCHLD
Child process 5674 exited normally
Signal sent by user 1000
------------------------------------------------------------
*** New process 5676 ***
*** New process 5677 ***
[5677] exit_group(1)
*** Process 5677 exited with code 1 ***
------------------------------------------------------------
PID: 5676
Signal: SIGCHLD
Child process 5677 killed by signal SIGHUP
Signal sent by user 1000
------------------------------------------------------------
[5676] exit_group(0)
*** Process 5676 exited normally ***
------------------------------------------------------------
PID: 5669
Signal: SIGCHLD
Child process 5676 exited normally
Signal sent by user 1000
------------------------------------------------------------
*** New process 5678 ***
read failed -- starting debugger
> /home/peet/Projects/pyroute2/strace.py(201)syscall()
-> process.syscall()
(Pdb) addr
140736183873504L
(Pdb) process.readBytes(addr, 1)
''
(Pdb) 

SELinux state: permissive

$ getenforce 
Permissive

This issue is really a blocker, since only single processes can be straced to get syscall data.


Can't ptrace child started with subprocess.Popen from other child

I apologize if this is an ignorant question. I have a parent process which spawns two children and I need one of the children (created via multiprocessing) to be able to ptrace the other (started via subprocess.Popen) but I am recieving the permission error: ptrace.error.PtraceError: ptrace(cmd=16, pid=15151, 0, 0) error #1: Operation not permitted

Here is sample code that demonstrates what I am trying to do and the error I am encountering:

import multiprocessing
import subprocess
import time

import ptrace.debugger


def ptrace_test(pid):
    debugger = ptrace.debugger.PtraceDebugger()
    process = debugger.addProcess(pid, False)
    # Other stuff


child = subprocess.Popen("/usr/bin/ls")
proc = multiprocessing.Process(target=ptrace_test, args=(child.pid,))
proc.start()
proc.join()

strace.py terminates with KeyError when tracing openssh server

Originally reported by: Pavel Šimerda (Bitbucket: pavlix, GitHub: pavlix)


For a network application testing project, I need to ptrace both client and server processes but tracing the SSH server apparently fails. So I also tried with strace.py and it quits with a traceback.

Reproducer:

Run the two comments in two terminal emulators alpha and beta. The behavior seems to be the same whether you make sure the SSH authentication succeeds or no.

alpha# ./strace.py -f -o trace.python-ptrace -- which sshd -D

beta$ ssh localhost true

Expected result:

With -D option, SSH server should run until you kill it and accept any incoming connections.

Actual result:

The first connection results in crashing the server with a traceback.


Ptrace Segmentation Fault signal handler can't handle RETurns to invalid addresses

Trying to _analyze() or display() a ProcessSignal of type SIGSEGV raised by a "RET" condition currently raises an Exception, as the current instruction handler has no detection for the RET opcode.

This segfault signal can be raised when an invalid address is at the top of the stack, then a RET is executed looking to pop the value into RIP. This is a valuable use-case for detecting buffer overflows / attempted RET2Libc attacks in binaries without stack protection canaries

Problem tracing clone/fork

Originally reported by: Luca Clementi (Bitbucket: lclementi, GitHub: lclementi)


If you apply the patch below to your strace.py it will block indefinitely.

I think it is a problem connected with the (clone/fork) where the two process get stuck waiting for each other.

The problem sees in ptrace/debugger/debugger.py at the function:
def addProcess(self, pid, is_attached, parent=None):

Do you have any suggestion on where to look?

Luca

#!diff

--- strace.py   2013-02-28 18:59:07.268588674 -0800
+++ strace.py.modified  2013-02-28 18:59:01.356588768 -0800
@@ -12,6 +12,7 @@
 from ptrace.compatibility import any
 from ptrace.error import PTRACE_ERRORS, writeError
 from ptrace.ctypes_tools import formatAddress
+import ptrace
 import re

 class SyscallTracer(Application):
@@ -73,6 +74,9 @@
         self.createLogOptions(parser)

         self.options, self.program = parser.parse_args()
+        self.program = ["bash","-c","/usr/bin/find /tmp &> /dev/null "]
+        self.program[0] = ptrace.tools.locateProgram(self.program[0])
+

         if self.options.list_syscalls:
             syscalls = SYSCALL_NAMES.items()

fork trace failed on waitpid()

Originally reported by: Peter Saveliev (Bitbucket: svinota, GitHub: svinota)


From time to time, using strace.py -f cmd, I get somethig like that:

[2506] rt_sigprocmask(SIG_SETMASK, <sigset=()>, NULL, 8) = 0
[2511] rt_sigaction(SIGTSTP, 0x00007fffdcd78370, 0x00007fffdcd78410, 8) = 0
[2506] rt_sigaction(SIGCHLD, 0x00007fffdcd784d0, 0x00007fffdcd78570, 8) = 0
[2511] rt_sigaction(SIGTTIN, 0x00007fffdcd78370, 0x00007fffdcd78410, 8) = 0
[2506] close(4)                                 = 0
[2511] rt_sigaction(SIGTTOU, 0x00007fffdcd78380, 0x00007fffdcd78420, 8) = 0
[2511] rt_sigaction(SIGINT, 0x00007fffdcd784a0, 0x00007fffdcd78540, 8) = 0
[2511] rt_sigaction(SIGQUIT, 0x00007fffdcd784a0, 0x00007fffdcd78540, 8) = 0
[2511] rt_sigaction(SIGCHLD, 0x00007fffdcd784a0, 0x00007fffdcd78540, 8) = 0
[2511] rt_sigaction(SIGCHLD, 0x00007fffdcd784d0, 0x00007fffdcd78570, 8) = 0
[2511] rt_sigaction(SIGINT, 0x00007fffdcd784d0, 0x00007fffdcd78570, 8) = 0
[2511] dup2(4, 1)                               = 1
[2511] close(4)                                 = 0
[2511] close(3)                                 = 0
[2511] rt_sigprocmask(SIG_BLOCK, NULL, <sigset=()>, 8) = 0
[2511] rt_sigprocmask(SIG_BLOCK, NULL, <sigset=()>, 8) = 0
[2511] rt_sigprocmask(SIG_BLOCK, NULL, <sigset=()>, 8) = 0
[2511] rt_sigprocmask(SIG_BLOCK, <sigset=(SIGINT, SIGCHLD)>, <sigset=()>, 8) = 0
waitpid() warning: Unknown PID 2512

At this point strace hangs until Ctrl-C.

Traced file — a testcase for tracing forked processes:

#!/bin/bash

ip ad

How reproducible: possibility ~0.3

How to reproduce:

  1. use simple bash script from above
  2. run strace:
$ strace.py -f ./test.sh

Possibly, some race condition.


Feature request: support x86 arch on x86_64 Linux

Originally reported by: Anonymous


When I try to run strace.py with a 32bits program in Ubuntu Linux x64 I get the following message:

Format argument filename of function lstat() value error: [ProcessError] readBytes(0x0000000000000003, 256) error: [Errno 5] Input/output error
Traceback (most recent call last):
File "/the/path/python-ptrace/ptrace/func_arg.py", line 31, in getText
text = self.createText()
File "/the/path/python-ptrace/ptrace/syscall/syscall_argument.py", line 106, in createText
return self.readCString(value)
File "/the/path/python-ptrace/ptrace/syscall/syscall_argument.py", line 183, in readCString
char, truncated = self.function.process.readCString(address, max_size)
File "/the/path/python-ptrace/ptrace/debugger/process.py", line 637, in readCString
data = self.readBytes(address, chunk_length)
File "/the/path/python-ptrace/ptrace/debugger/process.py", line 566, in readBytes
formatAddress(address), size, err))
ProcessError: readBytes(0x0000000000000003, 256) error: [Errno 5] Input/output error

Any idea about what is wrong? I tried to look at the source but I'm a bit lost.


Not able to extract the return value

Originally reported by: 0x71 (Bitbucket: 0x71, GitHub: 0x71)


Hey,

I am trying to extract the return value of an interrupted syscall.
Having a look at ptrace / func_arg.py and func_call.py , it seems that self.resvalue is initialized but never updated or set while the result type, all arguments and the syscall itself can be extracted properly.

Is there a way to extract the return value?

Best Regards


Signals not correctly received

Originally reported by: Anonymous


Hi,

I'm writing a tool that needs to catch when a process segfaults. For this purpose I'm using a code that ends up doing this:

    signal = process.waitSignals(11)
    print signal

However, even when the signal 11 (SIGSEGV) is received an exception is raised. This in an example changing the simple_dbg.py example to instead of wait for an event wait for a signal with the code previously mentioned:

Traceback (most recent call last):
  File "examples/simple_dbg.py", line 65, in <module>
    main()
  File "examples/simple_dbg.py", line 61, in main
    playWithProcess(process)
  File "examples/simple_dbg.py", line 15, in playWithProcess
    signal = process.waitSignals(11)
  File "/usr/local/lib/python2.7/dist-packages/python_ptrace-0.8-py2.7.egg/ptrace/debugger/process.py", line 726, in waitSignals
    return self.debugger.waitSignals(*signals, **{'pid': self.pid})
  File "/usr/local/lib/python2.7/dist-packages/python_ptrace-0.8-py2.7.egg/ptrace/debugger/debugger.py", line 192, in waitSignals
    raise event
ptrace.debugger.process_event.ProcessExit: Process 3691 killed by signal SIGSEGV

Am I missing something or doing something wrong?


Is there a way to capture 'stderr' / 'stdout' from the ptraced program?

Let assume I have this code (it is incomplete):

pid = createChild(arguments, False, env)
dbg = PtraceDebugger()
process = dbg.addProcess(pid, is_attached)
process.cont()

There seems to be no way to handle the stderr and stdout, there are something called pass_fd in the createChild function, but there is no documentation (that I can find) how to do it, trying to use os.pipe() on it seems to not work os.read(..) seems to be blocked

Can you provide an example? or direct me in the right way?

Create a new release

Hi! 👋

We're currently about to upgrade to Python 3.12 on Arch Linux.
This project is one of the projects still using the imp module in the latest released version.

Would it be possible to create a new release for this project, so that we can use that instead of applying 80e0c97?
That'd be much appreciated! 🙇

cc @anthraxx (package maintainer)

strace error on 32bit arch

Originally reported by: Peter Saveliev (Bitbucket: svinota, GitHub: svinota)


Running the debugger on 32bit RHEL, I've got following error:

#!
$ strace.py ip link
execve(/sbin/ip, ['/sbin/ip', 'link'], [/* 40 vars */]) = 2970
brk(NULL)                                = 0x091ac000
mmap2(NULL, 4096, <PROT_READ|PROT_WRITE> (3), 34, -1, 0) = 0xb776d000
access('/etc/ld.so.preload', <R_OK> (4)) = -2 (No such file or directory)
open('/etc/ld.so.cache', O_RDONLY)       = 3
fstat64(3, 0xbfbd0198)                   = 0
mmap2(NULL, 14032, <PROT_READ> (1), 2, 3, 0) = 0xb7769000
close(3)                                 = 0
open('/lib/libresolv.so.2', O_RDONLY)    = 3
read(3, 0xbfbd02b8, 512)                 = 512 (0x00000200)
fstat64(3, 0xbfbd01e0)                   = 0
mmap2(NULL, 104520, <PROT_READ|PROT_EXEC> (5), 2050, 3, 0) = 0x00ec2000
mprotect(0x00ed7000, 4096, 0)            = 0
mmap2(0x00ed8000, 8192, <PROT_READ|PROT_WRITE> (3), 2066, 3, 21) = 0x00ed8000
mmap2(0x00eda000, 6216, <PROT_READ|PROT_WRITE> (3), 50, -1, 0) = 0x00eda000
close(3)                                 = 0
open('/lib/libdl.so.2', O_RDONLY)        = 3
read(3, 0xbfbd029c, 512)                 = 512 (0x00000200)
fstat64(3, 0xbfbd01c4)                   = 0
mmap2(NULL, 16500, <PROT_READ|PROT_EXEC> (5), 2050, 3, 0) = 0x00d28000
mmap2(0x00d2b000, 8192, <PROT_READ|PROT_WRITE> (3), 2066, 3, 2) = 0x00d2b000
close(3)                                 = 0
open('/lib/libc.so.6', O_RDONLY)         = 3
read(3, 0xbfbd0280, 512)                 = 512 (0x00000200)
fstat64(3, 0xbfbd01a8)                   = 0
mmap2(NULL, 1665416, <PROT_READ|PROT_EXEC> (5), 2050, 3, 0) = 0x00abd000
mprotect(0x00c4d000, 4096, 0)            = 0
mmap2(0x00c4e000, 12288, <PROT_READ|PROT_WRITE> (3), 2066, 3, 400) = 0x00c4e000
mmap2(0x00c51000, 10632, <PROT_READ|PROT_WRITE> (3), 50, -1, 0) = 0x00c51000
close(3)                                 = 0
mmap2(NULL, 4096, <PROT_READ|PROT_WRITE> (3), 34, -1, 0) = 0xb7768000
mmap2(NULL, 4096, <PROT_READ|PROT_WRITE> (3), 34, -1, 0) = 0xb7767000
set_thread_area(<user_desc entry_number=6L, base_addr=3077999408L, limit=1048575L, _bits_='Q'>) = 0
mprotect(0x00c4e000, 8192, 1)            = 0
mprotect(0x00d2b000, 4096, 1)            = 0
mprotect(0x00ed8000, 4096, 1)            = 0
mprotect(0x00594000, 4096, 1)            = 0
munmap(0xb7769000, 14032)                = 0
Debugger error: [KeyError] 's'
Traceback (most recent call last):
  File "/usr/lib/python2.6/site-packages/python_ptrace-0.6.4-py2.6.egg/EGG-INFO/scripts/strace.py", line 247, in _main
    self.runDebugger()
  File "/usr/lib/python2.6/site-packages/python_ptrace-0.6.4-py2.6.egg/EGG-INFO/scripts/strace.py", line 235, in runDebugger
    self.syscallTrace(process)
  File "/usr/lib/python2.6/site-packages/python_ptrace-0.6.4-py2.6.egg/EGG-INFO/scripts/strace.py", line 181, in syscallTrace
    self.syscall(process)
  File "/usr/lib/python2.6/site-packages/python_ptrace-0.6.4-py2.6.egg/EGG-INFO/scripts/strace.py", line 185, in syscall
    syscall = state.event(self.syscall_options)
  File "/usr/lib/python2.6/site-packages/python_ptrace-0.6.4-py2.6.egg/ptrace/debugger/syscall_state.py", line 15, in event
    return self.enter(options)
  File "/usr/lib/python2.6/site-packages/python_ptrace-0.6.4-py2.6.egg/ptrace/debugger/syscall_state.py", line 24, in enter
    self.syscall.enter(regs)
  File "/usr/lib/python2.6/site-packages/python_ptrace-0.6.4-py2.6.egg/ptrace/syscall/ptrace_syscall.py", line 37, in enter
    setupSocketCall(self, self.process, self[0], self[1].value)
  File "/usr/lib/python2.6/site-packages/python_ptrace-0.6.4-py2.6.egg/ptrace/syscall/socketcall.py", line 52, in setupSocketCall
    function.restype, formats = SYSCALL_PROTOTYPES[function.name]
KeyError: 's'
Terminate <PtraceProcess #2970>

How reproducible: always

Steps to reproduce: try to debug on 32bit arch any program that uses netlink, e.g. ip or tc from iproute

The bug is blocker for svinota/pyroute2#4


cptrace arguments truncated on 64-bit systems

Originally reported by: Anonymous


This issue can be seen when writing data using PTRACE_POKETEXT on 64-bit systems: the most significant 4 bytes of the written 8 byte word are always 0.

In cptrace.c the arguments to the ptrace call are converted using the PyArg_ParseTupleAndKeywords format string "Ii|iiO". This should be changed to "Ii|llO". I haven't tested this, but the rest of the code looks ok on first inspection (the variables are correctly declared as unsigned long).


strace.py prints wrong file descriptors with pipe() syscall

Originally reported by: Anonymous


Hi,

I was very excited to use python-ptrace for a project, but I stumbled upon a bug in the example strace.py file (but I think the problem is deeper).

I tried to run the following C program in both strace and strace.py :

#!C

#include <stdio.h>

int main(void)
{
    int fd[2];
    pipe(fd);
    return 0;
}

If I run this program with strace, I get the following output

#!shell
pipe([3, 4])                            = 0

but if I use strace.py, I get this :

#!shell
pipe(<(0, 2)>)                           = 0

The file descriptors are obviously wrong, because they correspond to stdin and stderr.

I use Ubuntu 13.10 (x86_64 architecture).


Method `isTraced` is implemented incorrectly

The implementation

class PTraceProcess:
  ...
    def isTraced(self):
        if not HAS_PROC:
            self.notImplementedError()
        stat = readProcessStat(self.pid)
        return (stat.state == 'T')

is checking for T, but that is for stopped by a signal; from man proc:

       /proc/[pid]/stat
              Status information about the process.  This is used by ps(1).  It is defined in the kernel source file fs/proc/array.c.
              ...
              (3) state  %c
                     One of the following characters, indicating process state:

                    ....
                     T  Stopped (on a signal) or (before Linux 2.6.33) trace stopped

                     t  Tracing stop (Linux 2.6.33 onward)

should be t. Probably class ProcessState needs reworking too.

python-ptrace fork support

Hey ! I was checking out the new commits when I came accross this issue:

Using this script:

python-ptrace> cat ../test.py 
#!/usr/bin/env python
import subprocess

message = ["Message", "à", "écrire"]

processes = [subprocess.Popen(["echo", mot]) for mot in message]
[proc.wait() for proc in processes]

I get the following from python-ptrace:

python-ptrace> ./strace.py ../test.py
[ ... ]
Debugger error: [ProcessSignal] Signal signal<133>
Traceback (most recent call last):
  File "/home/jb/Projects/python-ptrace/./strace.py", line 259, in _main
    exitcode = self.runDebugger()
  File "/home/jb/Projects/python-ptrace/./strace.py", line 243, in runDebugger
    return self.syscallTrace(process)
  File "/home/jb/Projects/python-ptrace/./strace.py", line 188, in syscallTrace
    self.syscall(event.process)
  File "/home/jb/Projects/python-ptrace/./strace.py", line 193, in syscall
    syscall = state.event(self.syscall_options)
  File "/home/jb/Projects/python-ptrace/ptrace/debugger/syscall_state.py", line 15, in event
    return self.exit()
  File "/home/jb/Projects/python-ptrace/ptrace/debugger/syscall_state.py", line 40, in exit
    self.process.waitSignals(SIGTRAP)
  File "/home/jb/Projects/python-ptrace/ptrace/debugger/process.py", line 736, in waitSignals
    return self.debugger.waitSignals(*signals, **{'pid': self.pid})
  File "/home/jb/Projects/python-ptrace/ptrace/debugger/debugger.py", line 209, in waitSignals
    raise event
ptrace.debugger.ptrace_signal.ProcessSignal: Signal signal<133>
Terminate <PtraceProcess #2181>

This does not happen when using strace.py python test.py, but does when launching strace.py --fork python test.py.

I remember the documentation specifically stating lack of support for forks, has this been added ?

the performance of -f option

hi,
i want to know the program execution process ,when i use the -f option, the process will be very slowly。
for example, i excute command "apt-get install gedit" , it takes about 5 seconds. if i use " python2.7 ./strace.py -f apt-get install gedit",it takes 2.5 min, the time is unacceptable.
i alse use linux strace, excute cmd "strace -f apt-get install gedit", it taks 20 second.
do you know the reason of being slowly?

error message method

Why not display error message in the same way? Some functions use "print(xxxx, file=stderr)" directly, and the others use "error(xxxxxx)".

Besides, "file=stderr" is gone in python3, it should be rewritten.

Instead of catching SIGFPE signal module throws: ValueError: Invalid status: 255

Originally reported by: Symeon P. (Bitbucket: symeonp, GitHub: symeonp)


System:

Ubuntu 14.04.1 LTS 32bit,
reproduced also on a 64bit version.

I am using also the latest version of python-ptrace.

$ nautilus --version

GNOME nautilus 3.10.1

$ uname -a

Linux ubuntuvm 3.13.0-36-generic #63-Ubuntu SMP Wed Sep 3 21:30:45 UTC 2014 i686 i686 i686 GNU/Linux

$ gdb --args nautilus ~/Desktop/jpc

gdb$ r

#!python

Starting program: /usr/bin/nautilus /home/user/Desktop/jpc
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/i386-linux-gnu/libthread_db.so.1".
[New Thread 0xb4cb8b40 (LWP 4874)]
[New Thread 0xb4299b40 (LWP 4876)]
[New Thread 0xb38ffb40 (LWP 4877)]
[New Thread 0xb26e3b40 (LWP 4879)]
[New Thread 0xae133b40 (LWP 4880)]
[Thread 0xb38ffb40 (LWP 4877) exited]
[New Thread 0xad932b40 (LWP 4885)]

Program received signal SIGFPE, Arithmetic exception.
[Switching to Thread 0xad932b40 (LWP 4885)]
--------------------------------------------------------------------------[regs]
  EAX: 0x00000000  EBX: 0xAD413000  ECX: 0xB2F05620  EDX: 0x00000000  o d I t s Z a P c 
  ESI: 0xB2F06F28  EDI: 0x00000000  EBP: 0xB2F09794  ESP: 0xAD930EF0  EIP: 0xAD3E27E9
  CS: 0073  DS: 007B  ES: 007B  FS: 0000  GS: 0033  SS: 007B
--------------------------------------------------------------------------[code]
=> 0xad3e27e9:  div    edi
   0xad3e27eb:  xor    edx,edx
   0xad3e27ed:  mov    DWORD PTR [ecx-0x20],edi
   0xad3e27f0:  movzx  esi,BYTE PTR [ebp-0x1]
   0xad3e27f4:  mov    DWORD PTR [ecx-0x8],0x0
   0xad3e27fb:  mov    DWORD PTR [ecx-0x4],0x0
   0xad3e2802:  mov    DWORD PTR [ecx-0x1c],esi
   0xad3e2805:  mov    DWORD PTR [esp+0x10],eax
--------------------------------------------------------------------------------
0xad3e27e9 in ?? () from /usr/lib/i386-linux-gnu/libjasper.so.1

python ptrace output:

$ python strace.py --debug nautilus ~/Desktop/jpc

#!python

.... snip ....
Warning: Format argument utime of futex() value error: [ProcessError] readBytes(0x00000001, 8) error: [Errno 5] Input/output error
Traceback (most recent call last):
  File "/home/user/Desktop/python-ptrace/ptrace/syscall/syscall_argument.py", line 115, in createText
    text = self.formatValuePointer(argtype[:-1])
  File "/home/user/Desktop/python-ptrace/ptrace/syscall/syscall_argument.py", line 160, in formatValuePointer
    return self.readStruct(address, struct)
  File "/home/user/Desktop/python-ptrace/ptrace/func_arg.py", line 71, in readStruct
    data = self.function.process.readStruct(address, struct)
  File "/home/user/Desktop/python-ptrace/ptrace/debugger/process.py", line 633, in readStruct
    bytes = self.readBytes(address, sizeof(struct))
  File "/home/user/Desktop/python-ptrace/ptrace/debugger/process.py", line 566, in readBytes
    formatAddress(address), size, err))
ProcessError: readBytes(0x00000001, 8) error: [Errno 5] Input/output error
futex(0x09a0fd64, 133, 1, 0x00000001, 0x09a0fd60, 67108865) = 1
futex(0x09a0a2e0, 129, 1, <timespec tv_sec=0, tv_nsec=0>, NULL, 3064070720) = 1
time(NULL)                               = 1411652277 (0x54241ab5)
syscall<331>(0xbf8d2698, 0x00000000, 0xb6989000, 0xbf8d2698, 0xbf8d281c, 0x00000000) = 0
syscall<331>(0xbf8d2688, 0x00000000, 0xb6989000, 0xbf8d2688, 0xbf8d281c, 0x00000000) = 0
syscall<331>(0xbf8d2690, 0x00080000, 0xb6989000, 0xbf8d2690, 0xbf8d281c, 0x00000001) = 0
clone(<SIGCHLD|CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID> (18874385), NULL, NULL, NULL, 0xb4603b28) = 5947 (0x0000173b)
Warning: Format argument utime of futex() value error: [ProcessError] readBytes(0x000000f0, 8) error: [Errno 5] Input/output error
Traceback (most recent call last):
  File "/home/user/Desktop/python-ptrace/ptrace/syscall/syscall_argument.py", line 115, in createText
    text = self.formatValuePointer(argtype[:-1])
  File "/home/user/Desktop/python-ptrace/ptrace/syscall/syscall_argument.py", line 160, in formatValuePointer
    return self.readStruct(address, struct)
  File "/home/user/Desktop/python-ptrace/ptrace/func_arg.py", line 71, in readStruct
    data = self.function.process.readStruct(address, struct)
  File "/home/user/Desktop/python-ptrace/ptrace/debugger/process.py", line 633, in readStruct
    bytes = self.readBytes(address, sizeof(struct))
  File "/home/user/Desktop/python-ptrace/ptrace/debugger/process.py", line 566, in readBytes
    formatAddress(address), size, err))
ProcessError: readBytes(0x000000f0, 8) error: [Errno 5] Input/output error
futex(0xb2600010, 129, 1, 0x000000f0, 0xbf8d25b0, 3213698568) = 1
close(23)                                = 0
close(25)                                = 0
close(27)                                = 0
read(22, 0xbf8d26a8, 8)                  = 0
close(22)                                = 0
select(27, <fdset=(24, 26)>, NULL, NULL, NULL) = 2
Debugger error: [ValueError] Invalid status: 255
Traceback (most recent call last):
  File "strace.py", line 247, in _main
    self.runDebugger()
  File "strace.py", line 235, in runDebugger
    self.syscallTrace(process)
  File "strace.py", line 170, in syscallTrace
    event.display()
  File "/home/user/Desktop/python-ptrace/ptrace/debugger/ptrace_signal.py", line 216, in display
    self._analyze()
  File "/home/user/Desktop/python-ptrace/ptrace/debugger/ptrace_signal.py", line 68, in _analyze
    self.childExit()
  File "/home/user/Desktop/python-ptrace/ptrace/debugger/ptrace_signal.py", line 211, in childExit
    self.reason = ChildExit(child.pid, child.status, child.uid)
  File "/home/user/Desktop/python-ptrace/ptrace/debugger/signal_reason.py", line 154, in __init__
    message = formatProcessStatus(status, "Child process %s" % pid)
  File "/home/user/Desktop/python-ptrace/ptrace/process_tools.py", line 110, in formatProcessStatus
    raise ValueError("Invalid status: %r" % status)
ValueError: Invalid status: 255
Quit debugger
Terminate <PtraceProcess #5937>

Hopefully you should be able to reproduce it on a latest Ubuntu system with nautilus.
I am attaching also the test cases.

Many thanks Victor!

Cheers,
Symeon.


should add Seize/Cont functionality (only Linux)

Hi, this is my first time posting an Issue, apologies if its done in an incorrect way.

I really like this library. I extended it a bit to support using PTRACE_SEIZE and the various upsides this brings, however I can only test on my 64 Bit Linux and dont really now the constants values for other OSes nor can I test it.
Should I provide my fix even though it wont work on BSD?

Thank you for providing the library!

The strange useage of unix pipe, why it reads from itself.

For file : ptrace/debugger/child.py

def createChild(arguments, no_stdout, env=None):
    """
    Create a child process:
     - arguments: list of string where (e.g. ['ls', '-la'])
     - no_stdout: if True, use null device for stdout/stderr
     - env: environment variables dictionary

    Use:
     - env={} to start with an empty environment
     - env=None (default) to copy the environment
    """
    errpipe_read, errpipe_write = pipe()
    _set_cloexec_flag(errpipe_write)

    # Fork process
    pid = fork()
    if pid:
        close(errpipe_write)
        _createParent(pid, errpipe_read)
        return pid
    else:
        close(errpipe_read)
        _createChild(arguments, no_stdout, env, errpipe_write)`

It's very strange, if I remove 'close(errpipe_write)' line before '_createParent(pid, errpipe_read)'. the '_createParent' will be blocked. I can not understand this case of unix pipe, I think it's waiting for the data from the child.

Can anyone help me?

Plan to add aarch64 support?

Currently on 32-bit arm is supported. Do you plan to add aarch64 support?
uname would return aarch64 instead of arm*

ptrace on ARM

Originally reported by: Peter Saveliev (Bitbucket: svinota, GitHub: svinota)


root@localhost:~# ./strace.py ps
execve(/bin/ps, ['/bin/ps'], [/* 40 vars */]) = 19393
Debugger error: [NotImplementedError]
Traceback (most recent call last):
  File "./strace.py", line 247, in _main
    self.runDebugger()
  File "./strace.py", line 235, in runDebugger
    self.syscallTrace(process)
  File "./strace.py", line 181, in syscallTrace
    self.syscall(process)
  File "./strace.py", line 185, in syscall
    syscall = state.event(self.syscall_options)
  File "/usr/lib/python2.7/dist-packages/ptrace/debugger/syscall_state.py", line 15, in event
    return self.enter(options)
  File "/usr/lib/python2.7/dist-packages/ptrace/debugger/syscall_state.py", line 24, in enter
    self.syscall.enter(regs)
  File "/usr/lib/python2.7/dist-packages/ptrace/syscall/ptrace_syscall.py", line 33, in enter
    argument_values = self.readArgumentValues(regs)
  File "/usr/lib/python2.7/dist-packages/ptrace/syscall/ptrace_syscall.py", line 74, in readArgumentValues
    raise NotImplementedError()
NotImplementedError
Terminate <PtraceProcess #19393>
*** Error in `python': double free or corruption (!prev): 0x02340d90 ***
Aborted
root@localhost:~# cat /proc/cpuinfo
Processor       : ARMv7 Processor rev 9 (v7l)
processor       : 0
BogoMIPS        : 1993.93

processor       : 1
BogoMIPS        : 1993.93

processor       : 2
BogoMIPS        : 1993.93

processor       : 3
BogoMIPS        : 1993.93

Features        : swp half thumb fastmult vfp edsp neon vfpv3 tls
CPU implementer : 0x41
CPU architecture: 7
CPU variant     : 0x2
CPU part        : 0xc09
CPU revision    : 9

Hardware        : cardhu
Revision        : 0000
Serial          : 02458200e04f4300
root@localhost:~#

Platform -- Debian sid on asus transformer pad tf300t, using Android kernel:

root@localhost:~# uname -a
Linux localhost 3.1.10-00003-gb0003ba #1 SMP PREEMPT Fri Dec 28 17:34:15 CST 2012 armv7l GNU/Linux

If ARM platform is not supported, it would be better to raise an exception on import for non-distribution installations AND restrict platforms for distribution packaging.

If it is supported, it would be nice to have it fixed.


Enable syscall tracing for threads

Originally reported by: Michael Witt (Bitbucket: MichaelHTW, GitHub: Unknown)


Hi,

I recently discovered this library and wanted to use it for process syscall tracing. Soon I discovered that tracing of processed created with the clone-syscall (or more commonly known as threads) are not supported.

As I needed this functionality for tracing on linux-based systems I added the missing functionality. I've forked the repository and pushed my changes here https://bitbucket.org/MichaelHTW/python-ptrace-withclone/commits/f163841b72a76232ac4d3721dc3f30b5cf581173.

In case there are others out there that might require this functionality feel free to integrate.

Best regards and thanks for the great work
Michael


Unable to monitor living process memory

Originally reported by: Kevin Chen (Bitbucket: kvchen, GitHub: kvchen)


Here's a summary of what I'm trying to do:

dbg = PtraceDebugger()
process = dbg.addProcess(pid, False)
map = readProcessMappings(process)

while True:
    process.kill(19)    # Send SIGSTOP to pause the process
    process.readWord(0x189f9e0)    # Read some memory address
    process.cont()

After printing out the value on the first iteration, ptrace complains that the process PID could not be found for subsequent iterations:

ptrace.error.PtraceError: ptrace(cmd=1, pid=10679, 25819616, 0) error #3: No such process

I assume that there's something I don't know about ptrace, since it works if I stop the process and continually read memory without ever resuming it. Any pointers for what I'm doing wrong?


syscall missing

Hello, sys_rt_sigreturn is missing on your syscalls prototypes list

Closing file descriptors

What is the rationale behind the closing of file descriptors before executing a child ?

I noticed this pythonic behaviour in the subprocess module for Windows portability, but is there a case against an option to turn that off while creating a child ? strace does not do that, and my use case relies on opened file descriptors to communicate.

I can provide a pull request for that too, just wanted to know if there is a particular case this is required.

Sorry for the spam on an old repo !

strace.py prints incorrect select() systray arguments

Originally reported by: Pavel Šimerda (Bitbucket: pavlix, GitHub: pavlix)


I found a trivially reproducable difference between strace.py and genuine strace outputs showing that python-ptrace probably doesn't parse select() arguments properly.

How to test:

$ strace -e select -o trace.strace ssh localhost true
$ python strace.py -e select -o trace.python-ptrace ssh localhost true

Expected result:

Output files should be roughly the same.

Actual result:

The second command results in a file that wrongly suggest the select was run on a huge number of file descriptors.


Bug found

I found a bug in cpu.py:

    CPU_SUB_REGISTERS = {
        # main register name, shift, mask
        'al': ('rax', 0, 0xff),
        'bl': ('rbx', 0, 0xff),
        'cl': ('rcx', 0, 0xff),
        'dl': ('rdx', 0, 0xff),
        'ah': ('rax', 8, 0xff),
        'bh': ('rbx', 8, 0xff),
        'ch': ('rcx', 8, 0xff),
        'dh': ('rdx', 8, 0xff),
        'ax': ('rax', 0, 0xffff),
        'bx': ('rbx', 0, 0xffff),
        'cx': ('rcx', 0, 0xffff),
        'dx': ('rdx', 0, 0xffff),
        'eax': ('rax', 32, None),
        'ebx': ('rbx', 32, None),
        'ecx': ('rcx', 32, None),
        'edx': ('rdx', 32, None),
    }

here the shift and mask for eax, ebx, ecx, edx is wrong, the correct version should be:"

    CPU_SUB_REGISTERS = {
        # main register name, shift, mask
        'al': ('rax', 0, 0xff),
        'bl': ('rbx', 0, 0xff),
        'cl': ('rcx', 0, 0xff),
        'dl': ('rdx', 0, 0xff),
        'ah': ('rax', 8, 0xff),
        'bh': ('rbx', 8, 0xff),
        'ch': ('rcx', 8, 0xff),
        'dh': ('rdx', 8, 0xff),
        'ax': ('rax', 0, 0xffff),
        'bx': ('rbx', 0, 0xffff),
        'cx': ('rcx', 0, 0xffff),
        'dx': ('rdx', 0, 0xffff),
        'eax': ('rax', 0, 0xffffffff),
        'ebx': ('rbx', 0, 0xffffffff),
        'ecx': ('rcx', 0, 0xffffffff),
        'edx': ('rdx', 0, 0xffffffff),
    }

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.