From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 88497 invoked by alias); 22 Jun 2017 16:10:42 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Received: (qmail 88287 invoked by uid 89); 22 Jun 2017 16:10:34 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.9 required=5.0 tests=BAYES_00,SPF_HELO_PASS,T_RP_MATCHES_RCVD autolearn=ham version=3.3.2 spammy=stands, breach X-HELO: mx1.redhat.com Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Thu, 22 Jun 2017 16:10:33 +0000 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id B1A1D2EF183; Thu, 22 Jun 2017 16:10:31 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com B1A1D2EF183 Authentication-Results: ext-mx05.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx05.extmail.prod.ext.phx2.redhat.com; spf=pass smtp.mailfrom=law@redhat.com DKIM-Filter: OpenDKIM Filter v2.11.0 mx1.redhat.com B1A1D2EF183 Received: from localhost.localdomain (ovpn-117-117.phx2.redhat.com [10.3.117.117]) by smtp.corp.redhat.com (Postfix) with ESMTP id 43F4560608; Thu, 22 Jun 2017 16:10:31 +0000 (UTC) Subject: Re: RFC: stack/heap collision vulnerability and mitigation with GCC To: Wilco Dijkstra , Richard Earnshaw , GCC Patches Cc: nd References: <03f6ffbb-045f-e591-0416-74fc19f585df@redhat.com> From: Jeff Law Message-ID: <65e55d54-caf5-ca5f-7835-7541091e7528@redhat.com> Date: Thu, 22 Jun 2017 16:10:00 -0000 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Thunderbird/52.1.0 MIME-Version: 1.0 In-Reply-To: Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-IsSubscribed: yes X-SW-Source: 2017-06/txt/msg01688.txt.bz2 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