arm64: elf: Enable BTI at exec based on ELF program properties
authorDave Martin <Dave.Martin@arm.com>
Mon, 16 Mar 2020 16:50:47 +0000 (16:50 +0000)
committerCatalin Marinas <catalin.marinas@arm.com>
Mon, 16 Mar 2020 17:19:48 +0000 (17:19 +0000)
For BTI protection to be as comprehensive as possible, it is
desirable to have BTI enabled from process startup.  If this is not
done, the process must use mprotect() to enable BTI for each of its
executable mappings, but this is painful to do in the libc startup
code.  It's simpler and more sound to have the kernel do it
instead.

To this end, detect BTI support in the executable (or ELF
interpreter, as appropriate), via the
NT_GNU_PROGRAM_PROPERTY_TYPE_0 note, and tweak the initial prot
flags for the process' executable pages to include PROT_BTI as
appropriate.

Signed-off-by: Mark Brown <broonie@kernel.org>
Signed-off-by: Dave Martin <Dave.Martin@arm.com>
Reviewed-by: Kees Cook <keescook@chromium.org>
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
arch/arm64/Kconfig
arch/arm64/include/asm/elf.h
arch/arm64/kernel/process.c
include/uapi/linux/elf.h

index 0b30e88..8a15bc6 100644 (file)
@@ -9,6 +9,7 @@ config ARM64
        select ACPI_MCFG if (ACPI && PCI)
        select ACPI_SPCR_TABLE if ACPI
        select ACPI_PPTT if ACPI
+       select ARCH_BINFMT_ELF_STATE
        select ARCH_CLOCKSOURCE_DATA
        select ARCH_HAS_DEBUG_VIRTUAL
        select ARCH_HAS_DEVMEM_IS_ALLOWED
@@ -33,6 +34,7 @@ config ARM64
        select ARCH_HAS_SYSCALL_WRAPPER
        select ARCH_HAS_TEARDOWN_DMA_OPS if IOMMU_SUPPORT
        select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST
+       select ARCH_HAVE_ELF_PROT
        select ARCH_HAVE_NMI_SAFE_CMPXCHG
        select ARCH_INLINE_READ_LOCK if !PREEMPTION
        select ARCH_INLINE_READ_LOCK_BH if !PREEMPTION
@@ -62,6 +64,7 @@ config ARM64
        select ARCH_INLINE_SPIN_UNLOCK_IRQRESTORE if !PREEMPTION
        select ARCH_KEEP_MEMBLOCK
        select ARCH_USE_CMPXCHG_LOCKREF
+       select ARCH_USE_GNU_PROPERTY if BINFMT_ELF
        select ARCH_USE_QUEUED_RWLOCKS
        select ARCH_USE_QUEUED_SPINLOCKS
        select ARCH_SUPPORTS_MEMORY_FAILURE
index b618017..4f00d50 100644 (file)
 
 #ifndef __ASSEMBLY__
 
+#include <uapi/linux/elf.h>
 #include <linux/bug.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/types.h>
 #include <asm/processor.h> /* for signal_minsigstksz, used by ARCH_DLINFO */
 
 typedef unsigned long elf_greg_t;
@@ -224,6 +228,52 @@ extern int aarch32_setup_additional_pages(struct linux_binprm *bprm,
 
 #endif /* CONFIG_COMPAT */
 
+struct arch_elf_state {
+       int flags;
+};
+
+#define ARM64_ELF_BTI          (1 << 0)
+
+#define INIT_ARCH_ELF_STATE {                  \
+       .flags = 0,                             \
+}
+
+static inline int arch_parse_elf_property(u32 type, const void *data,
+                                         size_t datasz, bool compat,
+                                         struct arch_elf_state *arch)
+{
+       /* No known properties for AArch32 yet */
+       if (IS_ENABLED(CONFIG_COMPAT) && compat)
+               return 0;
+
+       if (type == GNU_PROPERTY_AARCH64_FEATURE_1_AND) {
+               const u32 *p = data;
+
+               if (datasz != sizeof(*p))
+                       return -ENOEXEC;
+
+               if (system_supports_bti() &&
+                   (*p & GNU_PROPERTY_AARCH64_FEATURE_1_BTI))
+                       arch->flags |= ARM64_ELF_BTI;
+       }
+
+       return 0;
+}
+
+static inline int arch_elf_pt_proc(void *ehdr, void *phdr,
+                                  struct file *f, bool is_interp,
+                                  struct arch_elf_state *state)
+{
+       return 0;
+}
+
+static inline int arch_check_elf(void *ehdr, bool has_interp,
+                                void *interp_ehdr,
+                                struct arch_elf_state *state)
+{
+       return 0;
+}
+
 #endif /* !__ASSEMBLY__ */
 
 #endif
index 0062605..b8e3faa 100644 (file)
@@ -11,6 +11,7 @@
 
 #include <linux/compat.h>
 #include <linux/efi.h>
+#include <linux/elf.h>
 #include <linux/export.h>
 #include <linux/sched.h>
 #include <linux/sched/debug.h>
@@ -18,6 +19,7 @@
 #include <linux/sched/task_stack.h>
 #include <linux/kernel.h>
 #include <linux/lockdep.h>
+#include <linux/mman.h>
 #include <linux/mm.h>
 #include <linux/stddef.h>
 #include <linux/sysctl.h>
@@ -654,3 +656,20 @@ asmlinkage void __sched arm64_preempt_schedule_irq(void)
        if (system_capabilities_finalized())
                preempt_schedule_irq();
 }
+
+#ifdef CONFIG_BINFMT_ELF
+int arch_elf_adjust_prot(int prot, const struct arch_elf_state *state,
+                        bool has_interp, bool is_interp)
+{
+       if (is_interp != has_interp)
+               return prot;
+
+       if (!(state->flags & ARM64_ELF_BTI))
+               return prot;
+
+       if (prot & PROT_EXEC)
+               prot |= PROT_BTI;
+
+       return prot;
+}
+#endif
index 20900f4..c6dd021 100644 (file)
@@ -448,4 +448,10 @@ typedef struct elf64_note {
   Elf64_Word n_type;   /* Content type */
 } Elf64_Nhdr;
 
+/* .note.gnu.property types for EM_AARCH64: */
+#define GNU_PROPERTY_AARCH64_FEATURE_1_AND     0xc0000000
+
+/* Bits for GNU_PROPERTY_AARCH64_FEATURE_1_BTI */
+#define GNU_PROPERTY_AARCH64_FEATURE_1_BTI     (1U << 0)
+
 #endif /* _UAPI_LINUX_ELF_H */