This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: RFC: stack/heap collision vulnerability and mitigation with GCC


On 06/21/2017 11:47 AM, Wilco Dijkstra wrote:
> Jeff Law wrote:
> 
>> I'm a little confused.  I'm not defining or changing the ABI.  I'm
>> working within my understanding of the existing aarch64 ABI used on
>> linux systems.  My understanding after reading that ABI and the prologue
>> code for aarch64 is there's nothing that can currently be relied upon in
>> terms of the offset from the incoming stack pointer to the most recent
>> "probe" in the caller.
> 
> Well what we need is a properly defined ABI on when to emit probes.  That
> doesn't exist yet indeed, so there is nothing you can rely on today.  But that
> is true for any architecture. In particular if the caller hasn't been compiled with
> probes, even if the call instruction does an implicit probe, you still have to 
> assume that the stack guard has been breached already (ie. doing probes in
> the callee is useless if they aren't done in the whole call chain).
You can be in one of 3 states when you start the callee's prologue.

1. You're somewhere in the normal stack.

2. You've past the guard and are already in the heap or elsewhere

3. You're somewhere in the guard


State #1 is trivially handled.  You emit probes every PROBE_INTERVAL
bytes in newly allocated space and you're OK.

State #2 we can't do anything about.

State #3 is what we're trying to address.  The attacker has advanced the
stack pointer into the guard, but has not fully breached the guard.  We
need to ensure that we hit the guard to prevent the breach.

On x86 and ppc state #3 does not occur due to the ISA and ABI.  We rely
on not being in state #3 to avoid a great number of the explicit probes.

But on aarch64, s390 and likely many other architectures, state #3 is a
real possibility and we need to account for it.

As it stands right now we can be in state #3 and the stack pointer could
be STACK_BOUNDARY / BITS_PER_UNIT bytes away from the end of the guard.
If we were to emit a

stp lr, fp, [sp, -32]!

That would complete jumping the guard since it allocates 32 bytes of
space, then writes 16 and thus we do not hit the guard.


If (for example) the ABI were to mandate touching last outgoing arg slot
if it were > 1k and touch the last slot of the dynamic space in the
caller, then we would know that the stack pointer must be at least
3kbytes away from the end of the guard.  And thus

stp lr, fp, [sp, -32]!

Would hit the guard.  In fact, we could allocate up to 3kbytes of space
without a probe.

> Remember Richard's reply was to this:
>>> aarch64 is significantly worse.  There are no implicit probes we can
>>> exploit.  Furthermore, the prologue may allocate stack space 3-4 times.
>>> So we have the track the distance to the most recent probe and when that
>>> distance grows too large, we have to emit a probe.  Of course we have to
>>> make worst case assumptions at function entry.
> 
> As pointed out, AArch64 is not significantly worse since the majority of frames
> do not need any probes (let alone multiple probes as suggested), neither do we
> need to make worst-case assumptions on entry (stack guard has already been
> breached).
See above.  It is significantly worse on aarch64/s390 because we need to
account for case #3 above.  Whereas x86 and ppc do not because of how
their ISA and ABIs work.

> 
>> Just limiting the size of the outgoing arguments is not sufficient
>> though.  You still have the dynamic allocation area in the caller.  The
>> threat model assumes the caller follows the ABI, but does not have to
>> have been compiled with -fstack-check.
> 
> The only mitigation for that is to increase the stack guard. A callee cannot 
> somehow undo crossing the stack guard by an unchecked caller (that includes
> the case where calls do an implicit probe).
I think you're looking at case #2 above and indeed we can't do anything
about that.  If they've fully breached the guard, then there's nothing
we can do.  But if they have only partially breached the guard then we
can and should stop them (case #3).

jeff


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]