simuvex icon indicating copy to clipboard operation
simuvex copied to clipboard

started to implement ptrace behaviour

Open themaks opened this issue 8 years ago • 9 comments

ptrace syscall now handles the PTRACE_TRACEME request

themaks avatar Jan 28 '17 12:01 themaks

Have you tested this? I don't believe this will work. A new SimProcedure instance is created for each time the procedure is executed...

rhelmot avatar Jan 28 '17 14:01 rhelmot

Yes, I just tested it against this program:

#include <stdio.h>
#include <stdlib.h>
#include <sys/ptrace.h>


int main(int argc, char** argvv){
  if(ptrace(PTRACE_TRACEME,0,0,0)==0)
    printf("Win 1\n");
  else
    printf("Fail 1\n");
  if(ptrace(PTRACE_TRACEME,0,0,0)==-1)
    printf("Win 2\n");
  else
    printf("Fail 2\n");

  return 0;
}

and executed the following commands :

In [1]: import angr

In [2]: b=angr.Project("./test_ptrace")

In [3]: pg=b.factory.path_group()

In [4]: pg.explore()
Out[4]: <PathGroup with 1 deadended>

In [5]: pg.one_deadended.state.posix.dumps(1)
Out[5]: 'Win 1\nWin 2\n'

If your concern is about the "ptrace.selftraced" variable, it is a static variable for the class ptrace and can be used everywhere, whereas "self.selftraced" would be specific to an instance of a class

themaks avatar Jan 28 '17 17:01 themaks

I think the issue that @rhelmot is pointing out is that in this implementation with ptrace.selftraced being a class variable, you will only ever get one path per invocation of python that will do a successful ptrace. Consider the following code:

#include <stdio.h>
#include <stdlib.h>
#include <sys/ptrace.h>


int main(int argc, char** argvv){
  if (argv[0] == 'a')
    printf("case 1\n");
  else
    printf("case 2\n");
  if(ptrace(PTRACE_TRACEME,0,0,0)==0)
    printf("Win 1\n");
  else
    printf("Fail 1\n");
  if(ptrace(PTRACE_TRACEME,0,0,0)==-1)
    printf("Win 2\n");
  else
    printf("Fail 2\n");

  return 0;
}

If you run this with a symbolic argv[0], with this implementation, you will only have one path that reaches Win 1, even though there should be two of them. The selftraced attribute should really be a per-state attribute on a state plugin state.posix is a good place to put it for now. That way, you can make the decision of whether it succeeded based on the program state in question, rather than a global variable, and properly trigger both conditions in my example.

There is also the more complicated question of dealing with symbolic values of selftraced in more complex use-cases (such as the merging of a path that was attached to with ptrace and a path that was not), but I suggest that we don't worry about that for now :-)

zardus avatar Jan 29 '17 01:01 zardus

Quick question : I was trying to make ptrace return an unconstrained value if the request is symbolic or not supported (!= PRACE_TRACEME), by inline_call-ing the ReturnUnconstrained stub, but it does not seem possible at the moment : the successors argument is set to None during an inline_call, but ReturnUnconstrained stub uses it.

[...]
/usr/local/lib/python2.7/dist-packages/simuvex-6.7.1.13.post2-py2.7.egg/simuvex/procedures/syscalls/ptrace.pyc in run(self, request, pid, addr, data)
     16         if self.state.se.symbolic(request):
     17             l.warning("Symbolic PTRACE_* request, returning unconstrained value")
---> 18             res = self.inline_call(simuvex.SimProcedures['stubs']['ReturnUnconstrained'])
     19         else:
     20             request = self.state.se.any_int(request)

/usr/local/lib/python2.7/dist-packages/simuvex-6.7.1.13.post2-py2.7.egg/simuvex/s_procedure.pyc in inline_call(self, procedure, *arguments, **sim_kwargs)
    261         e_args = [ self.state.se.BVV(a, self.state.arch.bits) if isinstance(a, (int, long)) else a for a in arguments ]
    262         p = procedure(self.addr, self.arch, sim_kwargs=sim_kwargs)
--> 263         p.execute(self.state, None, arguments=e_args)
    264         return p
    265

/usr/local/lib/python2.7/dist-packages/simuvex-6.7.1.13.post2-py2.7.egg/simuvex/s_procedure.pyc in execute(self, state, successors, arguments, ret_to)
    135
    136             # run it
--> 137             r = run_func(*sim_args, **self.kwargs)
    138
    139         if self.returns:

/usr/local/lib/python2.7/dist-packages/simuvex-6.7.1.13.post2-py2.7.egg/simuvex/procedures/stubs/ReturnUnconstrained.pyc in run(self, resolves)
     10         self.resolves = resolves
     11
---> 12         self.successors.artifacts['resolves'] = resolves
     13
     14         o = self.state.se.Unconstrained("unconstrained_ret_%s" % self.resolves, self.state.arch.bits)

AttributeError: 'NoneType' object has no attribute 'artifacts'

I am not quite familiar with angr's internal for now so I don't understand the meaning of this variable : is this behaviour a bug or is there something I don't understand and it doesn't make sense to inline_call ReturnUnconstrained ?

themaks avatar Feb 18 '17 16:02 themaks

The fact that it uses self.successors directly means that it's not intended to be used as an inline call.

You don't need to do a call out to ReturnUnconstrained, you can instead just return self.state.se.BVV('ptrace_return', self.state.arch.bits)

BTW, with regard to the original issue with the selftraced variable, angr now has state.procedure_data.global_variables, a dict where you can store global vars like that!

rhelmot avatar Feb 18 '17 18:02 rhelmot

Please squash this horrible git history when merging :D

themaks avatar Feb 21 '17 19:02 themaks

@themaks You can squash them with a force push!

ltfish avatar Feb 22 '17 01:02 ltfish

thanks, I didn't know I could do that ! I squashed all changes into one commit and rebased it onto current master branch

themaks avatar Feb 22 '17 09:02 themaks

This looks great! Can you please add a testcase in some way? The ideal way would be a pull request to binaries including a binary that exercises ptrace in several supported ways, and then updating your pull request to angr to emulate that binary and make sure we see the expected behavior. Ideally this test would happen once with simprocedures enabled and once without.

rhelmot avatar Feb 23 '17 22:02 rhelmot