From patchwork Thu Aug 20 17:05:40 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chris Kennelly X-Patchwork-Id: 11726863 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 3469E913 for ; Thu, 20 Aug 2020 17:10:25 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 18269208C7 for ; Thu, 20 Aug 2020 17:10:25 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=google.com header.i=@google.com header.b="JAoLsfvQ" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730476AbgHTRKC (ORCPT ); Thu, 20 Aug 2020 13:10:02 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43024 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1730400AbgHTRGy (ORCPT ); Thu, 20 Aug 2020 13:06:54 -0400 Received: from mail-qt1-x84a.google.com (mail-qt1-x84a.google.com [IPv6:2607:f8b0:4864:20::84a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 25654C061348 for ; Thu, 20 Aug 2020 10:05:53 -0700 (PDT) Received: by mail-qt1-x84a.google.com with SMTP id m88so1974356qtd.15 for ; Thu, 20 Aug 2020 10:05:53 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=sender:date:in-reply-to:message-id:mime-version:references:subject :from:to:cc; bh=Iv89Xj9r4G2AFHTvNFTUszt55oudaNNsbG7Jzt5MM3M=; b=JAoLsfvQ4br/TgUsmWn9DiWKTa+gHnJlRKDqSlFzX5V673qRD69mVU//vMYNLqeytr rhFyPscW3spdsfTlmOmV0nDCn+n1FekpqqrNOrpaPaUUDFPyK2yaaGgjnubuGAFXfgOZ 4RN2pffxWbl/Vt9OuWgk4OiLFRcn+ZneSYLa3l8/scg3+pGjlXbiE0IEgtCx62jc46ib dtjdcsceajNguBonA3n67SB27pzahfP4nEEXTjzZUXBgq6Cze40JodWRpNDL1p68sZMo 4pt1nbmOJkkOV9mUv901MxLQQu5ovydCHcUgt1ALfMQw7OjMdo6PynVY+OtkRA0EdKUh uRLA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=Iv89Xj9r4G2AFHTvNFTUszt55oudaNNsbG7Jzt5MM3M=; b=BTRb16wZpqf1+I2Qv18/lYqRMAaZhS5E+vmoOd1Max0eWriLQMzIqvFWf/Kh8gfDZd k8tSyon3VoASC1qHNWn10lpM+dfjrOv00G2zh3ew9kQATO6qCFrKGzgTpc9rhuFI1hjD BicN0je29XZWKDhvRTVMHU1UgE2a4LRw2Q23INW6wcr+bAlPpLYQCZV5fiMZKPs6TFJS wcYCstvT0rnlwSGaMyvvhAA0skJgsp5bcqxQSdqHR6ZWFSLAWcyhXhV385pmseocWcqh B3hbHJ2yJOtyGLOJnuI+yNu8i9TovzUvkaHvGPJWQyEFqZ7tGW3ytIuKVuLEQjVT4wGT edhw== X-Gm-Message-State: AOAM530ehCMlnMXB9L9WB0yoC+kH9EEobDkVWIPlcyLTrYF7WH2QQHLb 18kOZNwWb1j7J89iHMZQ0PN9IyfEmnSWfXE= X-Google-Smtp-Source: ABdhPJyAeDAmjp/cOMLYBlzKs+yr6QsVC8gvT2N9bGSimDFXyKsgrBOjYXHKDZ2UXbzrYoObhj6uF80NWOzZdd4= X-Received: from ckennelly28.nyc.corp.google.com ([2620:0:1003:1003:3e52:82ff:fe5a:a91a]) (user=ckennelly job=sendgmr) by 2002:a05:6214:1910:: with SMTP id er16mr3766114qvb.228.1597943152055; Thu, 20 Aug 2020 10:05:52 -0700 (PDT) Date: Thu, 20 Aug 2020 13:05:40 -0400 In-Reply-To: <20200820170541.1132271-1-ckennelly@google.com> Message-Id: <20200820170541.1132271-2-ckennelly@google.com> Mime-Version: 1.0 References: <20200820170541.1132271-1-ckennelly@google.com> X-Mailer: git-send-email 2.28.0.297.g1956fa8f8d-goog Subject: [PATCH v3 1/2] fs/binfmt_elf: Use PT_LOAD p_align values for suitable start address. From: Chris Kennelly To: Alexander Viro , Alexey Dobriyan , Song Liu Cc: David Rientjes , Ian Rogers , Hugh Dickens , Andrew Morton , Suren Baghdasaryan , Sandeep Patil , Fangrui Song , Nick Desaulniers , clang-built-linux@googlegroups.com, linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, Chris Kennelly Sender: linux-fsdevel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@vger.kernel.org The current ELF loading mechancism provides page-aligned mappings. This can lead to the program being loaded in a way unsuitable for file-backed, transparent huge pages when handling PIE executables. For binaries built with increased alignment, this limits the number of bits usable for ASLR, but provides some randomization over using fixed load addresses/non-PIE binaries. Tested: verified program with -Wl,-z,max-page-size=0x200000 loading Signed-off-by: Chris Kennelly --- fs/binfmt_elf.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 13d053982dd73..a980dc3704639 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -421,6 +422,24 @@ static int elf_read(struct file *file, void *buf, size_t len, loff_t pos) return 0; } +static unsigned long maximum_alignment(struct elf_phdr *cmds, int nr) +{ + unsigned long alignment = 0; + int i; + + for (i = 0; i < nr; i++) { + if (cmds[i].p_type == PT_LOAD) { + /* skip non-power of two alignments */ + if (!is_power_of_2(cmds[i].p_align)) + continue; + alignment = max(alignment, cmds[i].p_align); + } + } + + /* ensure we align to at least one page */ + return ELF_PAGEALIGN(alignment); +} + /** * load_elf_phdrs() - load ELF program headers * @elf_ex: ELF header of the binary whose program headers should be loaded @@ -1008,6 +1027,7 @@ static int load_elf_binary(struct linux_binprm *bprm) int elf_prot, elf_flags; unsigned long k, vaddr; unsigned long total_size = 0; + unsigned long alignment; if (elf_ppnt->p_type != PT_LOAD) continue; @@ -1086,6 +1106,9 @@ static int load_elf_binary(struct linux_binprm *bprm) load_bias = ELF_ET_DYN_BASE; if (current->flags & PF_RANDOMIZE) load_bias += arch_mmap_rnd(); + alignment = maximum_alignment(elf_phdata, elf_ex->e_phnum); + if (alignment) + load_bias &= ~(alignment - 1); elf_flags |= MAP_FIXED; } else load_bias = 0; From patchwork Thu Aug 20 17:05:41 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chris Kennelly X-Patchwork-Id: 11726859 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 28DA2913 for ; Thu, 20 Aug 2020 17:09:52 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 0F03C208B3 for ; Thu, 20 Aug 2020 17:09:52 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=google.com header.i=@google.com header.b="IQxhLKQz" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730470AbgHTRJt (ORCPT ); Thu, 20 Aug 2020 13:09:49 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43038 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1730405AbgHTRG6 (ORCPT ); Thu, 20 Aug 2020 13:06:58 -0400 Received: from mail-qk1-x749.google.com (mail-qk1-x749.google.com [IPv6:2607:f8b0:4864:20::749]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id BA4F8C06134A for ; Thu, 20 Aug 2020 10:05:54 -0700 (PDT) Received: by mail-qk1-x749.google.com with SMTP id n128so1644508qke.2 for ; Thu, 20 Aug 2020 10:05:54 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=sender:date:in-reply-to:message-id:mime-version:references:subject :from:to:cc; bh=TSLmEPwlFccaRVuUrhKv3FaWDdmO/JVWcm6IHHbjArg=; b=IQxhLKQzVwP0KfRd3Pxusat2zuJXNWxSnetqcoJjEmjg6JYB5IlUOQbPP/AoZyFPkq WT7YDdzd9pR675DhQ7Jv2wWLSbjv95xYAi/Q1SnDTc67zJHbvGwHMDwOD+D60a53Xm5G m+qmz4GM91iSdhxOX6FJ8SKJizHlgiBu6fpxwUCDggo2KKVUJfWWgjXLwuUMPQRdQhYc mLEY+xaTMF0LajircdB5xwjhf+my/lFMchNajJn7yPIXaZJi7iK23yJ1H4n4Wg4+gkCr Uu4zr0coaktldxBJNc1wcvhs8glYdWdURQUh9yqXoXDEz/p0X8w55uUyi4fzSSDuXf3y 5lqg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=TSLmEPwlFccaRVuUrhKv3FaWDdmO/JVWcm6IHHbjArg=; b=X7123MkmYKEqvA2jGTkSclK0CsDHWjatEzj/1CogrhY2wZPaRCl4syfe8oYw/1NZlM UxqhfXZKiVoQ87kMY/aFhJPwguhhFRwQc5vMa6S/8hmqTjMja6emEYSTcpxR4qe1TxIl wQ9QZh61eQ7gIcUYVRmCYip93hlp4M5ytA6G/TZiBZxlESY9yIg/58MG5+NL+p01uimt LFn3IzcBzA6/Cq0hEIhtpkMbDZGXsKMcGJJzpb/GyK+bzzJGHNHyrlapVveD3J0tFqVZ P45mAhp+K/gaJSB+UwqKeso1IkpUTMx7oRwuv5xSF40YOESBS7bcRwn3aDlvP+8uSdjA wBWg== X-Gm-Message-State: AOAM533+MLyoRCDZQk4ynO0Yn9cY4EJD2iRZjZ+NzuLy+KRM9Lr+w+AJ frsy0weZrSXcTq4IsrbVz7anJBsrdyjtwOs= X-Google-Smtp-Source: ABdhPJygXfncfS/0/GMyGN6IEog77U5++V0HYUNA1HpjGL1sVvQW+wDkctEyZr/Lj2VhjuVrDzHMWkVPFzeqx24= X-Received: from ckennelly28.nyc.corp.google.com ([2620:0:1003:1003:3e52:82ff:fe5a:a91a]) (user=ckennelly job=sendgmr) by 2002:a05:6214:108a:: with SMTP id o10mr3962299qvr.239.1597943153890; Thu, 20 Aug 2020 10:05:53 -0700 (PDT) Date: Thu, 20 Aug 2020 13:05:41 -0400 In-Reply-To: <20200820170541.1132271-1-ckennelly@google.com> Message-Id: <20200820170541.1132271-3-ckennelly@google.com> Mime-Version: 1.0 References: <20200820170541.1132271-1-ckennelly@google.com> X-Mailer: git-send-email 2.28.0.297.g1956fa8f8d-goog Subject: [PATCH v3 2/2] Add self-test for verifying load alignment. From: Chris Kennelly To: Alexander Viro , Alexey Dobriyan , Song Liu Cc: David Rientjes , Ian Rogers , Hugh Dickens , Andrew Morton , Suren Baghdasaryan , Sandeep Patil , Fangrui Song , Nick Desaulniers , clang-built-linux@googlegroups.com, linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, Chris Kennelly Sender: linux-fsdevel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@vger.kernel.org This produces a PIE binary with a variety of p_align requirements, suitable for verifying that the load address meets that alignment requirement. Signed-off-by: Chris Kennelly --- tools/testing/selftests/exec/.gitignore | 1 + tools/testing/selftests/exec/Makefile | 9 ++- tools/testing/selftests/exec/load_address.c | 68 +++++++++++++++++++++ 3 files changed, 76 insertions(+), 2 deletions(-) create mode 100644 tools/testing/selftests/exec/load_address.c diff --git a/tools/testing/selftests/exec/.gitignore b/tools/testing/selftests/exec/.gitignore index 344a99c6da1b7..9e2f00343f15f 100644 --- a/tools/testing/selftests/exec/.gitignore +++ b/tools/testing/selftests/exec/.gitignore @@ -7,6 +7,7 @@ execveat.moved execveat.path.ephemeral execveat.ephemeral execveat.denatured +/load_address_* /recursion-depth xxxxxxxx* pipe diff --git a/tools/testing/selftests/exec/Makefile b/tools/testing/selftests/exec/Makefile index 0a13b110c1e66..cf69b2fcce59e 100644 --- a/tools/testing/selftests/exec/Makefile +++ b/tools/testing/selftests/exec/Makefile @@ -4,7 +4,7 @@ CFLAGS += -Wno-nonnull CFLAGS += -D_GNU_SOURCE TEST_PROGS := binfmt_script non-regular -TEST_GEN_PROGS := execveat +TEST_GEN_PROGS := execveat load_address_4096 load_address_2097152 load_address_16777216 TEST_GEN_FILES := execveat.symlink execveat.denatured script subdir pipe # Makefile is a run-time dependency, since it's accessed by the execveat test TEST_FILES := Makefile @@ -27,4 +27,9 @@ $(OUTPUT)/execveat.symlink: $(OUTPUT)/execveat $(OUTPUT)/execveat.denatured: $(OUTPUT)/execveat cp $< $@ chmod -x $@ - +$(OUTPUT)/load_address_4096: load_address.c + $(CC) $(CFLAGS) $(LDFLAGS) -Wl,-z,max-page-size=0x1000 -pie $< -o $@ +$(OUTPUT)/load_address_2097152: load_address.c + $(CC) $(CFLAGS) $(LDFLAGS) -Wl,-z,max-page-size=0x200000 -pie $< -o $@ +$(OUTPUT)/load_address_16777216: load_address.c + $(CC) $(CFLAGS) $(LDFLAGS) -Wl,-z,max-page-size=0x1000000 -pie $< -o $@ diff --git a/tools/testing/selftests/exec/load_address.c b/tools/testing/selftests/exec/load_address.c new file mode 100644 index 0000000000000..d487c2f6a6150 --- /dev/null +++ b/tools/testing/selftests/exec/load_address.c @@ -0,0 +1,68 @@ +// SPDX-License-Identifier: GPL-2.0-only +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif +#include +#include +#include + +struct Statistics { + unsigned long long load_address; + unsigned long long alignment; +}; + +int ExtractStatistics(struct dl_phdr_info *info, size_t size, void *data) +{ + struct Statistics *stats = (struct Statistics *) data; + int i; + + if (info->dlpi_name != NULL && info->dlpi_name[0] != '\0') { + // Ignore headers from other than the executable. + return 2; + } + + stats->load_address = (unsigned long long) info->dlpi_addr; + stats->alignment = 0; + + for (i = 0; i < info->dlpi_phnum; i++) { + if (info->dlpi_phdr[i].p_type != PT_LOAD) + continue; + + if (info->dlpi_phdr[i].p_align > stats->alignment) + stats->alignment = info->dlpi_phdr[i].p_align; + } + + return 1; // Terminate dl_iterate_phdr. +} + +int main(int argc, char **argv) +{ + struct Statistics extracted; + unsigned long long misalign; + int ret; + + ret = dl_iterate_phdr(ExtractStatistics, &extracted); + if (ret != 1) { + fprintf(stderr, "FAILED\n"); + return 1; + } + + if (extracted.alignment == 0) { + fprintf(stderr, "No alignment found\n"); + return 1; + } else if (extracted.alignment & (extracted.alignment - 1)) { + fprintf(stderr, "Alignment is not a power of 2\n"); + return 1; + } + + misalign = extracted.load_address & (extracted.alignment - 1); + if (misalign) { + printf("alignment = %llu, load_address = %llu\n", + extracted.alignment, extracted.load_address); + fprintf(stderr, "FAILED\n"); + return 1; + } + + fprintf(stderr, "PASS\n"); + return 0; +}