From patchwork Fri Aug 23 17:23:39 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dave Martin X-Patchwork-Id: 172128 Delivered-To: patch@linaro.org Received: by 2002:a92:d204:0:0:0:0:0 with SMTP id y4csp956731ily; Fri, 23 Aug 2019 10:24:33 -0700 (PDT) X-Google-Smtp-Source: APXvYqzgjLIqpTAKZLymkcgrtAQBb4djduwQz5UEGmTElwvzFrMDDdVrIMKmEn+2/f9GNn3r6Y3+ X-Received: by 2002:a17:902:aa09:: with SMTP id be9mr5869241plb.52.1566581072924; Fri, 23 Aug 2019 10:24:32 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1566581072; cv=none; d=google.com; s=arc-20160816; b=aW+pu1WS13Kl/ojR7hDMRr6q2fZvU98vtK5sQozdnDP5yH5EkU6vEt2a2UbmP2pACy 3B8Pw6jdzyu27TeFDH5INCgr/U4Aojge3bsXr2BPHvlB1I6wjXJNmiNgbpOO1oOMgyGb FTx4WRRhcWJOkXLcLU/mIm87aAtQyGrR+JRRQ/izsLThP/yiXgQR3L1JXcTUYNXT2Dqr r9DvidtZrcrCnfjb/TKzxzCtyXNfhY6JNoKIssOyA3RKQRuiNEf+4RQ923qkeDWoYpE6 iGxVvAhWgbDTc1zSBYDOuzgtEe4G1+2FA4txF0qc/3LR35NbQD/ozniYvCsNrFTaNGzy 5yxg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from; bh=CX8yasXqGFb0Pg9FKEid8Jkjybex60f6joit9P9dnyA=; b=yCjrYX4WlXRGe5vkVNk/Y7UPT3FJ/ems6nSVq7KT71D1V4NaQDHLDFROWUjP9jDaj6 tt6dE5CHNPQ1O6gB/aZUth03I6NjFl1Z1GkosM/AErWwwo3Z+dXG8BJfN8bZgCBxcFkq 4TVRUPl9Yk7V2Zc2Ketwc/32osh5MyYRW+lncYbG3YHpekzL0Hf3HugIa8fcVlDXHc5T 8y6neFjbBK9LUvkAV9dTX0XFaTedAgd/gm6VKnUqruhapxzQ2WtkZAxZmqMkHkul2Am0 douo1bf46jTryDkeMI3yIaS2hfglQYnZASvx0cjAqV0d8rmzDLRozw4MfLDLD94kb5+m AeXg== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id k73si2434330pge.353.2019.08.23.10.24.32; Fri, 23 Aug 2019 10:24:32 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-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 linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2389412AbfHWRYb (ORCPT + 28 others); Fri, 23 Aug 2019 13:24:31 -0400 Received: from foss.arm.com ([217.140.110.172]:37596 "EHLO foss.arm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2388090AbfHWRY1 (ORCPT ); Fri, 23 Aug 2019 13:24:27 -0400 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 3D6C1337; Fri, 23 Aug 2019 10:24:27 -0700 (PDT) Received: from e103592.cambridge.arm.com (usa-sjc-imap-foss1.foss.arm.com [10.121.207.14]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id 053C03F246; Fri, 23 Aug 2019 10:24:25 -0700 (PDT) From: Dave Martin To: linux-kernel@vger.kernel.org Cc: linux-arch@vger.kernel.org, Kees Cook , Thomas Gleixner , Jann Horn , "H.J. Lu" , Eugene Syromiatnikov , Florian Weimer , Yu-cheng Yu , Peter Zijlstra Subject: [RFC PATCH v2 1/2] ELF: UAPI and Kconfig additions for ELF program properties Date: Fri, 23 Aug 2019 18:23:39 +0100 Message-Id: <1566581020-9953-2-git-send-email-Dave.Martin@arm.com> X-Mailer: git-send-email 2.1.4 In-Reply-To: <1566581020-9953-1-git-send-email-Dave.Martin@arm.com> References: <1566581020-9953-1-git-send-email-Dave.Martin@arm.com> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Pull the basic ELF definitions from Yu-Cheng Yu's series. Signed-off-by: Yu-cheng Yu Signed-off-by: Dave Martin --- This patch should be merged with the next patch. I kept it seprate for now to document where this code came from. Changes since RFC v1: * Move struct gnu_property to . There's currently no consensus about exactly what this should look like in the public headers, so keep in private to the kernel for now. Binutils etc. are using their own definitions anyway. --- fs/Kconfig.binfmt | 3 +++ include/linux/elf.h | 8 ++++++++ include/uapi/linux/elf.h | 1 + 3 files changed, 12 insertions(+) -- 2.1.4 diff --git a/fs/Kconfig.binfmt b/fs/Kconfig.binfmt index 62dc4f5..d2cfe07 100644 --- a/fs/Kconfig.binfmt +++ b/fs/Kconfig.binfmt @@ -36,6 +36,9 @@ config COMPAT_BINFMT_ELF config ARCH_BINFMT_ELF_STATE bool +config ARCH_USE_GNU_PROPERTY + bool + config BINFMT_ELF_FDPIC bool "Kernel support for FDPIC ELF binaries" default y if !BINFMT_ELF diff --git a/include/linux/elf.h b/include/linux/elf.h index e3649b3..4485499 100644 --- a/include/linux/elf.h +++ b/include/linux/elf.h @@ -2,6 +2,7 @@ #ifndef _LINUX_ELF_H #define _LINUX_ELF_H +#include #include #include @@ -56,4 +57,11 @@ static inline int elf_coredump_extra_notes_write(struct coredump_params *cprm) { extern int elf_coredump_extra_notes_size(void); extern int elf_coredump_extra_notes_write(struct coredump_params *cprm); #endif + +/* NT_GNU_PROPERTY_TYPE_0 header */ +struct gnu_property { + __u32 pr_type; + __u32 pr_datasz; +}; + #endif /* _LINUX_ELF_H */ diff --git a/include/uapi/linux/elf.h b/include/uapi/linux/elf.h index 34c02e4..c377314 100644 --- a/include/uapi/linux/elf.h +++ b/include/uapi/linux/elf.h @@ -36,6 +36,7 @@ typedef __s64 Elf64_Sxword; #define PT_LOPROC 0x70000000 #define PT_HIPROC 0x7fffffff #define PT_GNU_EH_FRAME 0x6474e550 +#define PT_GNU_PROPERTY 0x6474e553 #define PT_GNU_STACK (PT_LOOS + 0x474e551) From patchwork Fri Aug 23 17:23:40 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dave Martin X-Patchwork-Id: 172129 Delivered-To: patch@linaro.org Received: by 2002:a92:d204:0:0:0:0:0 with SMTP id y4csp956810ily; Fri, 23 Aug 2019 10:24:37 -0700 (PDT) X-Google-Smtp-Source: APXvYqzG+1Lz2qqsqly+tUtPjrR2u6WbtwvZs7H0GZEkJQFW86Yph/4gjzZStouNs1uUBOZ0cfPk X-Received: by 2002:a17:902:f301:: with SMTP id gb1mr5849136plb.249.1566581077371; Fri, 23 Aug 2019 10:24:37 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1566581077; cv=none; d=google.com; s=arc-20160816; b=l0TH69gBd4UF2GeeAH51QURdZQmhkOxL55te1Xi4d2Lw3EoIF6KJcZfILcA9saaKqK fu94fOEEFQEMl224KtTjIloWUz77guanrZs8wjVO6867cg/hUF+GX90LRj74Fndw2U8Q Iwd8EQKJu67IxscXeDDdEtuvylql9qUaCKMDeykZWPBTLSQ+UgfLqLuB71ExyKKmDZiq sKElE05uy6i7RCTA2K1U9hNkXXKg3HrIKTrPlA+aOxCDV8/Rf7+fdw3jrL8Lu3LuNFOS 1QrsxiTTCsnkeoGyhE0tTOgFvhs6AdSqV60SEPrfbN3Xw3IkO6dGk75ROc/ieFHVqqDy BVPQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from; bh=1+Zqh0Xgeev6grhqnqWLo7MVCEZQVi5YWFG3+YVsw94=; b=xOz1RfSPbc6nEANkra9BlU338n7Yg5bahIoU//1e+r/fg4P9ttqcPtRT5XMZWRtD0J lQg3Jb01yy/2c1T40QzMlDwqCodxTCgOzQOUuvF2ZQSItklQMsSDCsY0uSAFQXo+XG3j NvpvxNjdOH+rz0HIyauvgLYet6WRkkq8+JmG68ayxCivzHpfpZTnw/Fml/CMKy3QZmQx NoushEXSbM3qChCiD84X58jI+/1mjgeYU8JCjVwzstuCrQw3gsuqiDqSgVXpD6SI7TtS ZPC8risIbHyaCwrSvbBXhstQYt1Wb77LRu5GFYlSfHqIKAgEe93QUcqO8Y2OmNbmC4es 6o7Q== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id k73si2434330pge.353.2019.08.23.10.24.36; Fri, 23 Aug 2019 10:24:37 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-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 linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2389590AbfHWRYg (ORCPT + 28 others); Fri, 23 Aug 2019 13:24:36 -0400 Received: from foss.arm.com ([217.140.110.172]:37614 "EHLO foss.arm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2389289AbfHWRY3 (ORCPT ); Fri, 23 Aug 2019 13:24:29 -0400 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id AB43C1570; Fri, 23 Aug 2019 10:24:28 -0700 (PDT) Received: from e103592.cambridge.arm.com (usa-sjc-imap-foss1.foss.arm.com [10.121.207.14]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id 720F33F246; Fri, 23 Aug 2019 10:24:27 -0700 (PDT) From: Dave Martin To: linux-kernel@vger.kernel.org Cc: linux-arch@vger.kernel.org, Kees Cook , Thomas Gleixner , Jann Horn , "H.J. Lu" , Eugene Syromiatnikov , Florian Weimer , Yu-cheng Yu , Peter Zijlstra Subject: [RFC PATCH v2 2/2] ELF: Add ELF program property parsing support Date: Fri, 23 Aug 2019 18:23:40 +0100 Message-Id: <1566581020-9953-3-git-send-email-Dave.Martin@arm.com> X-Mailer: git-send-email 2.1.4 In-Reply-To: <1566581020-9953-1-git-send-email-Dave.Martin@arm.com> References: <1566581020-9953-1-git-send-email-Dave.Martin@arm.com> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org ELF program properties will needed for detecting whether to enable optional architecture or ABI features for a new ELF process. For now, there are no generic properties that we care about, so do nothing unless CONFIG_ARCH_USE_GNU_PROPERTY=y. Otherwise, the presence of properties using the PT_PROGRAM_PROPERTY phdrs entry (if any), and notify each property to the arch code. For now, the added code is not used. Signed-off-by: Dave Martin --- Changes since RFC v1: * Fix stupid typo in IS_ENABLED(). * Fix premature dereference of possibly-NULL phdr in parse_elf_properties(). * Demote BUG_ON() to WARN_ON(), and add comments to explain why they should never fire. These are only for development and should probably go away before merge. * Enforce that there are no duplicate properties and that the properties are sorted on pr_type. This is not strictly necessary for kernel safety or for correct handling of valid ELF files, but may help flag up binaries from duff linkers which we would otherwise silently execute. * Shuffle parse_elf_properties() logic to move as many checks as possible into parse_elf_property(). This keeps most checks in the same function as the code that relies on them, and simplifies the outer parsing loop. parse_elf_properties's cursor is now just a byte offset into the note, which makes comparisons more straightfward and reduces the amount of pointer casting a bit. --- fs/binfmt_elf.c | 124 +++++++++++++++++++++++++++++++++++++++++++++++ fs/compat_binfmt_elf.c | 4 ++ include/linux/elf.h | 19 ++++++++ include/uapi/linux/elf.h | 4 ++ 4 files changed, 151 insertions(+) -- 2.1.4 Reviewed-by: Kees Cook diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index d4e11b2..d6541e8 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -39,12 +39,18 @@ #include #include #include +#include +#include #include #include #include #include #include +#ifndef ELF_COMPAT +#define ELF_COMPAT 0 +#endif + #ifndef user_long_t #define user_long_t long #endif @@ -690,6 +696,108 @@ static unsigned long randomize_stack_top(unsigned long stack_top) #endif } +static int parse_elf_property(const char *data, size_t *off, size_t datasz, + struct arch_elf_state *arch, + bool have_prev_type, u32 *prev_type) +{ + size_t size, step; + const struct gnu_property *pr; + int ret; + + if (*off == datasz) + return -ENOENT; + + if (WARN_ON(*off > datasz || *off % elf_gnu_property_align)) + return -EIO; + + size = datasz - *off; + if (size < sizeof(*pr)) + return -EIO; + + pr = (const struct gnu_property *)(data + *off); + if (pr->pr_datasz > size - sizeof(*pr)) + return -EIO; + + step = round_up(sizeof(*pr) + pr->pr_datasz, elf_gnu_property_align); + if (step > size) + return -EIO; + + /* Properties are supposed to be unique and sorted on pr_type: */ + if (have_prev_type && pr->pr_type <= *prev_type) + return -EIO; + *prev_type = pr->pr_type; + + ret = arch_parse_elf_property(pr->pr_type, + data + *off + sizeof(*pr), + pr->pr_datasz, ELF_COMPAT, arch); + if (ret) + return ret; + + *off += step; + return 0; +} + +#define NOTE_DATA_SZ SZ_1K +#define GNU_PROPERTY_TYPE_0_NAME "GNU" +#define NOTE_NAME_SZ (sizeof(GNU_PROPERTY_TYPE_0_NAME)) + +static int parse_elf_properties(struct file *f, const struct elf_phdr *phdr, + struct arch_elf_state *arch) +{ + union { + struct elf_note nhdr; + char data[NOTE_DATA_SZ]; + } note; + loff_t pos; + ssize_t n; + size_t off, datasz; + int ret; + bool have_prev_type; + u32 prev_type; + + if (!IS_ENABLED(CONFIG_ARCH_USE_GNU_PROPERTY) || !phdr) + return 0; + + /* load_elf_binary() shouldn't call us unless this is true... */ + if (WARN_ON(phdr->p_type != PT_GNU_PROPERTY)) + return -EIO; + + /* If the properties are crazy large, that's too bad (for now): */ + if (phdr->p_filesz > sizeof(note)) + return -ENOEXEC; + + pos = phdr->p_offset; + n = kernel_read(f, ¬e, phdr->p_filesz, &pos); + + BUILD_BUG_ON(sizeof(note) < sizeof(note.nhdr) + NOTE_NAME_SZ); + if (n < 0 || n < sizeof(note.nhdr) + NOTE_NAME_SZ) + return -EIO; + + if (note.nhdr.n_type != NT_GNU_PROPERTY_TYPE_0 || + note.nhdr.n_namesz != NOTE_NAME_SZ || + strncmp(note.data + sizeof(note.nhdr), + GNU_PROPERTY_TYPE_0_NAME, n - sizeof(note.nhdr))) + return -EIO; + + off = round_up(sizeof(note.nhdr) + NOTE_NAME_SZ, + elf_gnu_property_align); + if (off > n) + return -EIO; + + if (note.nhdr.n_descsz > n - off) + return -EIO; + datasz = off + note.nhdr.n_descsz; + + have_prev_type = false; + do { + ret = parse_elf_property(note.data, &off, datasz, arch, + have_prev_type, &prev_type); + have_prev_type = true; + } while (!ret); + + return ret == -ENOENT ? 0 : ret; +} + static int load_elf_binary(struct linux_binprm *bprm) { struct file *interpreter = NULL; /* to shut gcc up */ @@ -697,6 +805,7 @@ static int load_elf_binary(struct linux_binprm *bprm) int load_addr_set = 0; unsigned long error; struct elf_phdr *elf_ppnt, *elf_phdata, *interp_elf_phdata = NULL; + struct elf_phdr *elf_property_phdata = NULL; unsigned long elf_bss, elf_brk; int bss_prot = 0; int retval, i; @@ -744,6 +853,11 @@ static int load_elf_binary(struct linux_binprm *bprm) char *elf_interpreter; loff_t pos; + if (elf_ppnt->p_type == PT_GNU_PROPERTY) { + elf_property_phdata = elf_ppnt; + continue; + } + if (elf_ppnt->p_type != PT_INTERP) continue; @@ -839,9 +953,14 @@ static int load_elf_binary(struct linux_binprm *bprm) goto out_free_dentry; /* Pass PT_LOPROC..PT_HIPROC headers to arch code */ + elf_property_phdata = NULL; elf_ppnt = interp_elf_phdata; for (i = 0; i < loc->interp_elf_ex.e_phnum; i++, elf_ppnt++) switch (elf_ppnt->p_type) { + case PT_GNU_PROPERTY: + elf_property_phdata = elf_ppnt; + break; + case PT_LOPROC ... PT_HIPROC: retval = arch_elf_pt_proc(&loc->interp_elf_ex, elf_ppnt, interpreter, @@ -852,6 +971,11 @@ static int load_elf_binary(struct linux_binprm *bprm) } } + retval = parse_elf_properties(interpreter ?: bprm->file, + elf_property_phdata, &arch_state); + if (retval) + goto out_free_dentry; + /* * Allow arch code to reject the ELF at this point, whilst it's * still possible to return an error to the code that invoked diff --git a/fs/compat_binfmt_elf.c b/fs/compat_binfmt_elf.c index b7f9ffa..f9ee476 100644 --- a/fs/compat_binfmt_elf.c +++ b/fs/compat_binfmt_elf.c @@ -17,6 +17,8 @@ #include #include +#define ELF_COMPAT 1 + /* * Rename the basic ELF layout types to refer to the 32-bit class of files. */ @@ -28,11 +30,13 @@ #undef elf_shdr #undef elf_note #undef elf_addr_t +#undef elf_gnu_property_align #define elfhdr elf32_hdr #define elf_phdr elf32_phdr #define elf_shdr elf32_shdr #define elf_note elf32_note #define elf_addr_t Elf32_Addr +#define elf_gnu_property_align elf32_gnu_property_align /* * Some data types as stored in coredump. diff --git a/include/linux/elf.h b/include/linux/elf.h index 4485499..d9779c0 100644 --- a/include/linux/elf.h +++ b/include/linux/elf.h @@ -22,6 +22,9 @@ SET_PERSONALITY(ex) #endif +#define elf32_gnu_property_align 4 +#define elf64_gnu_property_align 8 + #if ELF_CLASS == ELFCLASS32 extern Elf32_Dyn _DYNAMIC []; @@ -32,6 +35,7 @@ extern Elf32_Dyn _DYNAMIC []; #define elf_addr_t Elf32_Off #define Elf_Half Elf32_Half #define Elf_Word Elf32_Word +#define elf_gnu_property_align elf32_gnu_property_align #else @@ -43,6 +47,7 @@ extern Elf64_Dyn _DYNAMIC []; #define elf_addr_t Elf64_Off #define Elf_Half Elf64_Half #define Elf_Word Elf64_Word +#define elf_gnu_property_align elf64_gnu_property_align #endif @@ -64,4 +69,18 @@ struct gnu_property { __u32 pr_datasz; }; +struct arch_elf_state; + +#ifndef CONFIG_ARCH_USE_GNU_PROPERTY +static inline int arch_parse_elf_property(u32 type, const void *data, + size_t datasz, bool compat, + struct arch_elf_state *arch) +{ + return 0; +} +#else +extern int arch_parse_elf_property(u32 type, const void *data, size_t datasz, + bool compat, struct arch_elf_state *arch); +#endif + #endif /* _LINUX_ELF_H */ diff --git a/include/uapi/linux/elf.h b/include/uapi/linux/elf.h index c377314..20900f4 100644 --- a/include/uapi/linux/elf.h +++ b/include/uapi/linux/elf.h @@ -368,6 +368,7 @@ typedef struct elf64_shdr { * Notes used in ET_CORE. Architectures export some of the arch register sets * using the corresponding note types via the PTRACE_GETREGSET and * PTRACE_SETREGSET requests. + * The note name for all these is "LINUX". */ #define NT_PRSTATUS 1 #define NT_PRFPREG 2 @@ -430,6 +431,9 @@ typedef struct elf64_shdr { #define NT_MIPS_FP_MODE 0x801 /* MIPS floating-point mode */ #define NT_MIPS_MSA 0x802 /* MIPS SIMD registers */ +/* Note types with note name "GNU" */ +#define NT_GNU_PROPERTY_TYPE_0 5 + /* Note header in a PT_NOTE section */ typedef struct elf32_note { Elf32_Word n_namesz; /* Name size */