linux-api.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Yu-cheng Yu <yu-cheng.yu@intel.com>
To: x86@kernel.org, "H. Peter Anvin" <hpa@zytor.com>,
	Thomas Gleixner <tglx@linutronix.de>,
	Ingo Molnar <mingo@redhat.com>,
	linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org,
	linux-mm@kvack.org, linux-arch@vger.kernel.org,
	linux-api@vger.kernel.org, Arnd Bergmann <arnd@arndb.de>,
	Andy Lutomirski <luto@amacapital.net>,
	Balbir Singh <bsingharora@gmail.com>,
	Borislav Petkov <bp@alien8.de>,
	Cyrill Gorcunov <gorcunov@gmail.com>,
	Dave Hansen <dave.hansen@linux.intel.com>,
	Eugene Syromiatnikov <esyr@redhat.com>,
	Florian Weimer <fweimer@redhat.com>,
	"H.J. Lu" <hjl.tools@gmail.com>, Jann Horn <jannh@google.com>,
	Jonathan Corbet <corbet@lwn.net>,
	Kees Cook <keescook@chromium.org>,
	Mike Kravetz <mike.kravetz@oracle.com>,
	Nadav Amit <nadav.amit@gmail.com>
Cc: Yu-cheng Yu <yu-cheng.yu@intel.com>
Subject: [PATCH v8 22/27] binfmt_elf: Extract .note.gnu.property from an ELF file
Date: Tue, 13 Aug 2019 13:52:20 -0700	[thread overview]
Message-ID: <20190813205225.12032-23-yu-cheng.yu@intel.com> (raw)
In-Reply-To: <20190813205225.12032-1-yu-cheng.yu@intel.com>

An ELF file's .note.gnu.property indicates features the executable file
can support.  For example, the property GNU_PROPERTY_X86_FEATURE_1_AND
indicates the file supports GNU_PROPERTY_X86_FEATURE_1_IBT and/or
GNU_PROPERTY_X86_FEATURE_1_SHSTK.

With this patch, if an arch needs to setup features from ELF properties,
it needs CONFIG_ARCH_USE_GNU_PROPERTY to be set, and specific
arch_parse_property() and arch_setup_property().

For example, for X86_64:

int arch_setup_property(void *ehdr, void *phdr, struct file *f, bool inter)
{
	int r;
	uint32_t property;

	r = get_gnu_property(ehdr, phdr, f, GNU_PROPERTY_X86_FEATURE_1_AND,
			     &property);
	...
}

This patch is derived from code provided by H.J. Lu <hjl.tools@gmail.com>.

Signed-off-by: Yu-cheng Yu <yu-cheng.yu@intel.com>
---
 fs/Kconfig.binfmt        |   3 +
 fs/Makefile              |   1 +
 fs/binfmt_elf.c          |  20 +++++
 fs/gnu_property.c        | 178 +++++++++++++++++++++++++++++++++++++++
 include/linux/elf.h      |  11 +++
 include/uapi/linux/elf.h |  14 +++
 6 files changed, 227 insertions(+)
 create mode 100644 fs/gnu_property.c

diff --git a/fs/Kconfig.binfmt b/fs/Kconfig.binfmt
index 62dc4f577ba1..d2cfe0729a73 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/fs/Makefile b/fs/Makefile
index d60089fd689b..939b1eb7e8cc 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -44,6 +44,7 @@ obj-$(CONFIG_BINFMT_ELF)	+= binfmt_elf.o
 obj-$(CONFIG_COMPAT_BINFMT_ELF)	+= compat_binfmt_elf.o
 obj-$(CONFIG_BINFMT_ELF_FDPIC)	+= binfmt_elf_fdpic.o
 obj-$(CONFIG_BINFMT_FLAT)	+= binfmt_flat.o
+obj-$(CONFIG_ARCH_USE_GNU_PROPERTY) += gnu_property.o
 
 obj-$(CONFIG_FS_MBCACHE)	+= mbcache.o
 obj-$(CONFIG_FS_POSIX_ACL)	+= posix_acl.o
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index d4e11b2e04f6..a4e87fcb10a8 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -852,6 +852,21 @@ static int load_elf_binary(struct linux_binprm *bprm)
 			}
 	}
 
+	if (interpreter) {
+		retval = arch_parse_property(&loc->interp_elf_ex,
+					     interp_elf_phdata,
+					     interpreter, true,
+					     &arch_state);
+	} else {
+		retval = arch_parse_property(&loc->elf_ex,
+					     elf_phdata,
+					     bprm->file, false,
+					     &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
@@ -1080,6 +1095,11 @@ static int load_elf_binary(struct linux_binprm *bprm)
 		goto out_free_dentry;
 	}
 
+	retval = arch_setup_property(&arch_state);
+
+	if (retval < 0)
+		goto out_free_dentry;
+
 	if (interpreter) {
 		unsigned long interp_map_addr = 0;
 
diff --git a/fs/gnu_property.c b/fs/gnu_property.c
new file mode 100644
index 000000000000..b22b43f4d6a0
--- /dev/null
+++ b/fs/gnu_property.c
@@ -0,0 +1,178 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Extract an ELF file's .note.gnu.property.
+ *
+ * The path from the ELF header to .note.gnu.property is:
+ *	elfhdr->elf_phdr->elf_note.
+ *
+ * .note.gnu.property layout:
+ *
+ *	struct elf_note {
+ *		u32 n_namesz; --> sizeof(n_name[]); always (4)
+ *		u32 n_ndescsz;--> sizeof(property[])
+ *		u32 n_type;   --> always NT_GNU_PROPERTY_TYPE_0 (5)
+ *	};
+ *	char n_name[4]; --> always 'GNU\0'
+ *
+ *	struct {
+ *		struct gnu_property {
+ *			u32 pr_type;
+ *			u32 pr_datasz;
+ *		};
+ *		u8 pr_data[pr_datasz];
+ *	}[];
+ */
+
+#include <linux/elf.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/string.h>
+#include <linux/compat.h>
+
+/*
+ * Search a note's payload for 'pr_type'.
+ */
+static int check_note_payload(void *buf, unsigned long len, u32 pr_type,
+			      u32 *property)
+{
+	u32 pr_type_max = 0;
+
+	*property = 0;
+
+	while (len > 0) {
+		struct gnu_property *pr = buf;
+		unsigned long pr_len;
+
+		if (sizeof(*pr) > len)
+			return 0;
+
+		pr_len = sizeof(*pr) + pr->pr_datasz;
+
+		if (pr_len > len)
+			return -ENOEXEC;
+
+		/* property types are in ascending order */
+		if ((pr_type_max != 0) && (pr->pr_type > pr_type_max))
+			return 0;
+
+		if (pr->pr_type > pr_type)
+			return 0;
+
+		if ((pr->pr_type == pr_type) &&
+		    (pr->pr_datasz >= sizeof(u32))) {
+			*property = *(u32 *)(buf + sizeof(*pr));
+			return 0;
+		}
+
+		if (pr->pr_type > pr_type_max)
+			pr_type_max = pr->pr_type;
+
+		buf += pr_len;
+		len -= pr_len;
+	}
+
+	return 0;
+}
+
+/*
+ * Look at an ELF file's NT_GNU_PROPERTY for the property of pr_type.
+ *
+ * Input:
+ *	buf: the buffer containing the whole note.
+ *	len: size of buf.
+ *	align: alignment of the note's payload.
+ *	pr_type: the property type.
+ *
+ * Output:
+ *	The property found.
+ *
+ * Return:
+ *	Zero or error.
+ */
+static int check_note(void *buf, unsigned long len, int align,
+			  u32 pr_type, u32 *property)
+{
+	struct elf_note *n = buf;
+	char *note_name = buf + sizeof(*n);
+	unsigned long payload_offset;
+	unsigned long payload_len;
+
+	if (len < sizeof(*n) + 4)
+		return -ENOEXEC;
+
+	if ((n->n_namesz != 4) || strncmp("GNU", note_name, 3))
+		return -ENOEXEC;
+
+	payload_offset = round_up(sizeof(*n) + n->n_namesz, align);
+	payload_len = n->n_descsz;
+
+	if (payload_offset + payload_len > len)
+		return -ENOEXEC;
+
+	buf += payload_offset;
+	len -= payload_offset;
+
+	return check_note_payload(buf, len, pr_type, property);
+}
+
+#define find_note(phdr, nr_phdrs, align, pos, len) { \
+	int cnt; \
+	\
+	for (cnt = 0; cnt < nr_phdrs; cnt++) { \
+		if ((phdr)[cnt].p_align != align) \
+			continue; \
+		if ((phdr)[cnt].p_type == PT_GNU_PROPERTY) { \
+			pos = (phdr)[cnt].p_offset; \
+			len = (phdr)[cnt].p_filesz; \
+		} \
+	} \
+}
+
+int get_gnu_property(void *ehdr, void *phdr, struct file *file,
+		     u32 pr_type, u32 *property)
+{
+	Elf64_Ehdr *ehdr64 = ehdr;
+	Elf32_Ehdr *ehdr32 = ehdr;
+	void *buf;
+	int align;
+	loff_t pos = 0;
+	unsigned long len = 0;
+	int err = 0;
+
+	/*
+	 * Find PT_GNU_PROPERTY from ELF program headers.
+	 */
+	if (ehdr64->e_ident[EI_CLASS] == ELFCLASS64) {
+		align = 8;
+		find_note((Elf64_Phdr *)phdr, ehdr64->e_phnum, align, pos, len);
+	} else if (ehdr32->e_ident[EI_CLASS] == ELFCLASS32) {
+		align = 4;
+		find_note((Elf32_Phdr *)phdr, ehdr32->e_phnum, align, pos, len);
+	}
+
+	/*
+	 * Read in the whole note.  PT_GNU_PROPERTY
+	 * is not expected to be larger than a page.
+	 */
+	if (len == 0)
+		return 0;
+
+	if (len > PAGE_SIZE)
+		return -ENOEXEC;
+
+	buf = kmalloc(len, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	err = kernel_read(file, buf, len, &pos);
+	if (err < len) {
+		if (err >= 0)
+			err = -EIO;
+		goto out;
+	}
+
+	err = check_note(buf, len, align, pr_type, property);
+out:
+	kfree(buf);
+	return err;
+}
diff --git a/include/linux/elf.h b/include/linux/elf.h
index e3649b3e970e..c86cbfd17382 100644
--- a/include/linux/elf.h
+++ b/include/linux/elf.h
@@ -56,4 +56,15 @@ 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
+
+#ifdef CONFIG_ARCH_USE_GNU_PROPERTY
+extern int arch_parse_property(void *ehdr, void *phdr, struct file *f,
+			       bool inter, struct arch_elf_state *state);
+extern int arch_setup_property(struct arch_elf_state *state);
+extern int get_gnu_property(void *ehdr_p, void *phdr_p, struct file *f,
+			    u32 pr_type, u32 *feature);
+#else
+#define arch_parse_property(ehdr, phdr, file, inter, state) (0)
+#define arch_setup_property(state) (0)
+#endif
 #endif /* _LINUX_ELF_H */
diff --git a/include/uapi/linux/elf.h b/include/uapi/linux/elf.h
index 34c02e4290fe..530ce08467c2 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)
 
@@ -443,4 +444,17 @@ typedef struct elf64_note {
   Elf64_Word n_type;	/* Content type */
 } Elf64_Nhdr;
 
+/* NT_GNU_PROPERTY_TYPE_0 header */
+struct gnu_property {
+  __u32 pr_type;
+  __u32 pr_datasz;
+};
+
+/* .note.gnu.property types */
+#define GNU_PROPERTY_X86_FEATURE_1_AND		0xc0000002
+
+/* Bits of GNU_PROPERTY_X86_FEATURE_1_AND */
+#define GNU_PROPERTY_X86_FEATURE_1_IBT		0x00000001
+#define GNU_PROPERTY_X86_FEATURE_1_SHSTK	0x00000002
+
 #endif /* _UAPI_LINUX_ELF_H */
-- 
2.17.1

  parent reply	other threads:[~2019-08-13 20:52 UTC|newest]

Thread overview: 55+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-08-13 20:51 [PATCH v8 00/27] Control-flow Enforcement: Shadow Stack Yu-cheng Yu
2019-08-13 20:51 ` [PATCH v8 01/27] Documentation/x86: Add CET description Yu-cheng Yu
2019-08-14  8:07   ` Florian Weimer
2019-08-14 15:57     ` Yu-cheng Yu
2019-08-13 20:52 ` [PATCH v8 02/27] x86/cpufeatures: Add CET CPU feature flags for Control-flow Enforcement Technology (CET) Yu-cheng Yu
2019-08-21 10:20   ` Borislav Petkov
2019-08-21 14:46     ` Yu-cheng Yu
2019-08-13 20:52 ` [PATCH v8 03/27] x86/fpu/xstate: Change names to separate XSAVES system and user states Yu-cheng Yu
2019-08-21 14:45   ` Borislav Petkov
2019-08-13 20:52 ` [PATCH v8 04/27] x86/fpu/xstate: Introduce XSAVES system states Yu-cheng Yu
2019-08-16 19:56   ` Thomas Gleixner
2019-08-16 19:59     ` Yu-cheng Yu
2019-08-13 20:52 ` [PATCH v8 05/27] x86/fpu/xstate: Introduce CET MSR " Yu-cheng Yu
2019-08-13 20:52 ` [PATCH v8 06/27] x86/cet: Add control protection exception handler Yu-cheng Yu
2019-08-13 20:52 ` [PATCH v8 07/27] x86/cet/shstk: Add Kconfig option for user-mode shadow stack Yu-cheng Yu
2019-08-13 20:52 ` [PATCH v8 08/27] mm: Introduce VM_SHSTK for shadow stack memory Yu-cheng Yu
2019-08-13 20:52 ` [PATCH v8 09/27] mm/mmap: Prevent Shadow Stack VMA merges Yu-cheng Yu
2019-08-13 22:34   ` Dave Hansen
2019-08-14 16:20     ` Yu-cheng Yu
2019-08-13 20:52 ` [PATCH v8 10/27] x86/mm: Change _PAGE_DIRTY to _PAGE_DIRTY_HW Yu-cheng Yu
2019-08-13 20:52 ` [PATCH v8 11/27] x86/mm: Introduce _PAGE_DIRTY_SW Yu-cheng Yu
2019-08-13 23:02   ` Dave Hansen
2019-08-13 23:49     ` Andy Lutomirski
2019-08-14 16:42     ` Yu-cheng Yu
2019-08-14 16:58       ` Dave Hansen
2019-08-23 14:02   ` Peter Zijlstra
2019-08-27 22:37     ` Yu-cheng Yu
2019-08-28  7:03       ` Peter Zijlstra
2019-08-28 14:57         ` Yu-cheng Yu
2019-08-13 20:52 ` [PATCH v8 12/27] drm/i915/gvt: Update _PAGE_DIRTY to _PAGE_DIRTY_BITS Yu-cheng Yu
2019-08-13 20:52 ` [PATCH v8 13/27] x86/mm: Modify ptep_set_wrprotect and pmdp_set_wrprotect for _PAGE_DIRTY_SW Yu-cheng Yu
2019-08-13 20:52 ` [PATCH v8 14/27] x86/mm: Shadow stack page fault error checking Yu-cheng Yu
2019-08-13 20:52 ` [PATCH v8 15/27] mm: Handle shadow stack page fault Yu-cheng Yu
2019-08-13 22:55   ` Andy Lutomirski
2019-08-14 16:27     ` Yu-cheng Yu
2019-08-14 16:48       ` Dave Hansen
2019-08-14 17:00         ` Yu-cheng Yu
2019-08-13 20:52 ` [PATCH v8 16/27] mm: Handle THP/HugeTLB " Yu-cheng Yu
2019-08-13 20:52 ` [PATCH v8 17/27] mm: Update can_follow_write_pte/pmd for shadow stack Yu-cheng Yu
2019-08-13 20:52 ` [PATCH v8 18/27] mm: Introduce do_mmap_locked() Yu-cheng Yu
2019-08-20  1:02   ` Sean Christopherson
2019-08-20 16:08     ` Yu-cheng Yu
2019-08-13 20:52 ` [PATCH v8 19/27] x86/cet/shstk: User-mode shadow stack support Yu-cheng Yu
2019-08-13 20:52 ` [PATCH v8 20/27] x86/cet/shstk: Introduce WRUSS instruction Yu-cheng Yu
2019-08-13 20:52 ` [PATCH v8 21/27] x86/cet/shstk: Handle signals for shadow stack Yu-cheng Yu
2019-08-13 20:52 ` Yu-cheng Yu [this message]
2019-08-16 13:55   ` [PATCH v8 22/27] binfmt_elf: Extract .note.gnu.property from an ELF file Dave Martin
2019-08-20 10:02   ` Dave Martin
2019-08-13 20:52 ` [PATCH v8 23/27] x86/cet/shstk: ELF header parsing of Shadow Stack Yu-cheng Yu
2019-08-13 20:52 ` [PATCH v8 24/27] x86/cet/shstk: Handle thread shadow stack Yu-cheng Yu
2019-08-13 20:52 ` [PATCH v8 25/27] mm/mmap: Add Shadow stack pages to memory accounting Yu-cheng Yu
2019-08-13 20:52 ` [PATCH v8 26/27] x86/cet/shstk: Add arch_prctl functions for Shadow Stack Yu-cheng Yu
2019-08-13 20:52 ` [PATCH v8 27/27] x86/cet/shstk: Add Shadow Stack instructions to opcode map Yu-cheng Yu
2019-11-08 13:27   ` Adrian Hunter
2019-11-08 18:09     ` Yu-cheng Yu

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20190813205225.12032-23-yu-cheng.yu@intel.com \
    --to=yu-cheng.yu@intel.com \
    --cc=arnd@arndb.de \
    --cc=bp@alien8.de \
    --cc=bsingharora@gmail.com \
    --cc=corbet@lwn.net \
    --cc=dave.hansen@linux.intel.com \
    --cc=esyr@redhat.com \
    --cc=fweimer@redhat.com \
    --cc=gorcunov@gmail.com \
    --cc=hjl.tools@gmail.com \
    --cc=hpa@zytor.com \
    --cc=jannh@google.com \
    --cc=keescook@chromium.org \
    --cc=linux-api@vger.kernel.org \
    --cc=linux-arch@vger.kernel.org \
    --cc=linux-doc@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mm@kvack.org \
    --cc=luto@amacapital.net \
    --cc=mike.kravetz@oracle.com \
    --cc=mingo@redhat.com \
    --cc=nadav.amit@gmail.com \
    --cc=tglx@linutronix.de \
    --cc=x86@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).