Message ID | 20181119214809.6086-23-yu-cheng.yu@intel.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | Control-flow Enforcement: Shadow Stack | expand |
On Mon, Nov 19, 2018 at 01:48:05PM -0800, Yu-cheng Yu wrote: > Look in .note.gnu.property of an ELF file and check if Shadow Stack needs > to be enabled for the task. What's the status of this series? I don't see anything in linux-next yet. For describing ELF features, Arm has recently adopted NT_GNU_PROPERTY_TYPE_0, with properties closely modelled on GNU_PROPERTY_X86_FEATURE_1_AND etc. [1] So, arm64 will be need something like this patch for supporting new features (such as the Branch Target Identification feature of ARMv8.5-A [2]). If this series isn't likely to merge soon, can we split this patch into generic and x86-specific parts and handle them separately? It would be good to see the generic ELF note parsing move to common code -- I'll take a look and comment in more detail. [...] > diff --git a/arch/x86/include/asm/elf.h b/arch/x86/include/asm/elf.h > index 69c0f892e310..557ed0ba71c7 100644 > --- a/arch/x86/include/asm/elf.h > +++ b/arch/x86/include/asm/elf.h > @@ -381,4 +381,9 @@ struct va_alignment { > > extern struct va_alignment va_align; > extern unsigned long align_vdso_addr(unsigned long); > + > +#ifdef CONFIG_ARCH_HAS_PROGRAM_PROPERTIES > +extern int arch_setup_features(void *ehdr, void *phdr, struct file *file, > + bool interp); > +#endif > #endif /* _ASM_X86_ELF_H */ > diff --git a/arch/x86/include/uapi/asm/elf_property.h b/arch/x86/include/uapi/asm/elf_property.h > new file mode 100644 > index 000000000000..af361207718c > --- /dev/null > +++ b/arch/x86/include/uapi/asm/elf_property.h > @@ -0,0 +1,15 @@ > +/* SPDX-License-Identifier: GPL-2.0 */ > +#ifndef _UAPI_ASM_X86_ELF_PROPERTY_H > +#define _UAPI_ASM_X86_ELF_PROPERTY_H > + > +/* > + * pr_type > + */ > +#define GNU_PROPERTY_X86_FEATURE_1_AND (0xc0000002) > + > +/* > + * Bits for GNU_PROPERTY_X86_FEATURE_1_AND > + */ > +#define GNU_PROPERTY_X86_FEATURE_1_SHSTK (0x00000002) > + Generally we seem to collect all ELF definitions in <linux/uapi/elf.h>, including arch-specific ones. Is a new header really needed here? [...] > diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c > index 54207327f98f..007ff0fbae84 100644 > --- a/fs/binfmt_elf.c > +++ b/fs/binfmt_elf.c > @@ -1081,6 +1081,21 @@ static int load_elf_binary(struct linux_binprm *bprm) > goto out_free_dentry; > } > > +#ifdef CONFIG_ARCH_HAS_PROGRAM_PROPERTIES > + if (interpreter) { > + retval = arch_setup_features(&loc->interp_elf_ex, > + interp_elf_phdata, > + interpreter, true); Can we dummy no-op functions in the common headers to avoid this ifdeffery? Logically all arches will always do this step, even if it's a no-op today. > + } else { > + retval = arch_setup_features(&loc->elf_ex, > + elf_phdata, > + bprm->file, false); > + } > + > + if (retval < 0) > + goto out_free_dentry; > +#endif > + > if (elf_interpreter) { > unsigned long interp_map_addr = 0; > > diff --git a/include/uapi/linux/elf.h b/include/uapi/linux/elf.h > index c5358e0ae7c5..5ef25a565e88 100644 > --- a/include/uapi/linux/elf.h > +++ b/include/uapi/linux/elf.h > @@ -372,6 +372,7 @@ typedef struct elf64_shdr { > #define NT_PRFPREG 2 > #define NT_PRPSINFO 3 > #define NT_TASKSTRUCT 4 > +#define NT_GNU_PROPERTY_TYPE_0 5 IIUC, note type codes are namespaced by the note name. This section currently only seems to have codes for name == "LINUX". There are conflicts: for example NT_GNU_ABI_TAG == NT_PRSTATUS. We should probably split out the codes for name == "GNU" into a separate list, otherwise people are likely to get confused. As noted above, can the GNU_PRPOERTY_<arch>_* definitions just go in here instead of a separate header? [...] Cheers ---Dave [1] https://developer.arm.com/docs/ihi0056/latest/elf-for-the-arm-64-bit-architecture-aarch64-abi-2019q1-documentation [2] https://community.arm.com/developer/ip-products/processors/b/processors-ip-blog/posts/arm-a-profile-architecture-2018-developments-armv85a
On Thu, 2019-04-25 at 12:02 +0100, Dave Martin wrote: > On Mon, Nov 19, 2018 at 01:48:05PM -0800, Yu-cheng Yu wrote: > > Look in .note.gnu.property of an ELF file and check if Shadow Stack needs > > to be enabled for the task. > > What's the status of this series? I don't see anything in linux-next > yet. > > For describing ELF features, Arm has recently adopted > NT_GNU_PROPERTY_TYPE_0, with properties closely modelled on > GNU_PROPERTY_X86_FEATURE_1_AND etc. [1] > > So, arm64 will be need something like this patch for supporting new > features (such as the Branch Target Identification feature of ARMv8.5-A > [2]). > > If this series isn't likely to merge soon, can we split this patch into > generic and x86-specific parts and handle them separately? > > It would be good to see the generic ELF note parsing move to common > code -- I'll take a look and comment in more detail. Yes, I will work on that. > > [...] > > > diff --git a/arch/x86/include/asm/elf.h b/arch/x86/include/asm/elf.h > > index 69c0f892e310..557ed0ba71c7 100644 > > --- a/arch/x86/include/asm/elf.h > > +++ b/arch/x86/include/asm/elf.h > > @@ -381,4 +381,9 @@ struct va_alignment { > > > > extern struct va_alignment va_align; > > extern unsigned long align_vdso_addr(unsigned long); > > + > > +#ifdef CONFIG_ARCH_HAS_PROGRAM_PROPERTIES > > +extern int arch_setup_features(void *ehdr, void *phdr, struct file *file, > > + bool interp); > > +#endif > > #endif /* _ASM_X86_ELF_H */ > > diff --git a/arch/x86/include/uapi/asm/elf_property.h > > b/arch/x86/include/uapi/asm/elf_property.h > > new file mode 100644 > > index 000000000000..af361207718c > > --- /dev/null > > +++ b/arch/x86/include/uapi/asm/elf_property.h > > @@ -0,0 +1,15 @@ > > +/* SPDX-License-Identifier: GPL-2.0 */ > > +#ifndef _UAPI_ASM_X86_ELF_PROPERTY_H > > +#define _UAPI_ASM_X86_ELF_PROPERTY_H > > + > > +/* > > + * pr_type > > + */ > > +#define GNU_PROPERTY_X86_FEATURE_1_AND (0xc0000002) > > + > > +/* > > + * Bits for GNU_PROPERTY_X86_FEATURE_1_AND > > + */ > > +#define GNU_PROPERTY_X86_FEATURE_1_SHSTK (0x00000002) > > + > > Generally we seem to collect all ELF definitions in <linux/uapi/elf.h>, > including arch-specific ones. Agree. > > Is a new header really needed here? > > [...] > > > diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c > > index 54207327f98f..007ff0fbae84 100644 > > --- a/fs/binfmt_elf.c > > +++ b/fs/binfmt_elf.c > > @@ -1081,6 +1081,21 @@ static int load_elf_binary(struct linux_binprm *bprm) > > goto out_free_dentry; > > } > > > > +#ifdef CONFIG_ARCH_HAS_PROGRAM_PROPERTIES > > + if (interpreter) { > > + retval = arch_setup_features(&loc->interp_elf_ex, > > + interp_elf_phdata, > > + interpreter, true); > > Can we dummy no-op functions in the common headers to avoid this > ifdeffery? Logically all arches will always do this step, even if it's > a no-op today. Sure. Thanks, Yu-cheng
On Thu, Apr 25, 2019 at 08:14:52AM -0700, Yu-cheng Yu wrote: > On Thu, 2019-04-25 at 12:02 +0100, Dave Martin wrote: > > On Mon, Nov 19, 2018 at 01:48:05PM -0800, Yu-cheng Yu wrote: > > > Look in .note.gnu.property of an ELF file and check if Shadow Stack needs > > > to be enabled for the task. > > > > What's the status of this series? I don't see anything in linux-next > > yet. > > > > For describing ELF features, Arm has recently adopted > > NT_GNU_PROPERTY_TYPE_0, with properties closely modelled on > > GNU_PROPERTY_X86_FEATURE_1_AND etc. [1] > > > > So, arm64 will be need something like this patch for supporting new > > features (such as the Branch Target Identification feature of ARMv8.5-A > > [2]). > > > > If this series isn't likely to merge soon, can we split this patch into > > generic and x86-specific parts and handle them separately? > > > > It would be good to see the generic ELF note parsing move to common > > code -- I'll take a look and comment in more detail. > > Yes, I will work on that. Thanks. I may try to hack something in the meantime based on your patch. One other question: according to the draft spec at https://github.com/hjl-tools/linux-abi/wiki/Linux-Extensions-to-gABI, it looks like the .note.gnu.property section is supposed to be marked with SHF_ALLOC in object files. I think that means that the linker will map it with a PT_LOAD entry in the program header table in addition to the PT_NOTE that describes the location of the note. I need to check what the toolchain actually does. If so, can we simply rely on the notes being already mapped, rather than needing to do additional I/O on the ELF file to fetch the notes? [...] Cheers ---Dave
On Thu, Apr 25, 2019 at 04:35:48PM +0100, Dave Martin wrote: > On Thu, Apr 25, 2019 at 08:14:52AM -0700, Yu-cheng Yu wrote: > > On Thu, 2019-04-25 at 12:02 +0100, Dave Martin wrote: > > > On Mon, Nov 19, 2018 at 01:48:05PM -0800, Yu-cheng Yu wrote: > > > > Look in .note.gnu.property of an ELF file and check if Shadow Stack needs > > > > to be enabled for the task. > > > > > > What's the status of this series? I don't see anything in linux-next > > > yet. > > > > > > For describing ELF features, Arm has recently adopted > > > NT_GNU_PROPERTY_TYPE_0, with properties closely modelled on > > > GNU_PROPERTY_X86_FEATURE_1_AND etc. [1] > > > > > > So, arm64 will be need something like this patch for supporting new > > > features (such as the Branch Target Identification feature of ARMv8.5-A > > > [2]). > > > > > > If this series isn't likely to merge soon, can we split this patch into > > > generic and x86-specific parts and handle them separately? > > > > > > It would be good to see the generic ELF note parsing move to common > > > code -- I'll take a look and comment in more detail. > > > > Yes, I will work on that. > > Thanks. I may try to hack something in the meantime based on your > patch. > > One other question: according to the draft spec at > https://github.com/hjl-tools/linux-abi/wiki/Linux-Extensions-to-gABI, it > looks like the .note.gnu.property section is supposed to be marked with > SHF_ALLOC in object files. > > I think that means that the linker will map it with a PT_LOAD entry in > the program header table in addition to the PT_NOTE that describes the > location of the note. I need to check what the toolchain actually > does. > > If so, can we simply rely on the notes being already mapped, rather than > needing to do additional I/O on the ELF file to fetch the notes? [...] BTW, it looks like this holds true for AArch64 (see below). Providing this also works on other arches, I think we can just pick PT_GNU_PROPERTY out of the program headers and rely on the corresponding note being already mapped by the existing binfmt_elf code. Cheers ---Dave --8<-- $ echo 'void f(void) { }' | \ aarch64-linux-gnu-gcc -v -nostdlib -Wl,-ef \ -mbranch-protection=standard -o /tmp/x -x c - && \ aarch64-linux-gnu-readelf -nl /tmp/x [...] gcc version 9.0.1 20190425 (experimental) (GCC) [...] GNU assembler version 2.32.51 (aarch64-linux-gnu) using BFD version (GNU Binutils) 2.32.51.20190425 [...] Elf file type is EXEC (Executable file) Entry point 0x400178 There are 5 program headers, starting at offset 64 Program Headers: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flags Align LOAD 0x0000000000000000 0x0000000000400000 0x0000000000400000 0x00000000000001c0 0x00000000000001c0 R E 0x10000 NOTE 0x0000000000000158 0x0000000000400158 0x0000000000400158 0x0000000000000020 0x0000000000000020 R 0x8 GNU_PROPERTY 0x0000000000000158 0x0000000000400158 0x0000000000400158 0x0000000000000020 0x0000000000000020 R 0x8 GNU_EH_FRAME 0x0000000000000184 0x0000000000400184 0x0000000000400184 0x0000000000000014 0x0000000000000014 R 0x4 GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000 0x0000000000000000 0x0000000000000000 RW 0x10 Section to Segment mapping: Segment Sections... 00 .note.gnu.property .text .eh_frame_hdr .eh_frame 01 .note.gnu.property 02 .note.gnu.property 03 .eh_frame_hdr 04 Displaying notes found in: .note.gnu.property Owner Data size Description GNU 0x00000010 NT_GNU_PROPERTY_TYPE_0 Properties: AArch64 feature: BTI, PAC
On Thu, 2019-04-25 at 16:35 +0100, Dave Martin wrote: > On Thu, Apr 25, 2019 at 08:14:52AM -0700, Yu-cheng Yu wrote: > > On Thu, 2019-04-25 at 12:02 +0100, Dave Martin wrote: > > > [...] > One other question: according to the draft spec at > https://github.com/hjl-tools/linux-abi/wiki/Linux-Extensions-to-gABI, it > looks like the .note.gnu.property section is supposed to be marked with > SHF_ALLOC in object files. > > I think that means that the linker will map it with a PT_LOAD entry in > the program header table in addition to the PT_NOTE that describes the > location of the note. I need to check what the toolchain actually > does. > > If so, can we simply rely on the notes being already mapped, rather than > needing to do additional I/O on the ELF file to fetch the notes? Assuming that is mapped and we do copy_from_user, it will trigger page faults. I suspect in this case reading from the file is better? Yu-cheng
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 86fb68f496a6..73dfb94cde71 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -1925,6 +1925,9 @@ config X86_INTEL_CET config ARCH_HAS_SHSTK def_bool n +config ARCH_HAS_PROGRAM_PROPERTIES + def_bool n + config X86_INTEL_SHADOW_STACK_USER prompt "Intel Shadow Stack for user-mode" def_bool n @@ -1932,6 +1935,7 @@ config X86_INTEL_SHADOW_STACK_USER select ARCH_USES_HIGH_VMA_FLAGS select X86_INTEL_CET select ARCH_HAS_SHSTK + select ARCH_HAS_PROGRAM_PROPERTIES ---help--- Shadow stack provides hardware protection against program stack corruption. Only when all the following are true will an application diff --git a/arch/x86/include/asm/elf.h b/arch/x86/include/asm/elf.h index 69c0f892e310..557ed0ba71c7 100644 --- a/arch/x86/include/asm/elf.h +++ b/arch/x86/include/asm/elf.h @@ -381,4 +381,9 @@ struct va_alignment { extern struct va_alignment va_align; extern unsigned long align_vdso_addr(unsigned long); + +#ifdef CONFIG_ARCH_HAS_PROGRAM_PROPERTIES +extern int arch_setup_features(void *ehdr, void *phdr, struct file *file, + bool interp); +#endif #endif /* _ASM_X86_ELF_H */ diff --git a/arch/x86/include/uapi/asm/elf_property.h b/arch/x86/include/uapi/asm/elf_property.h new file mode 100644 index 000000000000..af361207718c --- /dev/null +++ b/arch/x86/include/uapi/asm/elf_property.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _UAPI_ASM_X86_ELF_PROPERTY_H +#define _UAPI_ASM_X86_ELF_PROPERTY_H + +/* + * pr_type + */ +#define GNU_PROPERTY_X86_FEATURE_1_AND (0xc0000002) + +/* + * Bits for GNU_PROPERTY_X86_FEATURE_1_AND + */ +#define GNU_PROPERTY_X86_FEATURE_1_SHSTK (0x00000002) + +#endif /* _UAPI_ASM_X86_ELF_PROPERTY_H */ diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile index fbb2d91fb756..36b14ef410c8 100644 --- a/arch/x86/kernel/Makefile +++ b/arch/x86/kernel/Makefile @@ -141,6 +141,8 @@ obj-$(CONFIG_UNWINDER_GUESS) += unwind_guess.o obj-$(CONFIG_X86_INTEL_CET) += cet.o +obj-$(CONFIG_ARCH_HAS_PROGRAM_PROPERTIES) += elf.o + ### # 64 bit specific files ifeq ($(CONFIG_X86_64),y) diff --git a/arch/x86/kernel/elf.c b/arch/x86/kernel/elf.c new file mode 100644 index 000000000000..60e396e2abe9 --- /dev/null +++ b/arch/x86/kernel/elf.c @@ -0,0 +1,358 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Look at an ELF file's .note.gnu.property and determine if the file + * supports shadow stack and/or indirect branch tracking. + * The path from the ELF header to the note section is the following: + * elfhdr->elf_phdr->elf_note->property[]. + */ + +#include <asm/cet.h> +#include <asm/elf_property.h> +#include <asm/prctl.h> +#include <asm/processor.h> +#include <uapi/linux/elf-em.h> +#include <uapi/linux/prctl.h> +#include <linux/binfmts.h> +#include <linux/elf.h> +#include <linux/slab.h> +#include <linux/fs.h> +#include <linux/uaccess.h> +#include <linux/string.h> +#include <linux/compat.h> + +/* + * The .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 + * }; + * char n_name[4]; --> always 'GNU\0' + * + * struct { + * struct property_x86 { + * u32 pr_type; + * u32 pr_datasz; + * }; + * u8 pr_data[pr_datasz]; + * }[]; + */ + +#define BUF_SIZE (PAGE_SIZE / 4) + +struct property_x86 { + u32 pr_type; + u32 pr_datasz; +}; + +typedef bool (test_item_fn)(void *buf, u32 *arg); +typedef void *(next_item_fn)(void *buf, u32 *arg); + +static inline bool test_note_type_0(void *buf, u32 *align) +{ + struct elf_note *n = buf; + + return ((n->n_type == NT_GNU_PROPERTY_TYPE_0) && (n->n_namesz == 4) && + (memcmp(n + 1, "GNU", 4) == 0)); +} + +static inline void *next_note(void *buf, u32 *align) +{ + struct elf_note *n = buf; + u64 size; + + if (check_add_overflow((u64)sizeof(*n), (u64)n->n_namesz, &size)) + return NULL; + + size = round_up(size, *align); + + if (check_add_overflow(size, (u64)n->n_descsz, &size)) + return NULL; + + size = round_up(size, *align); + + if (buf + size < buf) + return NULL; + else + return (buf + size); +} + +static inline bool test_property_x86(void *buf, u32 *max_type) +{ + struct property_x86 *pr = buf; + + /* + * Property types must be in ascending order. + * Keep track of the max when testing each. + */ + if (pr->pr_type > *max_type) + *max_type = pr->pr_type; + + return (pr->pr_type == GNU_PROPERTY_X86_FEATURE_1_AND); +} + +static inline void *next_property(void *buf, u32 *max_type) +{ + struct property_x86 *pr = buf; + + if ((buf + sizeof(*pr) + pr->pr_datasz < buf) || + (pr->pr_type > GNU_PROPERTY_X86_FEATURE_1_AND) || + (pr->pr_type > *max_type)) + return NULL; + else + return (buf + sizeof(*pr) + pr->pr_datasz); +} + +/* + * Scan 'buf' for a pattern; return true if found. + * *pos is the distance from the beginning of buf to where + * the searched item or the next item is located. + */ +static int scan(u8 *buf, u32 buf_size, int item_size, test_item_fn test_item, + next_item_fn next_item, u32 *arg, u32 *pos) +{ + int found = 0; + u8 *p, *max; + + max = buf + buf_size; + if (max < buf) + return 0; + + p = buf; + + while ((p + item_size < max) && (p + item_size > buf)) { + if (test_item(p, arg)) { + found = 1; + break; + } + + p = next_item(p, arg); + } + + *pos = (p + item_size <= buf) ? 0 : (u32)(p - buf); + return found; +} + +/* + * Search a NT_GNU_PROPERTY_TYPE_0 for GNU_PROPERTY_X86_FEATURE_1_AND. + */ +static int find_feature_x86(struct file *file, unsigned long desc_size, + loff_t file_offset, u8 *buf, u32 *feature) +{ + u32 buf_pos; + unsigned long read_size; + unsigned long done; + int found = 0; + int ret = 0; + u32 last_pr = 0; + + *feature = 0; + buf_pos = 0; + + for (done = 0; done < desc_size; done += buf_pos) { + read_size = desc_size - done; + if (read_size > BUF_SIZE) + read_size = BUF_SIZE; + + ret = kernel_read(file, buf, read_size, &file_offset); + + if (ret != read_size) + return (ret < 0) ? ret : -EIO; + + ret = 0; + found = scan(buf, read_size, sizeof(struct property_x86), + test_property_x86, next_property, + &last_pr, &buf_pos); + + if ((!buf_pos) || found) + break; + + file_offset += buf_pos - read_size; + } + + if (found) { + struct property_x86 *pr = + (struct property_x86 *)(buf + buf_pos); + + if (pr->pr_datasz == 4) { + u32 *max = (u32 *)(buf + read_size); + u32 *data = (u32 *)((u8 *)pr + sizeof(*pr)); + + if (data + 1 <= max) { + *feature = *data; + } else { + file_offset += buf_pos - read_size; + file_offset += sizeof(*pr); + ret = kernel_read(file, feature, 4, + &file_offset); + } + } + } + + return ret; +} + +/* + * Search a PT_NOTE segment for NT_GNU_PROPERTY_TYPE_0. + */ +static int find_note_type_0(struct file *file, unsigned long note_size, + loff_t file_offset, u32 align, u32 *feature) +{ + u8 *buf; + u32 buf_pos; + unsigned long read_size; + unsigned long done; + int found = 0; + int ret = 0; + + buf = kmalloc(BUF_SIZE, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + *feature = 0; + buf_pos = 0; + + for (done = 0; done < note_size; done += buf_pos) { + read_size = note_size - done; + if (read_size > BUF_SIZE) + read_size = BUF_SIZE; + + ret = kernel_read(file, buf, read_size, &file_offset); + + if (ret != read_size) { + ret = (ret < 0) ? ret : -EIO; + kfree(buf); + return ret; + } + + /* + * item_size = sizeof(struct elf_note) + elf_note.n_namesz. + * n_namesz is 4 for the note type we look for. + */ + ret = scan(buf, read_size, sizeof(struct elf_note) + 4, + test_note_type_0, next_note, + &align, &buf_pos); + + file_offset += buf_pos - read_size; + + if (ret && !found) { + struct elf_note *n = + (struct elf_note *)(buf + buf_pos); + u64 start = round_up(sizeof(*n) + n->n_namesz, align); + u64 total = 0; + + if (check_add_overflow(start, (u64)n->n_descsz, &total)) { + ret = -EINVAL; + break; + } + total = round_up(total, align); + + ret = find_feature_x86(file, n->n_descsz, + file_offset + start, + buf, feature); + found++; + file_offset += total; + buf_pos += total; + } else if (!buf_pos || ret) { + ret = 0; + *feature = 0; + break; + } + } + + kfree(buf); + return ret; +} + +#ifdef CONFIG_COMPAT +static int check_notes_32(struct file *file, struct elf32_phdr *phdr, + int phnum, u32 *feature) +{ + int i; + int err = 0; + + for (i = 0; i < phnum; i++, phdr++) { + if ((phdr->p_type != PT_NOTE) || (phdr->p_align != 4)) + continue; + + err = find_note_type_0(file, phdr->p_filesz, phdr->p_offset, + phdr->p_align, feature); + if (err) + return err; + } + + return 0; +} +#endif + +#ifdef CONFIG_X86_64 +static int check_notes_64(struct file *file, struct elf64_phdr *phdr, + int phnum, u32 *feature) +{ + int i; + int err = 0; + + for (i = 0; i < phnum; i++, phdr++) { + if ((phdr->p_type != PT_NOTE) || (phdr->p_align != 8)) + continue; + + err = find_note_type_0(file, phdr->p_filesz, phdr->p_offset, + phdr->p_align, feature); + if (err) + return err; + } + + return 0; +} +#endif + +int arch_setup_features(void *ehdr_p, void *phdr_p, + struct file *file, bool interp) +{ + int err = 0; + u32 feature = 0; + + struct elf64_hdr *ehdr64 = ehdr_p; + + if (!cpu_x86_cet_enabled()) + return 0; + + if (ehdr64->e_ident[EI_CLASS] == ELFCLASS64) { + struct elf64_phdr *phdr64 = phdr_p; + + err = check_notes_64(file, phdr64, ehdr64->e_phnum, + &feature); + if (err < 0) + goto out; + } else { +#ifdef CONFIG_COMPAT + struct elf32_hdr *ehdr32 = ehdr_p; + + if (ehdr32->e_ident[EI_CLASS] == ELFCLASS32) { + struct elf32_phdr *phdr32 = phdr_p; + + err = check_notes_32(file, phdr32, ehdr32->e_phnum, + &feature); + if (err < 0) + goto out; + } +#else + WARN_ONCE(1, "Exec of 32-bit app, but CONFIG_COMPAT is not enabled.\n"); + return -ENOTSUPP; +#endif + } + + memset(¤t->thread.cet, 0, sizeof(struct cet_status)); + + if (cpu_feature_enabled(X86_FEATURE_SHSTK)) { + if (feature & GNU_PROPERTY_X86_FEATURE_1_SHSTK) { + err = cet_setup_shstk(); + if (err < 0) + goto out; + } + } + +out: + return err; +} diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 54207327f98f..007ff0fbae84 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -1081,6 +1081,21 @@ static int load_elf_binary(struct linux_binprm *bprm) goto out_free_dentry; } +#ifdef CONFIG_ARCH_HAS_PROGRAM_PROPERTIES + if (interpreter) { + retval = arch_setup_features(&loc->interp_elf_ex, + interp_elf_phdata, + interpreter, true); + } else { + retval = arch_setup_features(&loc->elf_ex, + elf_phdata, + bprm->file, false); + } + + if (retval < 0) + goto out_free_dentry; +#endif + if (elf_interpreter) { unsigned long interp_map_addr = 0; diff --git a/include/uapi/linux/elf.h b/include/uapi/linux/elf.h index c5358e0ae7c5..5ef25a565e88 100644 --- a/include/uapi/linux/elf.h +++ b/include/uapi/linux/elf.h @@ -372,6 +372,7 @@ typedef struct elf64_shdr { #define NT_PRFPREG 2 #define NT_PRPSINFO 3 #define NT_TASKSTRUCT 4 +#define NT_GNU_PROPERTY_TYPE_0 5 #define NT_AUXV 6 /* * Note to userspace developers: size of NT_SIGINFO note may increase