]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
Merge branch 'for-next/bti-user' into for-next/bti
authorWill Deacon <will@kernel.org>
Tue, 5 May 2020 14:15:58 +0000 (15:15 +0100)
committerWill Deacon <will@kernel.org>
Tue, 5 May 2020 14:15:58 +0000 (15:15 +0100)
Merge in user support for Branch Target Identification, which narrowly
missed the cut for 5.7 after a late ABI concern.

* for-next/bti-user:
  arm64: bti: Document behaviour for dynamically linked binaries
  arm64: elf: Fix allnoconfig kernel build with !ARCH_USE_GNU_PROPERTY
  arm64: BTI: Add Kconfig entry for userspace BTI
  mm: smaps: Report arm64 guarded pages in smaps
  arm64: mm: Display guarded pages in ptdump
  KVM: arm64: BTI: Reset BTYPE when skipping emulated instructions
  arm64: BTI: Reset BTYPE when skipping emulated instructions
  arm64: traps: Shuffle code to eliminate forward declarations
  arm64: unify native/compat instruction skipping
  arm64: BTI: Decode BYTPE bits when printing PSTATE
  arm64: elf: Enable BTI at exec based on ELF program properties
  elf: Allow arch to tweak initial mmap prot flags
  arm64: Basic Branch Target Identification support
  ELF: Add ELF program property parsing support
  ELF: UAPI and Kconfig additions for ELF program properties

35 files changed:
Documentation/arm64/cpu-feature-registers.rst
Documentation/arm64/elf_hwcaps.rst
Documentation/filesystems/proc.rst
arch/arm64/Kconfig
arch/arm64/include/asm/cpucaps.h
arch/arm64/include/asm/cpufeature.h
arch/arm64/include/asm/elf.h
arch/arm64/include/asm/esr.h
arch/arm64/include/asm/exception.h
arch/arm64/include/asm/hwcap.h
arch/arm64/include/asm/kvm_emulate.h
arch/arm64/include/asm/mman.h [new file with mode: 0644]
arch/arm64/include/asm/pgtable-hwdef.h
arch/arm64/include/asm/pgtable.h
arch/arm64/include/asm/ptrace.h
arch/arm64/include/asm/sysreg.h
arch/arm64/include/uapi/asm/hwcap.h
arch/arm64/include/uapi/asm/mman.h [new file with mode: 0644]
arch/arm64/include/uapi/asm/ptrace.h
arch/arm64/kernel/cpufeature.c
arch/arm64/kernel/cpuinfo.c
arch/arm64/kernel/entry-common.c
arch/arm64/kernel/process.c
arch/arm64/kernel/ptrace.c
arch/arm64/kernel/signal.c
arch/arm64/kernel/syscall.c
arch/arm64/kernel/traps.c
arch/arm64/mm/dump.c
fs/Kconfig.binfmt
fs/binfmt_elf.c
fs/compat_binfmt_elf.c
fs/proc/task_mmu.c
include/linux/elf.h
include/linux/mm.h
include/uapi/linux/elf.h

index 41937a8091aaa2a9c2252fc3f98615a4bbb25436..314fa5bc2655da3b30fdde5c12e602ae2633ccc5 100644 (file)
@@ -176,6 +176,8 @@ infrastructure:
      +------------------------------+---------+---------+
      | SSBS                         | [7-4]   |    y    |
      +------------------------------+---------+---------+
+     | BT                           | [3-0]   |    y    |
+     +------------------------------+---------+---------+
 
 
   4) MIDR_EL1 - Main ID Register
index 7dfb97dfe416058f20ef3863c9185d9a071f46ec..84a9fd2d41b4700d00fe35e2a595156ae03c6668 100644 (file)
@@ -236,6 +236,11 @@ HWCAP2_RNG
 
     Functionality implied by ID_AA64ISAR0_EL1.RNDR == 0b0001.
 
+HWCAP2_BTI
+
+    Functionality implied by ID_AA64PFR0_EL1.BT == 0b0001.
+
+
 4. Unused AT_HWCAP bits
 -----------------------
 
index 38b606991065b3df4f075bb3120dc9e5db09bf71..9969bf4c0c44f6370cb65c59486f071a0178edc4 100644 (file)
@@ -543,6 +543,7 @@ encoded manner. The codes are the following:
     hg    huge page advise flag
     nh    no huge page advise flag
     mg    mergable advise flag
+    bt  - arm64 BTI guarded page
     ==    =======================================
 
 Note that there is no guarantee that every flag and associated mnemonic will
index 40fb05d96c6072c9357cf69965ca006c0a5fdb27..43be825d0730a6c8657402342fcec9da84a99f3c 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_HAS_DEBUG_VIRTUAL
        select ARCH_HAS_DEVMEM_IS_ALLOWED
        select ARCH_HAS_DMA_PREP_COHERENT
@@ -32,6 +33,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
@@ -61,6 +63,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
        select ARCH_USE_QUEUED_RWLOCKS
        select ARCH_USE_QUEUED_SPINLOCKS
        select ARCH_SUPPORTS_MEMORY_FAILURE
@@ -1584,6 +1587,28 @@ endmenu
 
 menu "ARMv8.5 architectural features"
 
+config ARM64_BTI
+       bool "Branch Target Identification support"
+       default y
+       help
+         Branch Target Identification (part of the ARMv8.5 Extensions)
+         provides a mechanism to limit the set of locations to which computed
+         branch instructions such as BR or BLR can jump.
+
+         To make use of BTI on CPUs that support it, say Y.
+
+         BTI is intended to provide complementary protection to other control
+         flow integrity protection mechanisms, such as the Pointer
+         authentication mechanism provided as part of the ARMv8.3 Extensions.
+         For this reason, it does not make sense to enable this option without
+         also enabling support for pointer authentication.  Thus, when
+         enabling this option you should also select ARM64_PTR_AUTH=y.
+
+         Userspace binaries must also be specifically compiled to make use of
+         this mechanism.  If you say N here or the hardware does not support
+         BTI, such binaries can still run, but you get no additional
+         enforcement of branch destinations.
+
 config ARM64_E0PD
        bool "Enable support for E0PD"
        default y
index 8eb5a088ae6588c8c0f2332b31ca92945eda9b66..7b6051494f717116e4c3510167bb5095f2726a6b 100644 (file)
@@ -61,7 +61,8 @@
 #define ARM64_HAS_AMU_EXTN                     51
 #define ARM64_HAS_ADDRESS_AUTH                 52
 #define ARM64_HAS_GENERIC_AUTH                 53
+#define ARM64_BTI                              54
 
-#define ARM64_NCAPS                            54
+#define ARM64_NCAPS                            55
 
 #endif /* __ASM_CPUCAPS_H */
index afe08251ff95640818a89453db51d2127258a11c..99ab13a07a1d7d0d2f2454f2837a9e597fb59f6f 100644 (file)
@@ -680,6 +680,11 @@ static inline bool system_has_prio_mask_debugging(void)
               system_uses_irq_prio_masking();
 }
 
+static inline bool system_supports_bti(void)
+{
+       return IS_ENABLED(CONFIG_ARM64_BTI) && cpus_have_const_cap(ARM64_BTI);
+}
+
 #define ARM64_BP_HARDEN_UNKNOWN                -1
 #define ARM64_BP_HARDEN_WA_NEEDED      0
 #define ARM64_BP_HARDEN_NOT_REQUIRED   1
index b618017205a3f6af4ad612310d0187abdc2d73c1..4f00d50585a4c055756800df1408ddd6d4c4e98b 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 6a395a7e6707bae66291b7ce2c2cd81f2003f262..035003acfa876dd998c56d842ea48e882aa44638 100644 (file)
@@ -22,7 +22,7 @@
 #define ESR_ELx_EC_PAC         (0x09)  /* EL2 and above */
 /* Unallocated EC: 0x0A - 0x0B */
 #define ESR_ELx_EC_CP14_64     (0x0C)
-/* Unallocated EC: 0x0d */
+#define ESR_ELx_EC_BTI         (0x0D)
 #define ESR_ELx_EC_ILL         (0x0E)
 /* Unallocated EC: 0x0F - 0x10 */
 #define ESR_ELx_EC_SVC32       (0x11)
index 7a6e81ca23a8e0ed5a11013fc74f3ca82cefd1c5..7577a754d44343b26c700811c54b9155893b1322 100644 (file)
@@ -34,6 +34,7 @@ static inline u32 disr_to_esr(u64 disr)
 asmlinkage void enter_from_user_mode(void);
 void do_mem_abort(unsigned long addr, unsigned int esr, struct pt_regs *regs);
 void do_undefinstr(struct pt_regs *regs);
+void do_bti(struct pt_regs *regs);
 asmlinkage void bad_mode(struct pt_regs *regs, int reason, unsigned int esr);
 void do_debug_exception(unsigned long addr_if_watchpoint, unsigned int esr,
                        struct pt_regs *regs);
index 0f00265248b5c2d67fab6b9bae98f47dfab8d665..d683bcbf1e7c074fd007a794117a7c66ebe13ea1 100644 (file)
@@ -94,6 +94,7 @@
 #define KERNEL_HWCAP_BF16              __khwcap2_feature(BF16)
 #define KERNEL_HWCAP_DGH               __khwcap2_feature(DGH)
 #define KERNEL_HWCAP_RNG               __khwcap2_feature(RNG)
+#define KERNEL_HWCAP_BTI               __khwcap2_feature(BTI)
 
 /*
  * This yields a mask that user programs can use to figure out what
index a30b4eec7cb40048c92d9d4261765446c2365af8..6ea53e6e8b262b1497de1e9cc4b0b4be493f04c3 100644 (file)
@@ -507,10 +507,12 @@ static inline unsigned long vcpu_data_host_to_guest(struct kvm_vcpu *vcpu,
 
 static __always_inline void kvm_skip_instr(struct kvm_vcpu *vcpu, bool is_wide_instr)
 {
-       if (vcpu_mode_is_32bit(vcpu))
+       if (vcpu_mode_is_32bit(vcpu)) {
                kvm_skip_instr32(vcpu, is_wide_instr);
-       else
+       } else {
                *vcpu_pc(vcpu) += 4;
+               *vcpu_cpsr(vcpu) &= ~PSR_BTYPE_MASK;
+       }
 
        /* advance the singlestep state machine */
        *vcpu_cpsr(vcpu) &= ~DBG_SPSR_SS;
diff --git a/arch/arm64/include/asm/mman.h b/arch/arm64/include/asm/mman.h
new file mode 100644 (file)
index 0000000..081ec8d
--- /dev/null
@@ -0,0 +1,37 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __ASM_MMAN_H__
+#define __ASM_MMAN_H__
+
+#include <linux/compiler.h>
+#include <linux/types.h>
+#include <uapi/asm/mman.h>
+
+static inline unsigned long arch_calc_vm_prot_bits(unsigned long prot,
+       unsigned long pkey __always_unused)
+{
+       if (system_supports_bti() && (prot & PROT_BTI))
+               return VM_ARM64_BTI;
+
+       return 0;
+}
+#define arch_calc_vm_prot_bits(prot, pkey) arch_calc_vm_prot_bits(prot, pkey)
+
+static inline pgprot_t arch_vm_get_page_prot(unsigned long vm_flags)
+{
+       return (vm_flags & VM_ARM64_BTI) ? __pgprot(PTE_GP) : __pgprot(0);
+}
+#define arch_vm_get_page_prot(vm_flags) arch_vm_get_page_prot(vm_flags)
+
+static inline bool arch_validate_prot(unsigned long prot,
+       unsigned long addr __always_unused)
+{
+       unsigned long supported = PROT_READ | PROT_WRITE | PROT_EXEC | PROT_SEM;
+
+       if (system_supports_bti())
+               supported |= PROT_BTI;
+
+       return (prot & ~supported) == 0;
+}
+#define arch_validate_prot(prot, addr) arch_validate_prot(prot, addr)
+
+#endif /* ! __ASM_MMAN_H__ */
index 6bf5e650da7883ba560f2f43a037d4f69facc3e4..167f1d1d48aa64ef4d2346646ae247c84db2a047 100644 (file)
 #define PTE_SHARED             (_AT(pteval_t, 3) << 8)         /* SH[1:0], inner shareable */
 #define PTE_AF                 (_AT(pteval_t, 1) << 10)        /* Access Flag */
 #define PTE_NG                 (_AT(pteval_t, 1) << 11)        /* nG */
+#define PTE_GP                 (_AT(pteval_t, 1) << 50)        /* BTI guarded */
 #define PTE_DBM                        (_AT(pteval_t, 1) << 51)        /* Dirty Bit Management */
 #define PTE_CONT               (_AT(pteval_t, 1) << 52)        /* Contiguous range */
 #define PTE_PXN                        (_AT(pteval_t, 1) << 53)        /* Privileged XN */
index 538c85e62f86d5fbd2f064a66278b917deab240e..4fbf516d8cb238acf0209adbb2746554eab3d938 100644 (file)
@@ -660,7 +660,7 @@ static inline phys_addr_t pgd_page_paddr(pgd_t pgd)
 static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
 {
        const pteval_t mask = PTE_USER | PTE_PXN | PTE_UXN | PTE_RDONLY |
-                             PTE_PROT_NONE | PTE_VALID | PTE_WRITE;
+                             PTE_PROT_NONE | PTE_VALID | PTE_WRITE | PTE_GP;
        /* preserve the hardware dirty information */
        if (pte_hw_dirty(pte))
                pte = pte_mkdirty(pte);
index bf57308fcd635e0451bdc716c42646518ac72743..2172ec7594ba5435e7dfef1ebd45f629ef87e3b9 100644 (file)
@@ -35,6 +35,7 @@
 #define GIC_PRIO_PSR_I_SET             (1 << 4)
 
 /* Additional SPSR bits not exposed in the UABI */
+
 #define PSR_IL_BIT             (1 << 20)
 
 /* AArch32-specific ptrace requests */
index c4ac0ac25a00809bb36d45adcfcd00e5ff369eca..2918eb19f15399a3a8fdab19e0895e00aef29ca1 100644 (file)
 #endif
 
 /* SCTLR_EL1 specific flags. */
+#define SCTLR_EL1_BT1          (BIT(36))
+#define SCTLR_EL1_BT0          (BIT(35))
 #define SCTLR_EL1_UCI          (BIT(26))
 #define SCTLR_EL1_E0E          (BIT(24))
 #define SCTLR_EL1_SPAN         (BIT(23))
 
 /* id_aa64pfr1 */
 #define ID_AA64PFR1_SSBS_SHIFT         4
+#define ID_AA64PFR1_BT_SHIFT           0
 
 #define ID_AA64PFR1_SSBS_PSTATE_NI     0
 #define ID_AA64PFR1_SSBS_PSTATE_ONLY   1
 #define ID_AA64PFR1_SSBS_PSTATE_INSNS  2
+#define ID_AA64PFR1_BT_BTI             0x1
 
 /* id_aa64zfr0 */
 #define ID_AA64ZFR0_F64MM_SHIFT                56
index 7752d93bb50fa486d8e6df27049775e1d61572e8..2d6ba1c2592ed1d825a7a51fd645fd62f5a25647 100644 (file)
@@ -73,5 +73,6 @@
 #define HWCAP2_BF16            (1 << 14)
 #define HWCAP2_DGH             (1 << 15)
 #define HWCAP2_RNG             (1 << 16)
+#define HWCAP2_BTI             (1 << 17)
 
 #endif /* _UAPI__ASM_HWCAP_H */
diff --git a/arch/arm64/include/uapi/asm/mman.h b/arch/arm64/include/uapi/asm/mman.h
new file mode 100644 (file)
index 0000000..6fdd71e
--- /dev/null
@@ -0,0 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _UAPI__ASM_MMAN_H
+#define _UAPI__ASM_MMAN_H
+
+#include <asm-generic/mman.h>
+
+#define PROT_BTI       0x10            /* BTI guarded page */
+
+#endif /* ! _UAPI__ASM_MMAN_H */
index d1bb5b69f1ce49578823fc84c588a8b86ac04c20..42cbe34d95ceeb3d9ff2d4fed0f20d0726586cea 100644 (file)
@@ -46,6 +46,7 @@
 #define PSR_I_BIT      0x00000080
 #define PSR_A_BIT      0x00000100
 #define PSR_D_BIT      0x00000200
+#define PSR_BTYPE_MASK 0x00000c00
 #define PSR_SSBS_BIT   0x00001000
 #define PSR_PAN_BIT    0x00400000
 #define PSR_UAO_BIT    0x00800000
@@ -55,6 +56,8 @@
 #define PSR_Z_BIT      0x40000000
 #define PSR_N_BIT      0x80000000
 
+#define PSR_BTYPE_SHIFT                10
+
 /*
  * Groups of PSR bits
  */
 #define PSR_x          0x0000ff00      /* Extension            */
 #define PSR_c          0x000000ff      /* Control              */
 
+/* Convenience names for the values of PSTATE.BTYPE */
+#define PSR_BTYPE_NONE         (0b00 << PSR_BTYPE_SHIFT)
+#define PSR_BTYPE_JC           (0b01 << PSR_BTYPE_SHIFT)
+#define PSR_BTYPE_C            (0b10 << PSR_BTYPE_SHIFT)
+#define PSR_BTYPE_J            (0b11 << PSR_BTYPE_SHIFT)
+
 /* syscall emulation path in ptrace */
 #define PTRACE_SYSEMU            31
 #define PTRACE_SYSEMU_SINGLESTEP  32
index 9fac745aa7bb248771bf113c7b3e8539707af51a..b234d6f71cba6402a57bc833473b77bdfde2edba 100644 (file)
@@ -182,6 +182,8 @@ static const struct arm64_ftr_bits ftr_id_aa64pfr0[] = {
 
 static const struct arm64_ftr_bits ftr_id_aa64pfr1[] = {
        ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR1_SSBS_SHIFT, 4, ID_AA64PFR1_SSBS_PSTATE_NI),
+       ARM64_FTR_BITS(FTR_VISIBLE_IF_IS_ENABLED(CONFIG_ARM64_BTI),
+                                   FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR1_BT_SHIFT, 4, 0),
        ARM64_FTR_END,
 };
 
@@ -1409,6 +1411,21 @@ static bool can_use_gic_priorities(const struct arm64_cpu_capabilities *entry,
 }
 #endif
 
+#ifdef CONFIG_ARM64_BTI
+static void bti_enable(const struct arm64_cpu_capabilities *__unused)
+{
+       /*
+        * Use of X16/X17 for tail-calls and trampolines that jump to
+        * function entry points using BR is a requirement for
+        * marking binaries with GNU_PROPERTY_AARCH64_FEATURE_1_BTI.
+        * So, be strict and forbid other BRs using other registers to
+        * jump onto a PACIxSP instruction:
+        */
+       sysreg_clear_set(sctlr_el1, 0, SCTLR_EL1_BT0 | SCTLR_EL1_BT1);
+       isb();
+}
+#endif /* CONFIG_ARM64_BTI */
+
 /* Internal helper functions to match cpu capability type */
 static bool
 cpucap_late_cpu_optional(const struct arm64_cpu_capabilities *cap)
@@ -1778,6 +1795,19 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
                .sign = FTR_UNSIGNED,
                .min_field_value = 1,
        },
+#endif
+#ifdef CONFIG_ARM64_BTI
+       {
+               .desc = "Branch Target Identification",
+               .capability = ARM64_BTI,
+               .type = ARM64_CPUCAP_SYSTEM_FEATURE,
+               .matches = has_cpuid_feature,
+               .cpu_enable = bti_enable,
+               .sys_reg = SYS_ID_AA64PFR1_EL1,
+               .field_pos = ID_AA64PFR1_BT_SHIFT,
+               .min_field_value = ID_AA64PFR1_BT_BTI,
+               .sign = FTR_UNSIGNED,
+       },
 #endif
        {},
 };
@@ -1888,6 +1918,9 @@ static const struct arm64_cpu_capabilities arm64_elf_hwcaps[] = {
        HWCAP_CAP(SYS_ID_AA64ZFR0_EL1, ID_AA64ZFR0_F64MM_SHIFT, FTR_UNSIGNED, ID_AA64ZFR0_F64MM, CAP_HWCAP, KERNEL_HWCAP_SVEF64MM),
 #endif
        HWCAP_CAP(SYS_ID_AA64PFR1_EL1, ID_AA64PFR1_SSBS_SHIFT, FTR_UNSIGNED, ID_AA64PFR1_SSBS_PSTATE_INSNS, CAP_HWCAP, KERNEL_HWCAP_SSBS),
+#ifdef CONFIG_ARM64_BTI
+       HWCAP_CAP(SYS_ID_AA64PFR1_EL1, ID_AA64PFR1_BT_SHIFT, FTR_UNSIGNED, ID_AA64PFR1_BT_BTI, CAP_HWCAP, KERNEL_HWCAP_BTI),
+#endif
 #ifdef CONFIG_ARM64_PTR_AUTH
        HWCAP_MULTI_CAP(ptr_auth_hwcap_addr_matches, CAP_HWCAP, KERNEL_HWCAP_PACA),
        HWCAP_MULTI_CAP(ptr_auth_hwcap_gen_matches, CAP_HWCAP, KERNEL_HWCAP_PACG),
index 86136075ae41042ec32bb0b755ef38a7ce06d051..5e47e93b5dc152023fc65134c55027706742101c 100644 (file)
@@ -92,6 +92,7 @@ static const char *const hwcap_str[] = {
        "bf16",
        "dgh",
        "rng",
+       "bti",
        NULL
 };
 
index c839b5bf1904b128b0fe7f91d569397b8566d80a..1196eb4f4c762a1225ff300fa99229bcf5b88e59 100644 (file)
@@ -188,6 +188,14 @@ static void notrace el0_undef(struct pt_regs *regs)
 }
 NOKPROBE_SYMBOL(el0_undef);
 
+static void notrace el0_bti(struct pt_regs *regs)
+{
+       user_exit_irqoff();
+       local_daif_restore(DAIF_PROCCTX);
+       do_bti(regs);
+}
+NOKPROBE_SYMBOL(el0_bti);
+
 static void notrace el0_inv(struct pt_regs *regs, unsigned long esr)
 {
        user_exit_irqoff();
@@ -255,6 +263,9 @@ asmlinkage void notrace el0_sync_handler(struct pt_regs *regs)
        case ESR_ELx_EC_UNKNOWN:
                el0_undef(regs);
                break;
+       case ESR_ELx_EC_BTI:
+               el0_bti(regs);
+               break;
        case ESR_ELx_EC_BREAKPT_LOW:
        case ESR_ELx_EC_SOFTSTP_LOW:
        case ESR_ELx_EC_WATCHPT_LOW:
index 56be4cbf771f604a849f958382aec9acdf4e837f..eade7807e819d5637ea157315819ca136153e43d 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>
@@ -209,6 +211,15 @@ void machine_restart(char *cmd)
        while (1);
 }
 
+#define bstr(suffix, str) [PSR_BTYPE_ ## suffix >> PSR_BTYPE_SHIFT] = str
+static const char *const btypes[] = {
+       bstr(NONE, "--"),
+       bstr(  JC, "jc"),
+       bstr(   C, "-c"),
+       bstr(  J , "j-")
+};
+#undef bstr
+
 static void print_pstate(struct pt_regs *regs)
 {
        u64 pstate = regs->pstate;
@@ -227,7 +238,10 @@ static void print_pstate(struct pt_regs *regs)
                        pstate & PSR_AA32_I_BIT ? 'I' : 'i',
                        pstate & PSR_AA32_F_BIT ? 'F' : 'f');
        } else {
-               printk("pstate: %08llx (%c%c%c%c %c%c%c%c %cPAN %cUAO)\n",
+               const char *btype_str = btypes[(pstate & PSR_BTYPE_MASK) >>
+                                              PSR_BTYPE_SHIFT];
+
+               printk("pstate: %08llx (%c%c%c%c %c%c%c%c %cPAN %cUAO BTYPE=%s)\n",
                        pstate,
                        pstate & PSR_N_BIT ? 'N' : 'n',
                        pstate & PSR_Z_BIT ? 'Z' : 'z',
@@ -238,7 +252,8 @@ static void print_pstate(struct pt_regs *regs)
                        pstate & PSR_I_BIT ? 'I' : 'i',
                        pstate & PSR_F_BIT ? 'F' : 'f',
                        pstate & PSR_PAN_BIT ? '+' : '-',
-                       pstate & PSR_UAO_BIT ? '+' : '-');
+                       pstate & PSR_UAO_BIT ? '+' : '-',
+                       btype_str);
        }
 }
 
@@ -655,3 +670,25 @@ 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)
+{
+       /*
+        * For dynamically linked executables the interpreter is
+        * responsible for setting PROT_BTI on everything except
+        * itself.
+        */
+       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 b3d3005d9515de52dc5527696049aaffcc9633dd..585dd7f5c826cd04232a11b765f5928193d7b707 100644 (file)
@@ -1874,7 +1874,7 @@ void syscall_trace_exit(struct pt_regs *regs)
  */
 #define SPSR_EL1_AARCH64_RES0_BITS \
        (GENMASK_ULL(63, 32) | GENMASK_ULL(27, 25) | GENMASK_ULL(23, 22) | \
-        GENMASK_ULL(20, 13) | GENMASK_ULL(11, 10) | GENMASK_ULL(5, 5))
+        GENMASK_ULL(20, 13) | GENMASK_ULL(5, 5))
 #define SPSR_EL1_AARCH32_RES0_BITS \
        (GENMASK_ULL(63, 32) | GENMASK_ULL(22, 22) | GENMASK_ULL(20, 20))
 
index 339882db5a9159bfd888d933dc5fff235408e475..801d56cdf70176530b6ce95e444714c362a3500b 100644 (file)
@@ -732,6 +732,22 @@ static void setup_return(struct pt_regs *regs, struct k_sigaction *ka,
        regs->regs[29] = (unsigned long)&user->next_frame->fp;
        regs->pc = (unsigned long)ka->sa.sa_handler;
 
+       /*
+        * Signal delivery is a (wacky) indirect function call in
+        * userspace, so simulate the same setting of BTYPE as a BLR
+        * <register containing the signal handler entry point>.
+        * Signal delivery to a location in a PROT_BTI guarded page
+        * that is not a function entry point will now trigger a
+        * SIGILL in userspace.
+        *
+        * If the signal handler entry point is not in a PROT_BTI
+        * guarded page, this is harmless.
+        */
+       if (system_supports_bti()) {
+               regs->pstate &= ~PSR_BTYPE_MASK;
+               regs->pstate |= PSR_BTYPE_C;
+       }
+
        if (ka->sa.sa_flags & SA_RESTORER)
                sigtramp = ka->sa.sa_restorer;
        else
index a12c0c88d3457357de64c32863690726639112f2..5f5b868292f52233f7d2b7f21f1f3d8d1ac5bdb6 100644 (file)
@@ -98,6 +98,24 @@ static void el0_svc_common(struct pt_regs *regs, int scno, int sc_nr,
        regs->orig_x0 = regs->regs[0];
        regs->syscallno = scno;
 
+       /*
+        * BTI note:
+        * The architecture does not guarantee that SPSR.BTYPE is zero
+        * on taking an SVC, so we could return to userspace with a
+        * non-zero BTYPE after the syscall.
+        *
+        * This shouldn't matter except when userspace is explicitly
+        * doing something stupid, such as setting PROT_BTI on a page
+        * that lacks conforming BTI/PACIxSP instructions, falling
+        * through from one executable page to another with differing
+        * PROT_BTI, or messing with BTYPE via ptrace: in such cases,
+        * userspace should not be surprised if a SIGILL occurs on
+        * syscall return.
+        *
+        * So, don't touch regs->pstate & PSR_BTYPE_MASK here.
+        * (Similarly for HVC and SMC elsewhere.)
+        */
+
        cortex_a76_erratum_1463225_svc_handler();
        local_daif_restore(DAIF_PROCCTX);
        user_exit();
index cf402be5c573ff882797422ee02bc913d7c17f24..10d6451b27761810a2fcd1b281ef346b13aea890 100644 (file)
@@ -272,6 +272,61 @@ void arm64_notify_die(const char *str, struct pt_regs *regs,
        }
 }
 
+#ifdef CONFIG_COMPAT
+#define PSTATE_IT_1_0_SHIFT    25
+#define PSTATE_IT_1_0_MASK     (0x3 << PSTATE_IT_1_0_SHIFT)
+#define PSTATE_IT_7_2_SHIFT    10
+#define PSTATE_IT_7_2_MASK     (0x3f << PSTATE_IT_7_2_SHIFT)
+
+static u32 compat_get_it_state(struct pt_regs *regs)
+{
+       u32 it, pstate = regs->pstate;
+
+       it  = (pstate & PSTATE_IT_1_0_MASK) >> PSTATE_IT_1_0_SHIFT;
+       it |= ((pstate & PSTATE_IT_7_2_MASK) >> PSTATE_IT_7_2_SHIFT) << 2;
+
+       return it;
+}
+
+static void compat_set_it_state(struct pt_regs *regs, u32 it)
+{
+       u32 pstate_it;
+
+       pstate_it  = (it << PSTATE_IT_1_0_SHIFT) & PSTATE_IT_1_0_MASK;
+       pstate_it |= ((it >> 2) << PSTATE_IT_7_2_SHIFT) & PSTATE_IT_7_2_MASK;
+
+       regs->pstate &= ~PSR_AA32_IT_MASK;
+       regs->pstate |= pstate_it;
+}
+
+static void advance_itstate(struct pt_regs *regs)
+{
+       u32 it;
+
+       /* ARM mode */
+       if (!(regs->pstate & PSR_AA32_T_BIT) ||
+           !(regs->pstate & PSR_AA32_IT_MASK))
+               return;
+
+       it  = compat_get_it_state(regs);
+
+       /*
+        * If this is the last instruction of the block, wipe the IT
+        * state. Otherwise advance it.
+        */
+       if (!(it & 7))
+               it = 0;
+       else
+               it = (it & 0xe0) | ((it << 1) & 0x1f);
+
+       compat_set_it_state(regs, it);
+}
+#else
+static void advance_itstate(struct pt_regs *regs)
+{
+}
+#endif
+
 void arm64_skip_faulting_instruction(struct pt_regs *regs, unsigned long size)
 {
        regs->pc += size;
@@ -282,6 +337,11 @@ void arm64_skip_faulting_instruction(struct pt_regs *regs, unsigned long size)
         */
        if (user_mode(regs))
                user_fastforward_single_step(current);
+
+       if (compat_user_mode(regs))
+               advance_itstate(regs);
+       else
+               regs->pstate &= ~PSR_BTYPE_MASK;
 }
 
 static LIST_HEAD(undef_hook);
@@ -411,6 +471,13 @@ void do_undefinstr(struct pt_regs *regs)
 }
 NOKPROBE_SYMBOL(do_undefinstr);
 
+void do_bti(struct pt_regs *regs)
+{
+       BUG_ON(!user_mode(regs));
+       force_signal_inject(SIGILL, ILL_ILLOPC, regs->pc);
+}
+NOKPROBE_SYMBOL(do_bti);
+
 #define __user_cache_maint(insn, address, res)                 \
        if (address >= user_addr_max()) {                       \
                res = -EFAULT;                                  \
@@ -566,34 +633,7 @@ static const struct sys64_hook sys64_hooks[] = {
        {},
 };
 
-
 #ifdef CONFIG_COMPAT
-#define PSTATE_IT_1_0_SHIFT    25
-#define PSTATE_IT_1_0_MASK     (0x3 << PSTATE_IT_1_0_SHIFT)
-#define PSTATE_IT_7_2_SHIFT    10
-#define PSTATE_IT_7_2_MASK     (0x3f << PSTATE_IT_7_2_SHIFT)
-
-static u32 compat_get_it_state(struct pt_regs *regs)
-{
-       u32 it, pstate = regs->pstate;
-
-       it  = (pstate & PSTATE_IT_1_0_MASK) >> PSTATE_IT_1_0_SHIFT;
-       it |= ((pstate & PSTATE_IT_7_2_MASK) >> PSTATE_IT_7_2_SHIFT) << 2;
-
-       return it;
-}
-
-static void compat_set_it_state(struct pt_regs *regs, u32 it)
-{
-       u32 pstate_it;
-
-       pstate_it  = (it << PSTATE_IT_1_0_SHIFT) & PSTATE_IT_1_0_MASK;
-       pstate_it |= ((it >> 2) << PSTATE_IT_7_2_SHIFT) & PSTATE_IT_7_2_MASK;
-
-       regs->pstate &= ~PSR_AA32_IT_MASK;
-       regs->pstate |= pstate_it;
-}
-
 static bool cp15_cond_valid(unsigned int esr, struct pt_regs *regs)
 {
        int cond;
@@ -614,42 +654,12 @@ static bool cp15_cond_valid(unsigned int esr, struct pt_regs *regs)
        return aarch32_opcode_cond_checks[cond](regs->pstate);
 }
 
-static void advance_itstate(struct pt_regs *regs)
-{
-       u32 it;
-
-       /* ARM mode */
-       if (!(regs->pstate & PSR_AA32_T_BIT) ||
-           !(regs->pstate & PSR_AA32_IT_MASK))
-               return;
-
-       it  = compat_get_it_state(regs);
-
-       /*
-        * If this is the last instruction of the block, wipe the IT
-        * state. Otherwise advance it.
-        */
-       if (!(it & 7))
-               it = 0;
-       else
-               it = (it & 0xe0) | ((it << 1) & 0x1f);
-
-       compat_set_it_state(regs, it);
-}
-
-static void arm64_compat_skip_faulting_instruction(struct pt_regs *regs,
-                                                  unsigned int sz)
-{
-       advance_itstate(regs);
-       arm64_skip_faulting_instruction(regs, sz);
-}
-
 static void compat_cntfrq_read_handler(unsigned int esr, struct pt_regs *regs)
 {
        int reg = (esr & ESR_ELx_CP15_32_ISS_RT_MASK) >> ESR_ELx_CP15_32_ISS_RT_SHIFT;
 
        pt_regs_write_reg(regs, reg, arch_timer_get_rate());
-       arm64_compat_skip_faulting_instruction(regs, 4);
+       arm64_skip_faulting_instruction(regs, 4);
 }
 
 static const struct sys64_hook cp15_32_hooks[] = {
@@ -669,7 +679,7 @@ static void compat_cntvct_read_handler(unsigned int esr, struct pt_regs *regs)
 
        pt_regs_write_reg(regs, rt, lower_32_bits(val));
        pt_regs_write_reg(regs, rt2, upper_32_bits(val));
-       arm64_compat_skip_faulting_instruction(regs, 4);
+       arm64_skip_faulting_instruction(regs, 4);
 }
 
 static const struct sys64_hook cp15_64_hooks[] = {
@@ -690,7 +700,7 @@ void do_cp15instr(unsigned int esr, struct pt_regs *regs)
                 * There is no T16 variant of a CP access, so we
                 * always advance PC by 4 bytes.
                 */
-               arm64_compat_skip_faulting_instruction(regs, 4);
+               arm64_skip_faulting_instruction(regs, 4);
                return;
        }
 
@@ -753,6 +763,7 @@ static const char *esr_class_str[] = {
        [ESR_ELx_EC_CP10_ID]            = "CP10 MRC/VMRS",
        [ESR_ELx_EC_PAC]                = "PAC",
        [ESR_ELx_EC_CP14_64]            = "CP14 MCRR/MRRC",
+       [ESR_ELx_EC_BTI]                = "BTI",
        [ESR_ELx_EC_ILL]                = "PSTATE.IL",
        [ESR_ELx_EC_SVC32]              = "SVC (AArch32)",
        [ESR_ELx_EC_HVC32]              = "HVC (AArch32)",
index 860c00ec8bd32a7307ef2326df25364f52c609c9..78163b7a7dde4271a0dc670c5d4bd5abe5761e1d 100644 (file)
@@ -145,6 +145,11 @@ static const struct prot_bits pte_bits[] = {
                .val    = PTE_UXN,
                .set    = "UXN",
                .clear  = "   ",
+       }, {
+               .mask   = PTE_GP,
+               .val    = PTE_GP,
+               .set    = "GP",
+               .clear  = "  ",
        }, {
                .mask   = PTE_ATTRINDX_MASK,
                .val    = PTE_ATTRINDX(MT_DEVICE_nGnRnE),
index 62dc4f577ba1330e0f373719b33692b97a5aad15..2358368319b8a0e10e805b6b80e94fc311e3df36 100644 (file)
@@ -36,6 +36,12 @@ config COMPAT_BINFMT_ELF
 config ARCH_BINFMT_ELF_STATE
        bool
 
+config ARCH_HAVE_ELF_PROT
+       bool
+
+config ARCH_USE_GNU_PROPERTY
+       bool
+
 config BINFMT_ELF_FDPIC
        bool "Kernel support for FDPIC ELF binaries"
        default y if !BINFMT_ELF
index 13f25e241ac46cbd2f5ffa23de45e60a035a0c1a..4adb963cdb830661c794969272a8aeb5e23ee578 100644 (file)
 #include <linux/sched/coredump.h>
 #include <linux/sched/task_stack.h>
 #include <linux/sched/cputime.h>
+#include <linux/sizes.h>
+#include <linux/types.h>
 #include <linux/cred.h>
 #include <linux/dax.h>
 #include <linux/uaccess.h>
 #include <asm/param.h>
 #include <asm/page.h>
 
+#ifndef ELF_COMPAT
+#define ELF_COMPAT 0
+#endif
+
 #ifndef user_long_t
 #define user_long_t long
 #endif
@@ -539,7 +545,8 @@ static inline int arch_check_elf(struct elfhdr *ehdr, bool has_interp,
 
 #endif /* !CONFIG_ARCH_BINFMT_ELF_STATE */
 
-static inline int make_prot(u32 p_flags)
+static inline int make_prot(u32 p_flags, struct arch_elf_state *arch_state,
+                           bool has_interp, bool is_interp)
 {
        int prot = 0;
 
@@ -549,7 +556,8 @@ static inline int make_prot(u32 p_flags)
                prot |= PROT_WRITE;
        if (p_flags & PF_X)
                prot |= PROT_EXEC;
-       return prot;
+
+       return arch_elf_adjust_prot(prot, arch_state, has_interp, is_interp);
 }
 
 /* This is much more generalized than the library routine read function,
@@ -559,7 +567,8 @@ static inline int make_prot(u32 p_flags)
 
 static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex,
                struct file *interpreter,
-               unsigned long no_base, struct elf_phdr *interp_elf_phdata)
+               unsigned long no_base, struct elf_phdr *interp_elf_phdata,
+               struct arch_elf_state *arch_state)
 {
        struct elf_phdr *eppnt;
        unsigned long load_addr = 0;
@@ -591,7 +600,8 @@ static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex,
        for (i = 0; i < interp_elf_ex->e_phnum; i++, eppnt++) {
                if (eppnt->p_type == PT_LOAD) {
                        int elf_type = MAP_PRIVATE | MAP_DENYWRITE;
-                       int elf_prot = make_prot(eppnt->p_flags);
+                       int elf_prot = make_prot(eppnt->p_flags, arch_state,
+                                                true, true);
                        unsigned long vaddr = 0;
                        unsigned long k, map_addr;
 
@@ -682,6 +692,111 @@ out:
  * libraries.  There is no binary dependent code anywhere else.
  */
 
+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 o, step;
+       const struct gnu_property *pr;
+       int ret;
+
+       if (*off == datasz)
+               return -ENOENT;
+
+       if (WARN_ON_ONCE(*off > datasz || *off % ELF_GNU_PROPERTY_ALIGN))
+               return -EIO;
+       o = *off;
+       datasz -= *off;
+
+       if (datasz < sizeof(*pr))
+               return -ENOEXEC;
+       pr = (const struct gnu_property *)(data + o);
+       o += sizeof(*pr);
+       datasz -= sizeof(*pr);
+
+       if (pr->pr_datasz > datasz)
+               return -ENOEXEC;
+
+       WARN_ON_ONCE(o % ELF_GNU_PROPERTY_ALIGN);
+       step = round_up(pr->pr_datasz, ELF_GNU_PROPERTY_ALIGN);
+       if (step > datasz)
+               return -ENOEXEC;
+
+       /* Properties are supposed to be unique and sorted on pr_type: */
+       if (have_prev_type && pr->pr_type <= *prev_type)
+               return -ENOEXEC;
+       *prev_type = pr->pr_type;
+
+       ret = arch_parse_elf_property(pr->pr_type, data + o,
+                                     pr->pr_datasz, ELF_COMPAT, arch);
+       if (ret)
+               return ret;
+
+       *off = o + 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_ONCE(phdr->p_type != PT_GNU_PROPERTY))
+               return -ENOEXEC;
+
+       /* 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, &note, 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 -ENOEXEC;
+
+       off = round_up(sizeof(note.nhdr) + NOTE_NAME_SZ,
+                      ELF_GNU_PROPERTY_ALIGN);
+       if (off > n)
+               return -ENOEXEC;
+
+       if (note.nhdr.n_descsz > n - off)
+               return -ENOEXEC;
+       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 */
@@ -689,6 +804,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;
@@ -726,6 +842,11 @@ static int load_elf_binary(struct linux_binprm *bprm)
        for (i = 0; i < elf_ex->e_phnum; i++, elf_ppnt++) {
                char *elf_interpreter;
 
+               if (elf_ppnt->p_type == PT_GNU_PROPERTY) {
+                       elf_property_phdata = elf_ppnt;
+                       continue;
+               }
+
                if (elf_ppnt->p_type != PT_INTERP)
                        continue;
 
@@ -819,9 +940,14 @@ out_free_interp:
                        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 < 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(interp_elf_ex,
                                                          elf_ppnt, interpreter,
@@ -832,6 +958,11 @@ out_free_interp:
                        }
        }
 
+       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
@@ -913,7 +1044,8 @@ out_free_interp:
                        }
                }
 
-               elf_prot = make_prot(elf_ppnt->p_flags);
+               elf_prot = make_prot(elf_ppnt->p_flags, &arch_state,
+                                    !!interpreter, false);
 
                elf_flags = MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE;
 
@@ -1056,7 +1188,8 @@ out_free_interp:
        if (interpreter) {
                elf_entry = load_elf_interp(interp_elf_ex,
                                            interpreter,
-                                           load_bias, interp_elf_phdata);
+                                           load_bias, interp_elf_phdata,
+                                           &arch_state);
                if (!IS_ERR((void *)elf_entry)) {
                        /*
                         * load_elf_interp() returns relocation
index aaad4ca1217ef116494ea7315de081b0f3c36c4c..13a087bc816bcdc72af2d2bec8e2ecbd0eeffe0b 100644 (file)
@@ -17,6 +17,8 @@
 #include <linux/elfcore-compat.h>
 #include <linux/time.h>
 
+#define ELF_COMPAT     1
+
 /*
  * Rename the basic ELF layout types to refer to the 32-bit class of files.
  */
 #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.
index 8d382d4ec0672f32549ac9b2dd9d156fb16dd1da..b73cdbb221e8d3d4cea62c5de916847a19f1c754 100644 (file)
@@ -638,6 +638,9 @@ static void show_smap_vma_flags(struct seq_file *m, struct vm_area_struct *vma)
                [ilog2(VM_ARCH_1)]      = "ar",
                [ilog2(VM_WIPEONFORK)]  = "wf",
                [ilog2(VM_DONTDUMP)]    = "dd",
+#ifdef CONFIG_ARM64_BTI
+               [ilog2(VM_ARM64_BTI)]   = "bt",
+#endif
 #ifdef CONFIG_MEM_SOFT_DIRTY
                [ilog2(VM_SOFTDIRTY)]   = "sd",
 #endif
index e3649b3e970e63d325958e2c31aebbe1ef16586e..5d5b0321da0bd81db3afa2bbe802252ca7e58a94 100644 (file)
@@ -2,6 +2,7 @@
 #ifndef _LINUX_ELF_H
 #define _LINUX_ELF_H
 
+#include <linux/types.h>
 #include <asm/elf.h>
 #include <uapi/linux/elf.h>
 
@@ -21,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 [];
@@ -31,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
 
@@ -42,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
 
@@ -56,4 +62,41 @@ 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:
+ * Keep this internal until/unless there is an agreed UAPI definition.
+ * pr_type values (GNU_PROPERTY_*) are public and defined in the UAPI header.
+ */
+struct gnu_property {
+       u32 pr_type;
+       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
+
+#ifdef CONFIG_ARCH_HAVE_ELF_PROT
+int arch_elf_adjust_prot(int prot, const struct arch_elf_state *state,
+                        bool has_interp, bool is_interp);
+#else
+static inline int arch_elf_adjust_prot(int prot,
+                                      const struct arch_elf_state *state,
+                                      bool has_interp, bool is_interp)
+{
+       return prot;
+}
+#endif
+
 #endif /* _LINUX_ELF_H */
index 5a323422d783d076c01b41b2a9a1f4bbd7d1a6a5..b61ca546eea4fcbd8e12b6c258d05e6c02c97189 100644 (file)
@@ -325,6 +325,9 @@ extern unsigned int kobjsize(const void *objp);
 #elif defined(CONFIG_SPARC64)
 # define VM_SPARC_ADI  VM_ARCH_1       /* Uses ADI tag for access control */
 # define VM_ARCH_CLEAR VM_SPARC_ADI
+#elif defined(CONFIG_ARM64)
+# define VM_ARM64_BTI  VM_ARCH_1       /* BTI guarded page, a.k.a. GP bit */
+# define VM_ARCH_CLEAR VM_ARM64_BTI
 #elif !defined(CONFIG_MMU)
 # define VM_MAPPED_COPY        VM_ARCH_1       /* T if mapped copy of data (nommu mmap) */
 #endif
index 34c02e4290fe5b7970b432052ddbd0beb8943f8a..c6dd0215482efc693b9d9ec9a4a8848e09b87223 100644 (file)
@@ -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)
 
@@ -367,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
@@ -429,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 */
@@ -443,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 */