Repository: angr/angr

Issue:
SimSegfaultException due to collision of stack and heap when tracing a binary
**Describe the bug.**

When tracing a CGC binary using a PoV for it, a `SimSegfaultException` is raised due to the collision of stack and heap.

**Environment Information.**

Platform: linux-x86_64
Python version: 3.8.5 (default, Jan 27 2021, 15:41:15) 
[GCC 9.3.0]
######## angr #########
Python found it in /home/dnivra/angr-dev/angr/angr
Pip version angr 9.0.gitrolling
Git info:
        Current commit 762becbf9c66d4798b8c23cfa512a7f893e2bcf9 from branch master
        Checked out from remote origin: https://github.com/angr/angr
######## ailment #########
Python found it in /home/dnivra/angr-dev/ailment/ailment
Pip version ailment 9.0.gitrolling
Git info:
        Current commit 4e2bba6f0299d1eda6ae570ceabd91eb8a0c72be from branch master
        Checked out from remote origin: https://github.com/angr/ailment
######## cle #########
Python found it in /home/dnivra/angr-dev/cle/cle
Pip version cle 9.0.gitrolling
Git info:
        Current commit 80dcd50abfaa70cbd5b2e360fe41b71406acbfb4 from branch master
        Checked out from remote origin: https://github.com/angr/cle
######## pyvex #########
Python found it in /home/dnivra/angr-dev/pyvex/pyvex
Pip version pyvex 9.0.gitrolling
Git info:
        Current commit 969ec1f10d3e3b15407ee986052aa4b6f2e9df05 from branch master
        Checked out from remote origin: https://github.com/angr/pyvex
######## claripy #########
Python found it in /home/dnivra/angr-dev/claripy/claripy
Pip version claripy 9.0.gitrolling
Git info:
        Current commit 34f31c487f7453f4666cd6fd1d529f417ff6ca08 from branch master
        Checked out from remote origin: https://github.com/angr/claripy
######## archinfo #########
Python found it in /home/dnivra/angr-dev/archinfo/archinfo
Pip version archinfo 9.0.gitrolling
Git info:
        Current commit 437b194538ccb0bf118b4b674613b88832b0b342 from branch master
        Checked out from remote origin: https://github.com/angr/archinfo
######## z3 #########
Python found it in /home/dnivra/.virtualenvs/angr-dev/lib/python3.8/site-packages/z3
Pip version z3-solver 4.8.9.0
Couldn't find git info
######## unicorn #########
Python found it in /home/dnivra/.virtualenvs/angr-dev/lib/python3.8/site-packages/unicorn
Pip version unicorn 1.0.2rc4
Couldn't find git info
######### Native Module Info ##########
angr: <CDLL '/home/dnivra/angr-dev/angr/angr/lib/angr_native.so', handle 3375570 at 0x7f938b7ee220>
unicorn: <CDLL '/home/dnivra/.virtualenvs/angr-dev/lib/python3.8/site-packages/unicorn/lib/libunicorn.so', handle 2aa9f70 at 0x7f93913291c0>
pyvex: <cffi.api._make_ffi_library.<locals>.FFILibrary object at 0x7f9391f39130>
z3: <CDLL '/home/dnivra/.virtualenvs/angr-dev/lib/python3.8/site-packages/z3/lib/libz3.so', handle 2d099d0 at 0x7f938ea3a340>

**To Reproduce.**

[CROMU_00004-stack-heap-collision-repro.zip](https://github.com/angr/angr/files/6481681/CROMU_00004-stack-heap-collision-repro.zip) has script, input and binary to reproduce the issue. `SimSegfaultException` is raised in the `receive` syscall after block 0x804b87b is executed for first time in the VEX engine(13th overall execution). It takes about 10 minutes for execution to reach this location

.


Discussion:
My professional opinion is that this isn't worth fixing the "right" way - that being that we have a hack installed in shellphish-qemu which will automatically grow the stack if a segfault occurs in the stack region. This is honestly what I would classify as a compiler bug.

I say just toss the testcase.
Dumb question; likely because of some gap in my understanding. The qemu tracer generates a trace properly for this binary. The crash happens when trying to follow the trace in angr. If I have understood correctly, only the basic block trace from qemu tracer is used by the tracer exploration technique isn't it?
Yes, that is correct. The problem is that there is a hack in our qemu which allows us to trace this binary "correctly": https://github.com/mechaphish/qemu-cgc/blob/base_cgc/linux-user/signal.c#L588. I don't care to replicate this hack in angr.

If you really want to make this binary trace correctly, you should change the stack preallocation to 0x100 pages.
> If you really want to make this binary trace correctly, you should change the stack preallocation to 0x100 pages.

Do it! @dnivra 
Somehow missed the responses. Thanks for the explanation! I can confirm 0x100 does prevent the stack heap collision. Should I send a PR changing the pre-allocation or just leave it as is?
I would make the cgc stack preallocation a state constructor parameter. That should safely insulate us from anything even more absurd in the future.

Resolving patch:
diff --git a/angr/simos/cgc.py b/angr/simos/cgc.py
--- a/angr/simos/cgc.py
+++ b/angr/simos/cgc.py
@@ -24,9 +24,10 @@ def __init__(self, project, **kwargs):
                 **kwargs)
 
     # pylint: disable=arguments-differ
-    def state_blank(self, flag_page=None, **kwargs):
+    def state_blank(self, flag_page=None, allocate_stack_page_count=0x100, **kwargs):
         """
-        :param flag_page:   Flag page content, either a string or a list of BV8s
+        :param flag_page:                   Flag page content, either a string or a list of BV8s
+        :param allocate_stack_page_count:   Number of pages to pre-allocate for stack
         """
         # default stack as specified in the cgc abi
         if kwargs.get('stack_end', None) is None:
@@ -36,9 +37,9 @@ def state_blank(self, flag_page=None, **kwargs):
 
         s = super(SimCGC, self).state_blank(**kwargs)  # pylint:disable=invalid-name
 
-        # pre-grow the stack by 20 pages. unsure if this is strictly required or just a hack around a compiler bug
+        # pre-grow the stack. unsure if this is strictly required or just a hack around a compiler bug
         if hasattr(s.memory, 'allocate_stack_pages'):
-            s.memory.allocate_stack_pages(kwargs['stack_end'] - 1, 20 * 0x1000)
+            s.memory.allocate_stack_pages(kwargs['stack_end'] - 1, allocate_stack_page_count * 0x1000)
 
         # Map the flag page
         if o.ABSTRACT_MEMORY not in s.options:


Test patch: