Skip to content
This repository has been archived by the owner on May 18, 2022. It is now read-only.

started to implement ptrace behaviour #78

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

themaks
Copy link
Contributor

@themaks themaks commented Jan 28, 2017

ptrace syscall now handles the PTRACE_TRACEME request

@rhelmot
Copy link
Member

rhelmot commented Jan 28, 2017

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

@themaks
Copy link
Contributor Author

themaks commented Jan 28, 2017

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

@zardus
Copy link
Member

zardus commented Jan 29, 2017

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 :-)

@themaks
Copy link
Contributor Author

themaks commented Feb 18, 2017

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 ?

@rhelmot
Copy link
Member

rhelmot commented Feb 18, 2017

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!

@themaks
Copy link
Contributor Author

themaks commented Feb 21, 2017

Please squash this horrible git history when merging :D

@ltfish
Copy link
Member

ltfish commented Feb 22, 2017

@themaks You can squash them with a force push!

now handles PTRACE_TRACEME requests
@themaks
Copy link
Contributor Author

themaks commented Feb 22, 2017

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

@rhelmot
Copy link
Member

rhelmot commented Feb 23, 2017

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.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants