Public
Snippet $316 authored by Jérome Perrin

use python-ptrace to inspect the files created/written and the unix socket for a process

slaptrace.py
import os
import socket

import ptrace.debugger
import ptrace.func_call
import ptrace.syscall

options = ptrace.func_call.FunctionCallOptions()
debugger = ptrace.debugger.PtraceDebugger()
pid = ptrace.debugger.child.createChild(("/srv/slapgrid/slappart8/tmp/inst/TestFilesAndSocketsInInstanceDir-0/etc/service/proftpd", ), no_stdout=True)

debugger.addProcess(pid, is_attached=True)
process = debugger.dict[pid]

def eventCallBack(process, event):
  if event.name  == 'open':
      # int open(const char *pathname, int flags, mode_t mode);
      mode = event.arguments[1].value
      # creating files or opening files for writing is not allowed
      if (mode & os.O_CREAT) or (mode & os.O_RDWR) or (mode & os.O_RDWR):
        filename = event.arguments[0].getText()
        filename = filename[1:-1] # XXX filename is quoted
        print "program opened a file for writing", filename

  elif event.name == 'bind':
    # int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

    # first read as "generic" sockaddr to know the family
    family = process.readStruct(
        event.arguments[1].value,
        ptrace.syscall.socketcall_struct.sockaddr).family
    
    # then re-read with the proper family
    struct_map = {
        socket.AF_UNIX: ptrace.syscall.socketcall_struct.sockaddr_un,
        socket.AF_INET: ptrace.syscall.socketcall_struct.sockaddr_in,
        socket.AF_INET6: ptrace.syscall.socketcall_struct.sockaddr_in6,
    }
    addr = process.readStruct(event.arguments[1].value, struct_map[family])
    if family == socket.AF_UNIX:
      print "program opened unix socket at", addr.sun_path
    # TODO: binding socket on other IP address than slapos partition is not allowed either.


while True:
  process.syscall()
  try:
    event = debugger.waitSyscall()
  except ptrace.debugger.NewProcessEvent, newprocess:
    print "TODO, trace new process"
  except ptrace.debugger.ProcessSignal, signal:
    print "Ignored signal", signal
  except ptrace.debugger.ProcessExecution, processExec:
    print "Ignored process execution", processExec
  except ptrace.debuggerprocess_event.ProcessExit, exit:
    print "Process exited", exit
    break
  
  event = process.syscall_state.event(options)
  eventCallBack(process, event)
  # XXX ( to integrate this we need to kill the process at some point )