Merge branch 'for-next/bti-user' into for-next/bti
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
This commit is contained in:
commit
80e4e56132
@ -176,6 +176,8 @@ infrastructure:
|
||||
+------------------------------+---------+---------+
|
||||
| SSBS | [7-4] | y |
|
||||
+------------------------------+---------+---------+
|
||||
| BT | [3-0] | y |
|
||||
+------------------------------+---------+---------+
|
||||
|
||||
|
||||
4) MIDR_EL1 - Main ID Register
|
||||
|
@ -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
|
||||
-----------------------
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
|
@ -114,7 +114,11 @@
|
||||
|
||||
#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
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
37
arch/arm64/include/asm/mman.h
Normal file
37
arch/arm64/include/asm/mman.h
Normal file
@ -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__ */
|
@ -151,6 +151,7 @@
|
||||
#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 */
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
|
@ -552,6 +552,8 @@
|
||||
#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))
|
||||
@ -660,10 +662,12 @@
|
||||
|
||||
/* 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
|
||||
|
@ -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 */
|
||||
|
9
arch/arm64/include/uapi/asm/mman.h
Normal file
9
arch/arm64/include/uapi/asm/mman.h
Normal file
@ -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 */
|
@ -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
|
||||
*/
|
||||
@ -63,6 +66,12 @@
|
||||
#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
|
||||
|
@ -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),
|
||||
|
@ -92,6 +92,7 @@ static const char *const hwcap_str[] = {
|
||||
"bf16",
|
||||
"dgh",
|
||||
"rng",
|
||||
"bti",
|
||||
NULL
|
||||
};
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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))
|
||||
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
@ -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)",
|
||||
|
@ -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),
|
||||
|
@ -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
|
||||
|
145
fs/binfmt_elf.c
145
fs/binfmt_elf.c
@ -40,12 +40,18 @@
|
||||
#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, ¬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 -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
|
||||
|
@ -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.
|
||||
*/
|
||||
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
Loading…
Reference in New Issue
Block a user