simuvex
simuvex copied to clipboard
started to implement ptrace behaviour
ptrace syscall now handles the PTRACE_TRACEME request
Have you tested this? I don't believe this will work. A new SimProcedure instance is created for each time the procedure is executed...
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
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 :-)
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
?
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!
Please squash this horrible git history when merging :D
@themaks You can squash them with a force push!
thanks, I didn't know I could do that ! I squashed all changes into one commit and rebased it onto current master branch
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.