From patchwork Fri Jun 23 20:59:56 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kees Cook X-Patchwork-Id: 9807325 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id A6DA260349 for ; Fri, 23 Jun 2017 21:07:14 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id A6B15223C7 for ; Fri, 23 Jun 2017 21:07:11 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 9A69F285A8; Fri, 23 Jun 2017 21:07:11 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-1.9 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID autolearn=unavailable version=3.3.1 Received: from bombadil.infradead.org (bombadil.infradead.org [65.50.211.133]) (using TLSv1.2 with cipher AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id F23C0223C7 for ; Fri, 23 Jun 2017 21:07:10 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:MIME-Version:Cc:List-Subscribe: List-Help:List-Post:List-Archive:List-Unsubscribe:List-Id:References: In-Reply-To:Message-Id:Date:Subject:To:From:Reply-To:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Owner; bh=dp3JoYaqn/hiMrP1R1OXiAUUKtZyHQDcZr/7c+E8MKI=; b=RkzNoNVfyT74T/opxD0i4pWoye f/0W6AptYCt7SK5k/xkSqkvwea2P+gHH6/vdmDnAE1GSChvUYvkg9rutK9atfDltC5u/2FQzvGYQu I2xjvXMjWzAY1G4a95wju8uutJw++UNdX5U3ixKrQZ+vvvEp7t8AhS2y6TebaQzee8qAqdvUaIR8G gH0iCw1HZkZiGFUhSVFonr8WcppWeyEvAusqouc+gfh0sThTD2Oob/szSHBQiEav6fFJfp2BBRQZ4 KfQlSTLsZMtoT1OCeYOo7F0N7VKPutcIZs4wwsOOVnm3XTcEahKGMnuZhvsgtZUD+gWHaW75ORqOX dxihMx1Q==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.87 #1 (Red Hat Linux)) id 1dOVnG-0002AV-LM; Fri, 23 Jun 2017 21:07:06 +0000 Received: from mail-pg0-x234.google.com ([2607:f8b0:400e:c05::234]) by bombadil.infradead.org with esmtps (Exim 4.87 #1 (Red Hat Linux)) id 1dOVgx-0007v1-17 for linux-arm-kernel@lists.infradead.org; Fri, 23 Jun 2017 21:00:36 +0000 Received: by mail-pg0-x234.google.com with SMTP id e187so25661696pgc.1 for ; Fri, 23 Jun 2017 14:00:14 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=NFyoaip5mpnN6gBUM3SgF5Ukjr88ow8vgNDorbGs/Rg=; b=CYyxj8tVDQ5V74S25XWboQYCxy53CHuftJga916LiX9v1tBoyWaAbpNA5+qKJ4jt0L Fy5q2bZ/cstH4BmrVWYS3O4fEtknmF1Etw73ViT2dFQnZNVKdwP7Z1Fqz1kGbX5wDp4N FwyPRoCQmqgCCrHKDcHGtaVsfT6eVcWH+YYF0= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=NFyoaip5mpnN6gBUM3SgF5Ukjr88ow8vgNDorbGs/Rg=; b=RNiTLUurMK2sl2Dohwjm92hJUIyfDmPSgE12+j7QymuqBAQ4VEx2YmpLI5pqvLV6hN /Dz4b2eTBoVcmrX5zHnW1FO+Tg87p6n+XI8oO3Lhce/tErSwnuz0Nr8ll5CZgWanE9LC 7yMxfFD7fUh/aQngaP45PdwtcIPqOD1RR22f2DKJQI9oy/Sv+QPVk83LFyipJbEc1a9R PfTFCJCfykEWc7QUTq2Da/UItCctiNP9SZ5b5pmq/px/AvPNCMiqOWLKRaq3f+us+Jey 3vZ1zkx46VJY2Std9Y1BU02bXh6vcYQ/LX05nBp2KmB73IlepYq2olp3qGjJ7Gq+FrSv AOgw== X-Gm-Message-State: AKS2vOyhQioAdifwmnkbjPAbQlAjwG9qF4yOekz1PYr/LxOAD8Y83/+S AoQLaT6hizX7/e0H X-Received: by 10.98.24.202 with SMTP id 193mr7658586pfy.24.1498251611621; Fri, 23 Jun 2017 14:00:11 -0700 (PDT) Received: from www.outflux.net (173-164-112-133-Oregon.hfc.comcastbusiness.net. [173.164.112.133]) by smtp.gmail.com with ESMTPSA id v21sm12059562pfk.75.2017.06.23.14.00.08 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 23 Jun 2017 14:00:08 -0700 (PDT) From: Kees Cook To: Andrew Morton Subject: [PATCH v2 1/5] binfmt_elf: Use ELF_ET_DYN_BASE only for PIE Date: Fri, 23 Jun 2017 13:59:56 -0700 Message-Id: <1498251600-132458-2-git-send-email-keescook@chromium.org> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1498251600-132458-1-git-send-email-keescook@chromium.org> References: <1498251600-132458-1-git-send-email-keescook@chromium.org> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20170623_140035_128610_7BA6403A X-CRM114-Status: GOOD ( 25.25 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Grzegorz Andrejczuk , kernel-hardening@lists.openwall.com, Catalin Marinas , Heiko Carstens , Masahiro Yamada , Paul Mackerras , "H. Peter Anvin" , Pratyush Anand , linux-s390@vger.kernel.org, Michael Ellerman , x86@kernel.org, Russell King , Ingo Molnar , Benjamin Herrenschmidt , Qualys Security Advisory , Rik van Riel , James Hogan , Kees Cook , Will Deacon , linux-fsdevel@vger.kernel.org, Alexander Viro , Thomas Gleixner , linux-arm-kernel@lists.infradead.org, Ard Biesheuvel , Dmitry Safonov , linux-kernel@vger.kernel.org, stable@vger.kernel.org, Daniel Micay , Martin Schwidefsky , linuxppc-dev@lists.ozlabs.org MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Virus-Scanned: ClamAV using ClamSMTP The ELF_ET_DYN_BASE position was originally intended to keep loaders away from ET_EXEC binaries. (For example, running "/lib/ld-linux.so.2 /bin/cat" might cause the subsequent load of /bin/cat into where the loader had been loaded.) With the advent of PIE (ET_DYN binaries with an INTERP Program Header), ELF_ET_DYN_BASE continued to be used since the kernel was only looking at ET_DYN. However, since ELF_ET_DYN_BASE is traditionally set at the top 1/3rd of the TASK_SIZE, a substantial portion of the address space is unused. For 32-bit tasks when RLIMIT_STACK is set to RLIM_INFINITY, programs are loaded below the mmap region. This means they can be made to collide (CVE-2017-1000370) or nearly collide (CVE-2017-1000371) with pathological stack regions. Lowering ELF_ET_DYN_BASE solves both by moving programs above the mmap region in all cases, and will now additionally avoid programs falling back to the mmap region by enforcing MAP_FIXED for program loads (i.e. if it would have collided with the stack, now it will fail to load instead of falling back to the mmap region). To allow for a lower ELF_ET_DYN_BASE, loaders (ET_DYN without INTERP) are loaded into the mmap region, leaving space available for either an ET_EXEC binary with a fixed location or PIE being loaded into mmap by the loader. Only PIE programs are loaded offset from ELF_ET_DYN_BASE, which means architectures can now safely lower their values without risk of loaders colliding with their subsequently loaded programs. For 64-bit, ELF_ET_DYN_BASE is best set to 4GB to allow runtimes to use the entire 32-bit address space for 32-bit pointers. For 32-bit, 4MB is used as the traditional minimum load location, likely to avoid historically requiring a 4MB page table entry when only a portion of the first 4MB would be used (since the NULL address is avoided). Thanks to PaX Team, Daniel Micay, and Rik van Riel for inspiration and suggestions on how to implement this solution. Fixes: d1fd836dcf00 ("mm: split ET_DYN ASLR from mmap ASLR") Cc: stable@vger.kernel.org Cc: x86@kernel.org Signed-off-by: Kees Cook Acked-by: Rik van Riel --- arch/x86/include/asm/elf.h | 13 +++++----- fs/binfmt_elf.c | 59 +++++++++++++++++++++++++++++++++++++++------- 2 files changed, 58 insertions(+), 14 deletions(-) diff --git a/arch/x86/include/asm/elf.h b/arch/x86/include/asm/elf.h index e8ab9a46bc68..1c18d83d3f09 100644 --- a/arch/x86/include/asm/elf.h +++ b/arch/x86/include/asm/elf.h @@ -245,12 +245,13 @@ extern int force_personality32; #define CORE_DUMP_USE_REGSET #define ELF_EXEC_PAGESIZE 4096 -/* This is the location that an ET_DYN program is loaded if exec'ed. Typical - use of this is to invoke "./ld.so someprog" to test out a new version of - the loader. We need to make sure that it is out of the way of the program - that it will "exec", and that there is sufficient room for the brk. */ - -#define ELF_ET_DYN_BASE (TASK_SIZE / 3 * 2) +/* + * This is the base location for PIE (ET_DYN with INTERP) loads. On + * 64-bit, this is raised to 4GB to leave the entire 32-bit address + * space open for things that want to use the area for 32-bit pointers. + */ +#define ELF_ET_DYN_BASE (mmap_is_ia32() ? 0x000400000UL : \ + 0x100000000UL) /* This yields a mask that user programs can use to figure out what instruction set this CPU supports. This could be done in user space, diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index ef4fb234bb5b..879ff9c7ffd0 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -925,17 +925,60 @@ static int load_elf_binary(struct linux_binprm *bprm) elf_flags = MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE; vaddr = elf_ppnt->p_vaddr; + /* + * If we are loading ET_EXEC or we have already performed + * the ET_DYN load_addr calculations, proceed normally. + */ if (loc->elf_ex.e_type == ET_EXEC || load_addr_set) { elf_flags |= MAP_FIXED; } else if (loc->elf_ex.e_type == ET_DYN) { - /* Try and get dynamic programs out of the way of the - * default mmap base, as well as whatever program they - * might try to exec. This is because the brk will - * follow the loader, and is not movable. */ - load_bias = ELF_ET_DYN_BASE - vaddr; - if (current->flags & PF_RANDOMIZE) - load_bias += arch_mmap_rnd(); - load_bias = ELF_PAGESTART(load_bias); + /* + * This logic is run once for the first LOAD Program + * Header for ET_DYN binaries to calculate the + * randomization (load_bias) for all the LOAD + * Program Headers, and to calculate the entire + * size of the ELF mapping (total_size). (Note that + * load_addr_set is set to true later once the + * initial mapping is performed.) + * + * There are effectively two types of ET_DYN + * binaries: programs (i.e. PIE: ET_DYN with INTERP) + * and loaders (ET_DYN without INTERP, since they + * _are_ the ELF interpreter). The loaders must + * be loaded away from programs since the program + * may otherwise collide with the loader (especially + * for ET_EXEC which does not have a randomized + * position). For example to handle invocations of + * "./ld.so someprog" to test out a new version of + * the loader, the subsequent program that the + * loader loads must avoid the loader itself, so + * they cannot share the same load range. Sufficient + * room for the brk must be allocated with the + * loader as well, since brk must be available with + * the loader. + * + * Therefore, programs are loaded offset from + * ELF_ET_DYN_BASE and loaders are loaded into the + * independently randomized mmap region (0 load_bias + * without MAP_FIXED). + */ + if (elf_interpreter) { + load_bias = ELF_ET_DYN_BASE; + if (current->flags & PF_RANDOMIZE) + load_bias += arch_mmap_rnd(); + elf_flags |= MAP_FIXED; + } else + load_bias = 0; + + /* + * Since load_bias is used for all subsequent loading + * calculations, we must lower it by the first vaddr + * so that the remaining calculations based on the + * ELF vaddrs will be correctly offset. The result + * is then page aligned. + */ + load_bias = ELF_PAGESTART(load_bias - vaddr); + total_size = total_mapping_size(elf_phdata, loc->elf_ex.e_phnum); if (!total_size) {