From patchwork Tue May 10 17:20:18 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Jon Medhurst \(Tixy\)" X-Patchwork-Id: 67471 Delivered-To: patch@linaro.org Received: by 10.140.92.199 with SMTP id b65csp2253877qge; Tue, 10 May 2016 10:41:37 -0700 (PDT) X-Received: by 10.98.52.195 with SMTP id b186mr60413100pfa.9.1462902097887; Tue, 10 May 2016 10:41:37 -0700 (PDT) Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id g26si3859053pfd.72.2016.05.10.10.41.37; Tue, 10 May 2016 10:41:37 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of stable-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of stable-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=stable-owner@vger.kernel.org; dmarc=fail (p=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751010AbcEJRlg (ORCPT + 3 others); Tue, 10 May 2016 13:41:36 -0400 Received: from queue01b.mail.zen.net.uk ([212.23.3.242]:49964 "EHLO queue01b.mail.zen.net.uk" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1750951AbcEJRlf (ORCPT ); Tue, 10 May 2016 13:41:35 -0400 X-Greylist: delayed 1272 seconds by postgrey-1.27 at vger.kernel.org; Tue, 10 May 2016 13:41:35 EDT Received: from [212.23.1.23] (helo=smarthost03d.mail.zen.net.uk) by queue01b.mail.zen.net.uk with esmtp (Exim 4.72) (envelope-from ) id 1b0BKX-0001np-Mf for stable@vger.kernel.org; Tue, 10 May 2016 17:20:21 +0000 Received: from [82.69.122.217] (helo=linaro2) by smarthost03d.mail.zen.net.uk with esmtpsa (TLS1.2:RSA_AES_128_CBC_SHA1:128) (Exim 4.80) (envelope-from ) id 1b0BKV-00053q-2X; Tue, 10 May 2016 17:20:19 +0000 Message-ID: <1462900818.3220.14.camel@linaro.org> Subject: [PATCH for 4.0 and before] arm64: Make arch_randomize_brk avoid stack area From: "Jon Medhurst (Tixy)" To: stable@vger.kernel.org Cc: Catalin Marinas , Kees Cook Date: Tue, 10 May 2016 18:20:18 +0100 In-Reply-To: <20160510155557.GD3214@e104818-lin.cambridge.arm.com> References: <1461848638.2848.19.camel@linaro.org> <1462370994.2895.11.camel@linaro.org> <20160506111937.GK20671@e104818-lin.cambridge.arm.com> <1462535460.4575.3.camel@linaro.org> <20160510155557.GD3214@e104818-lin.cambridge.arm.com> X-Mailer: Evolution 3.12.9-1+b1 Mime-Version: 1.0 X-Originating-smarthost03d-IP: [82.69.122.217] Sender: stable-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: stable@vger.kernel.org From: Jon Medhurst When a process is created, various address randomisations could end up colluding to place the address of brk in the stack memory. This would mean processes making small heap based memory allocations are in danger of having them overwriting, or overwritten by, the stack. Another consequence, is that even for processes that make no use of brk, the output of /proc/*/maps may show the stack area listed as '[heap]' rather than '[stack]'. Apart from being misleading this causes fatal errors with the Android run-time like: "No [stack] line found in /proc/self/task/*/maps" To prevent this problem pick a limit for brk that allows for the stack's memory. At the same time we remove randomize_base() as that was only used by arch_randomize_brk(). Note, in practice, since commit d1fd836dcf00 ("mm: split ET_DYN ASLR from mmap ASLR") this problem shouldn't occur because the address chosen for loading binaries is well clear of the stack, however, prior to that the problem does occur because of the following... The memory layout of a task is determined by arch_pick_mmap_layout. If address randomisation is enabled (task has flag PF_RANDOMIZE) this sets mmap_base to a random address at the top of task memory just below a region calculated to allow for a stack which itself may have a random base address. Any mmap operations that then happen which require an address allocating will use the topdown allocation method, i.e. the first allocated memory will be at the top of memory, just below the area set aside for the stack. When a relocatable binary is loaded into a new process by load_elf_binary and randomised address are enabled, it uses a 'load_bias' of zero, so that when mmap is called to create a memory region for it, a new address is picked (address zero not being available). As this is the first memory region in the task, it gets the region just below the stack, as described previously. The loader then set's brk to the end of the elf data section, which will be near the end of the loaded binary and then it calls arch_randomize_brk. As this currently stands, this adds a random amount to brk, which unfortunately may take it into the address range where the stack lies. Testing: These changes have been tested on Linux 3.18 (where the collision of brk and stack can happen) using 100000 invocations of a program [1] that can display the offset of a process's brk... $for i in $(seq 100000); do ./aslr --report brk ; done This shows values of brk are evenly distributed over a 1GB range before this change is applied. After this change the distribution shows a slope where lower values for brk are more common and upper values have about half the frequency of those. [1] http://bazaar.launchpad.net/~ubuntu-bugcontrol/qa-regression-testing/master/files/2499/scripts/kernel-security/aslr/ Signed-off-by: Jon Medhurst Acked-by: Kees Cook Acked-by: Catalin Marinas --- As mentioned in the commit message, the problem this patch fixes can't occur in kernels with commit d1fd836dcf00, i.e Linux 4.1 and later., but earlier kernel versions need this fix. I originally posted this to the ARM kernel list and arm64 maintainers, see http://www.spinics.net/lists/arm-kernel/msg502238.html arch/arm64/kernel/process.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) -- 2.1.4 -- To unsubscribe from this list: send the line "unsubscribe stable" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c index 07c4c53..afea4b1 100644 --- a/arch/arm64/kernel/process.c +++ b/arch/arm64/kernel/process.c @@ -434,13 +434,25 @@ unsigned long arch_align_stack(unsigned long sp) return sp & ~0xf; } -static unsigned long randomize_base(unsigned long base) +unsigned long arch_randomize_brk(struct mm_struct *mm) { + unsigned long base = mm->brk; unsigned long range_end = base + (STACK_RND_MASK << PAGE_SHIFT) + 1; - return randomize_range(base, range_end, 0) ? : base; -} + unsigned long max_stack, range_limit; -unsigned long arch_randomize_brk(struct mm_struct *mm) -{ - return randomize_base(mm->brk); + /* + * Determine how much room we need to leave available for the stack. + * We limit this to a reasonable value, because extremely large or + * unlimited stacks are always going to bump up against brk at some + * point and we don't want to fail to randomise brk in those cases. + */ + max_stack = rlimit(RLIMIT_STACK); + if (max_stack > SZ_128M) + max_stack = SZ_128M; + + range_limit = mm->start_stack - max_stack - 1; + if (range_end > range_limit) + range_end = range_limit; + + return randomize_range(base, range_end, 0) ? : base; }