2020-03-16 16:51:31

by Mark Brown

[permalink] [raw]
Subject: [PATCH v10 00/13] arm64: Branch Target Identification support

This patch series implements support for ARMv8.5-A Branch Target
Identification (BTI), which is a control flow integrity protection
feature introduced as part of the ARMv8.5-A extensions.

Changes:

v10:
- Fix build for !COMPAT configurations.
v9:
- Move Kconfig addition to final patch in series.
- Add patch from Daniel Kiss adding BTI information to smaps, this has
a trivial conflict with a .rst conversion in -next.
v8:
- Remove a redundant IS_ENABLED(CONFIG_ARM64_BTI) check.
v7:
- Rebase onto v5.6-rc3.
- Move comment about keeping NT_GNU_PROPERTY_TYPE_0 internal into first
patch.
- Add an explicit check for system_supports_bti() when parsing BTI ELF
property for improved robustness.
v6:
- Rebase onto v5.6-rc1.
- Fix typos s/BYTPE/BTYPE/ in commit log for "arm64: BTI: Decode BYTPE
bits when printing PSTATE".
v5:
- Changed a bunch of -EIO to -ENOEXEC in the ELF parsing code.
- Move PSR_BTYPE defines to UAPI.
- Use compat_user_mode() rather than open coding.
- Fix a typo s/BYTPE/BTYPE/ in syscall.c
v4:
- Dropped patch fixing existing documentation as it has already been merged.
- Convert WARN_ON() to WARN_ON_ONCE() in "ELF: Add ELF program property
parsing support".
- Added display of guarded pages to ptdump.
- Updated for conversion of exception handling from assembler to C.

Notes:

* GCC 9 can compile backwards-compatible BTI-enabled code with
-mbranch-protection=bti or -mbranch-protection=standard.

* Binutils 2.33 and later support the new ELF note.

Creation of a BTI-enabled binary requires _everything_ linked in to
be BTI-enabled. For now ld --force-bti can be used to override this,
but some things may break until the required C library support is in
place.

There is no straightforward way to mark a .s file as BTI-enabled:
scraping the output from gcc -S works as a quick hack for now.

readelf -n can be used to examing the program properties in an ELF
file.

* Runtime mmap() and mprotect() can be used to enable BTI on a
page-by-page basis using the new PROT_BTI, but the code in the
affected pages still needs to be written or compiled to contain the
appropriate BTI landing pads.

Daniel Kiss (1):
mm: smaps: Report arm64 guarded pages in smaps

Dave Martin (11):
ELF: UAPI and Kconfig additions for ELF program properties
ELF: Add ELF program property parsing support
arm64: Basic Branch Target Identification support
elf: Allow arch to tweak initial mmap prot flags
arm64: elf: Enable BTI at exec based on ELF program properties
arm64: BTI: Decode BYTPE bits when printing PSTATE
arm64: unify native/compat instruction skipping
arm64: traps: Shuffle code to eliminate forward declarations
arm64: BTI: Reset BTYPE when skipping emulated instructions
KVM: arm64: BTI: Reset BTYPE when skipping emulated instructions
arm64: BTI: Add Kconfig entry for userspace BTI

Mark Brown (1):
arm64: mm: Display guarded pages in ptdump

Documentation/arm64/cpu-feature-registers.rst | 2 +
Documentation/arm64/elf_hwcaps.rst | 5 +
Documentation/filesystems/proc.txt | 1 +
arch/arm64/Kconfig | 25 +++
arch/arm64/include/asm/cpucaps.h | 3 +-
arch/arm64/include/asm/cpufeature.h | 6 +
arch/arm64/include/asm/elf.h | 50 ++++++
arch/arm64/include/asm/esr.h | 2 +-
arch/arm64/include/asm/exception.h | 1 +
arch/arm64/include/asm/hwcap.h | 1 +
arch/arm64/include/asm/kvm_emulate.h | 6 +-
arch/arm64/include/asm/mman.h | 37 +++++
arch/arm64/include/asm/pgtable-hwdef.h | 1 +
arch/arm64/include/asm/pgtable.h | 2 +-
arch/arm64/include/asm/ptrace.h | 1 +
arch/arm64/include/asm/sysreg.h | 4 +
arch/arm64/include/uapi/asm/hwcap.h | 1 +
arch/arm64/include/uapi/asm/mman.h | 9 ++
arch/arm64/include/uapi/asm/ptrace.h | 9 ++
arch/arm64/kernel/cpufeature.c | 33 ++++
arch/arm64/kernel/cpuinfo.c | 1 +
arch/arm64/kernel/entry-common.c | 11 ++
arch/arm64/kernel/process.c | 36 ++++-
arch/arm64/kernel/ptrace.c | 2 +-
arch/arm64/kernel/signal.c | 16 ++
arch/arm64/kernel/syscall.c | 18 +++
arch/arm64/kernel/traps.c | 131 ++++++++--------
arch/arm64/mm/dump.c | 5 +
fs/Kconfig.binfmt | 6 +
fs/binfmt_elf.c | 145 +++++++++++++++++-
fs/compat_binfmt_elf.c | 4 +
fs/proc/task_mmu.c | 3 +
include/linux/elf.h | 43 ++++++
include/linux/mm.h | 3 +
include/uapi/linux/elf.h | 11 ++
35 files changed, 560 insertions(+), 74 deletions(-)
create mode 100644 arch/arm64/include/asm/mman.h
create mode 100644 arch/arm64/include/uapi/asm/mman.h


base-commit: f8788d86ab28f61f7b46eb6be375f8a726783636
--
2.20.1


2020-03-16 16:51:39

by Mark Brown

[permalink] [raw]
Subject: [PATCH v10 01/13] ELF: UAPI and Kconfig additions for ELF program properties

From: Dave Martin <[email protected]>

Pull the basic ELF definitions relating to the
NT_GNU_PROPERTY_TYPE_0 note from Yu-Cheng Yu's earlier x86 shstk
series.

Signed-off-by: Yu-cheng Yu <[email protected]>
Signed-off-by: Dave Martin <[email protected]>
Reviewed-by: Kees Cook <[email protected]>
Reviewed-by: Catalin Marinas <[email protected]>
Signed-off-by: Mark Brown <[email protected]>
---
fs/Kconfig.binfmt | 3 +++
include/linux/elf.h | 12 ++++++++++++
include/uapi/linux/elf.h | 1 +
3 files changed, 16 insertions(+)

diff --git a/fs/Kconfig.binfmt b/fs/Kconfig.binfmt
index 62dc4f577ba1..d2cfe0729a73 100644
--- a/fs/Kconfig.binfmt
+++ b/fs/Kconfig.binfmt
@@ -36,6 +36,9 @@ config COMPAT_BINFMT_ELF
config ARCH_BINFMT_ELF_STATE
bool

+config ARCH_USE_GNU_PROPERTY
+ bool
+
config BINFMT_ELF_FDPIC
bool "Kernel support for FDPIC ELF binaries"
default y if !BINFMT_ELF
diff --git a/include/linux/elf.h b/include/linux/elf.h
index e3649b3e970e..f7b24c5fcfb6 100644
--- a/include/linux/elf.h
+++ b/include/linux/elf.h
@@ -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>

@@ -56,4 +57,15 @@ static inline int elf_coredump_extra_notes_write(struct coredump_params *cprm) {
extern int elf_coredump_extra_notes_size(void);
extern int elf_coredump_extra_notes_write(struct coredump_params *cprm);
#endif
+
+/*
+ * 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;
+};
+
#endif /* _LINUX_ELF_H */
diff --git a/include/uapi/linux/elf.h b/include/uapi/linux/elf.h
index 34c02e4290fe..c37731407074 100644
--- a/include/uapi/linux/elf.h
+++ b/include/uapi/linux/elf.h
@@ -36,6 +36,7 @@ typedef __s64 Elf64_Sxword;
#define PT_LOPROC 0x70000000
#define PT_HIPROC 0x7fffffff
#define PT_GNU_EH_FRAME 0x6474e550
+#define PT_GNU_PROPERTY 0x6474e553

#define PT_GNU_STACK (PT_LOOS + 0x474e551)

--
2.20.1

2020-03-16 16:51:53

by Mark Brown

[permalink] [raw]
Subject: [PATCH v10 04/13] elf: Allow arch to tweak initial mmap prot flags

From: Dave Martin <[email protected]>

An arch may want to tweak the mmap prot flags for an
ELFexecutable's initial mappings. For example, arm64 is going to
need to add PROT_BTI for executable pages in an ELF process whose
executable is marked as using Branch Target Identification (an
ARMv8.5-A control flow integrity feature).

So that this can be done in a generic way, add a hook
arch_elf_adjust_prot() to modify the prot flags as desired: arches
can select CONFIG_HAVE_ELF_PROT and implement their own backend
where necessary.

By default, leave the prot flags unchanged.

Signed-off-by: Dave Martin <[email protected]>
Reviewed-by: Kees Cook <[email protected]>
Reviewed-by: Catalin Marinas <[email protected]>
Signed-off-by: Mark Brown <[email protected]>
---
fs/Kconfig.binfmt | 3 +++
fs/binfmt_elf.c | 18 ++++++++++++------
include/linux/elf.h | 12 ++++++++++++
3 files changed, 27 insertions(+), 6 deletions(-)

diff --git a/fs/Kconfig.binfmt b/fs/Kconfig.binfmt
index d2cfe0729a73..2358368319b8 100644
--- a/fs/Kconfig.binfmt
+++ b/fs/Kconfig.binfmt
@@ -36,6 +36,9 @@ config COMPAT_BINFMT_ELF
config ARCH_BINFMT_ELF_STATE
bool

+config ARCH_HAVE_ELF_PROT
+ bool
+
config ARCH_USE_GNU_PROPERTY
bool

diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index 1fb67e506b68..cceb29d6ef1d 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -544,7 +544,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;

@@ -554,7 +555,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,
@@ -564,7 +566,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;
@@ -596,7 +599,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;

@@ -1041,7 +1045,8 @@ static int load_elf_binary(struct linux_binprm *bprm)
}
}

- 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;

@@ -1184,7 +1189,8 @@ static int load_elf_binary(struct linux_binprm *bprm)
if (interpreter) {
elf_entry = load_elf_interp(&loc->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
diff --git a/include/linux/elf.h b/include/linux/elf.h
index db5113479f5e..5d5b0321da0b 100644
--- a/include/linux/elf.h
+++ b/include/linux/elf.h
@@ -87,4 +87,16 @@ 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 */
--
2.20.1

2020-03-16 16:52:00

by Mark Brown

[permalink] [raw]
Subject: [PATCH v10 03/13] arm64: Basic Branch Target Identification support

From: Dave Martin <[email protected]>

This patch adds the bare minimum required to expose the ARMv8.5
Branch Target Identification feature to userspace.

By itself, this does _not_ automatically enable BTI for any initial
executable pages mapped by execve(). This will come later, but for
now it should be possible to enable BTI manually on those pages by
using mprotect() from within the target process.

Other arches already using the generic mman.h are already using
0x10 for arch-specific prot flags, so we use that for PROT_BTI
here.

For consistency, signal handler entry points in BTI guarded pages
are required to be annotated as such, just like any other function.
This blocks a relatively minor attack vector, but comforming
userspace will have the annotations anyway, so we may as well
enforce them.

Signed-off-by: Dave Martin <[email protected]>
Signed-off-by: Mark Brown <[email protected]>
Reviewed-by: Catalin Marinas <[email protected]>
---
Documentation/arm64/cpu-feature-registers.rst | 2 +
Documentation/arm64/elf_hwcaps.rst | 5 +++
arch/arm64/include/asm/cpucaps.h | 3 +-
arch/arm64/include/asm/cpufeature.h | 6 +++
arch/arm64/include/asm/esr.h | 2 +-
arch/arm64/include/asm/exception.h | 1 +
arch/arm64/include/asm/hwcap.h | 1 +
arch/arm64/include/asm/mman.h | 37 +++++++++++++++++++
arch/arm64/include/asm/pgtable-hwdef.h | 1 +
arch/arm64/include/asm/pgtable.h | 2 +-
arch/arm64/include/asm/ptrace.h | 1 +
arch/arm64/include/asm/sysreg.h | 4 ++
arch/arm64/include/uapi/asm/hwcap.h | 1 +
arch/arm64/include/uapi/asm/mman.h | 9 +++++
arch/arm64/include/uapi/asm/ptrace.h | 9 +++++
arch/arm64/kernel/cpufeature.c | 33 +++++++++++++++++
arch/arm64/kernel/cpuinfo.c | 1 +
arch/arm64/kernel/entry-common.c | 11 ++++++
arch/arm64/kernel/ptrace.c | 2 +-
arch/arm64/kernel/signal.c | 16 ++++++++
arch/arm64/kernel/syscall.c | 18 +++++++++
arch/arm64/kernel/traps.c | 8 ++++
include/linux/mm.h | 3 ++
23 files changed, 172 insertions(+), 4 deletions(-)
create mode 100644 arch/arm64/include/asm/mman.h
create mode 100644 arch/arm64/include/uapi/asm/mman.h

diff --git a/Documentation/arm64/cpu-feature-registers.rst b/Documentation/arm64/cpu-feature-registers.rst
index 41937a8091aa..314fa5bc2655 100644
--- a/Documentation/arm64/cpu-feature-registers.rst
+++ b/Documentation/arm64/cpu-feature-registers.rst
@@ -176,6 +176,8 @@ infrastructure:
+------------------------------+---------+---------+
| SSBS | [7-4] | y |
+------------------------------+---------+---------+
+ | BT | [3-0] | y |
+ +------------------------------+---------+---------+


4) MIDR_EL1 - Main ID Register
diff --git a/Documentation/arm64/elf_hwcaps.rst b/Documentation/arm64/elf_hwcaps.rst
index 7dfb97dfe416..84a9fd2d41b4 100644
--- a/Documentation/arm64/elf_hwcaps.rst
+++ b/Documentation/arm64/elf_hwcaps.rst
@@ -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
-----------------------

diff --git a/arch/arm64/include/asm/cpucaps.h b/arch/arm64/include/asm/cpucaps.h
index 865e0253fc1e..58e776c22aab 100644
--- a/arch/arm64/include/asm/cpucaps.h
+++ b/arch/arm64/include/asm/cpucaps.h
@@ -58,7 +58,8 @@
#define ARM64_WORKAROUND_SPECULATIVE_AT_NVHE 48
#define ARM64_HAS_E0PD 49
#define ARM64_HAS_RNG 50
+#define ARM64_BTI 51

-#define ARM64_NCAPS 51
+#define ARM64_NCAPS 52

#endif /* __ASM_CPUCAPS_H */
diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h
index 92ef9539874a..e3ebcc59e83b 100644
--- a/arch/arm64/include/asm/cpufeature.h
+++ b/arch/arm64/include/asm/cpufeature.h
@@ -613,6 +613,12 @@ 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);
+}
+
static inline bool system_capabilities_finalized(void)
{
return static_branch_likely(&arm64_const_caps_ready);
diff --git a/arch/arm64/include/asm/esr.h b/arch/arm64/include/asm/esr.h
index cb29253ae86b..390b8ba67830 100644
--- a/arch/arm64/include/asm/esr.h
+++ b/arch/arm64/include/asm/esr.h
@@ -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)
diff --git a/arch/arm64/include/asm/exception.h b/arch/arm64/include/asm/exception.h
index 7a6e81ca23a8..7577a754d443 100644
--- a/arch/arm64/include/asm/exception.h
+++ b/arch/arm64/include/asm/exception.h
@@ -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);
diff --git a/arch/arm64/include/asm/hwcap.h b/arch/arm64/include/asm/hwcap.h
index 0f00265248b5..d683bcbf1e7c 100644
--- a/arch/arm64/include/asm/hwcap.h
+++ b/arch/arm64/include/asm/hwcap.h
@@ -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
diff --git a/arch/arm64/include/asm/mman.h b/arch/arm64/include/asm/mman.h
new file mode 100644
index 000000000000..081ec8de9ea6
--- /dev/null
+++ b/arch/arm64/include/asm/mman.h
@@ -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__ */
diff --git a/arch/arm64/include/asm/pgtable-hwdef.h b/arch/arm64/include/asm/pgtable-hwdef.h
index 6bf5e650da78..167f1d1d48aa 100644
--- a/arch/arm64/include/asm/pgtable-hwdef.h
+++ b/arch/arm64/include/asm/pgtable-hwdef.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 */
diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
index 538c85e62f86..4fbf516d8cb2 100644
--- a/arch/arm64/include/asm/pgtable.h
+++ b/arch/arm64/include/asm/pgtable.h
@@ -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);
diff --git a/arch/arm64/include/asm/ptrace.h b/arch/arm64/include/asm/ptrace.h
index bf57308fcd63..2172ec7594ba 100644
--- a/arch/arm64/include/asm/ptrace.h
+++ b/arch/arm64/include/asm/ptrace.h
@@ -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 */
diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
index b91570ff9db1..db08ceb4cc9a 100644
--- a/arch/arm64/include/asm/sysreg.h
+++ b/arch/arm64/include/asm/sysreg.h
@@ -514,6 +514,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))
@@ -620,10 +622,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
diff --git a/arch/arm64/include/uapi/asm/hwcap.h b/arch/arm64/include/uapi/asm/hwcap.h
index 7752d93bb50f..2d6ba1c2592e 100644
--- a/arch/arm64/include/uapi/asm/hwcap.h
+++ b/arch/arm64/include/uapi/asm/hwcap.h
@@ -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
index 000000000000..6fdd71eb644f
--- /dev/null
+++ b/arch/arm64/include/uapi/asm/mman.h
@@ -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 */
diff --git a/arch/arm64/include/uapi/asm/ptrace.h b/arch/arm64/include/uapi/asm/ptrace.h
index d1bb5b69f1ce..42cbe34d95ce 100644
--- a/arch/arm64/include/uapi/asm/ptrace.h
+++ b/arch/arm64/include/uapi/asm/ptrace.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
diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
index 0b6715625cf6..e6d31776e49b 100644
--- a/arch/arm64/kernel/cpufeature.c
+++ b/arch/arm64/kernel/cpufeature.c
@@ -179,6 +179,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,
};

@@ -1347,6 +1349,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 */
+
static const struct arm64_cpu_capabilities arm64_features[] = {
{
.desc = "GIC system register CPU interface",
@@ -1671,6 +1688,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
{},
};
@@ -1781,6 +1811,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),
diff --git a/arch/arm64/kernel/cpuinfo.c b/arch/arm64/kernel/cpuinfo.c
index 86136075ae41..5e47e93b5dc1 100644
--- a/arch/arm64/kernel/cpuinfo.c
+++ b/arch/arm64/kernel/cpuinfo.c
@@ -92,6 +92,7 @@ static const char *const hwcap_str[] = {
"bf16",
"dgh",
"rng",
+ "bti",
NULL
};

diff --git a/arch/arm64/kernel/entry-common.c b/arch/arm64/kernel/entry-common.c
index fde59981445c..55ec0627f5a7 100644
--- a/arch/arm64/kernel/entry-common.c
+++ b/arch/arm64/kernel/entry-common.c
@@ -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:
diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
index cd6e5fa48b9c..fd8ac7cf68e7 100644
--- a/arch/arm64/kernel/ptrace.c
+++ b/arch/arm64/kernel/ptrace.c
@@ -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))

diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c
index 339882db5a91..801d56cdf701 100644
--- a/arch/arm64/kernel/signal.c
+++ b/arch/arm64/kernel/signal.c
@@ -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
diff --git a/arch/arm64/kernel/syscall.c b/arch/arm64/kernel/syscall.c
index a12c0c88d345..5f5b868292f5 100644
--- a/arch/arm64/kernel/syscall.c
+++ b/arch/arm64/kernel/syscall.c
@@ -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();
diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c
index cf402be5c573..b8c714dda851 100644
--- a/arch/arm64/kernel/traps.c
+++ b/arch/arm64/kernel/traps.c
@@ -411,6 +411,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; \
@@ -753,6 +760,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)",
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 52269e56c514..9e5fce1b2099 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -324,6 +324,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
--
2.20.1

2020-03-16 16:52:10

by Mark Brown

[permalink] [raw]
Subject: [PATCH v10 11/13] arm64: mm: Display guarded pages in ptdump

v8.5-BTI introduces the GP field in stage 1 translation tables which
indicates that blocks and pages with it set are guarded pages for which
branch target identification checks should be performed. Decode this
when dumping the page tables to aid debugging.

Signed-off-by: Mark Brown <[email protected]>
Reviewed-by: Kees Cook <[email protected]>
---
arch/arm64/mm/dump.c | 5 +++++
1 file changed, 5 insertions(+)

diff --git a/arch/arm64/mm/dump.c b/arch/arm64/mm/dump.c
index 860c00ec8bd3..78163b7a7dde 100644
--- a/arch/arm64/mm/dump.c
+++ b/arch/arm64/mm/dump.c
@@ -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),
--
2.20.1

2020-03-16 16:52:17

by Mark Brown

[permalink] [raw]
Subject: [PATCH v10 12/13] mm: smaps: Report arm64 guarded pages in smaps

From: Daniel Kiss <[email protected]>

The arm64 Branch Target Identification support is activated by marking
executable pages as guarded pages. Report pages mapped this way in
smaps to aid diagnostics.

Signed-off-by: Daniel Kiss <[email protected]>
Reviewed-by: Kees Cook <[email protected]>
Signed-off-by: Mark Brown <[email protected]>
---
Documentation/filesystems/proc.txt | 1 +
fs/proc/task_mmu.c | 3 +++
2 files changed, 4 insertions(+)

diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt
index 99ca040e3f90..ed5465d0f435 100644
--- a/Documentation/filesystems/proc.txt
+++ b/Documentation/filesystems/proc.txt
@@ -519,6 +519,7 @@ 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
be present in all further kernel releases. Things get changed, the flags may
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index 3ba9ae83bff5..1e3409c484d1 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -668,6 +668,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.20.1

2020-03-16 16:52:20

by Mark Brown

[permalink] [raw]
Subject: [PATCH v10 13/13] arm64: BTI: Add Kconfig entry for userspace BTI

From: Dave Martin <[email protected]>

Now that the code for userspace BTI support is in the kernel add the
Kconfig entry so that it can be built and used.

[Split out of "arm64: Basic Branch Target Identification support"
-- broonie]

Signed-off-by: Dave Martin <[email protected]>
Reviewed-by: Kees Cook <[email protected]>
Signed-off-by: Mark Brown <[email protected]>
---
arch/arm64/Kconfig | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 8a15bc68dadd..d65d226a77ec 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -1522,6 +1522,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
--
2.20.1

2020-03-16 16:52:28

by Mark Brown

[permalink] [raw]
Subject: [PATCH v10 09/13] arm64: BTI: Reset BTYPE when skipping emulated instructions

From: Dave Martin <[email protected]>

Since normal execution of any non-branch instruction resets the
PSTATE BTYPE field to 0, so do the same thing when emulating a
trapped instruction.

Branches don't trap directly, so we should never need to assign a
non-zero value to BTYPE here.

Signed-off-by: Dave Martin <[email protected]>
Signed-off-by: Mark Brown <[email protected]>
---
arch/arm64/kernel/traps.c | 2 ++
1 file changed, 2 insertions(+)

diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c
index 3c986c8ca204..10d6451b2776 100644
--- a/arch/arm64/kernel/traps.c
+++ b/arch/arm64/kernel/traps.c
@@ -340,6 +340,8 @@ void arm64_skip_faulting_instruction(struct pt_regs *regs, unsigned long size)

if (compat_user_mode(regs))
advance_itstate(regs);
+ else
+ regs->pstate &= ~PSR_BTYPE_MASK;
}

static LIST_HEAD(undef_hook);
--
2.20.1

2020-03-16 16:52:29

by Mark Brown

[permalink] [raw]
Subject: [PATCH v10 10/13] KVM: arm64: BTI: Reset BTYPE when skipping emulated instructions

From: Dave Martin <[email protected]>

Since normal execution of any non-branch instruction resets the
PSTATE BTYPE field to 0, so do the same thing when emulating a
trapped instruction.

Branches don't trap directly, so we should never need to assign a
non-zero value to BTYPE here.

Signed-off-by: Dave Martin <[email protected]>
Acked-by: Marc Zyngier <[email protected]>
Signed-off-by: Mark Brown <[email protected]>
---
arch/arm64/include/asm/kvm_emulate.h | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
index 688c63412cc2..dee51c1dcb93 100644
--- a/arch/arm64/include/asm/kvm_emulate.h
+++ b/arch/arm64/include/asm/kvm_emulate.h
@@ -506,10 +506,12 @@ static inline unsigned long vcpu_data_host_to_guest(struct kvm_vcpu *vcpu,

static 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;
--
2.20.1

2020-03-16 16:52:40

by Mark Brown

[permalink] [raw]
Subject: [PATCH v10 07/13] arm64: unify native/compat instruction skipping

From: Dave Martin <[email protected]>

Skipping of an instruction on AArch32 works a bit differently from
AArch64, mainly due to the different CPSR/PSTATE semantics.

Currently arm64_skip_faulting_instruction() is only suitable for
AArch64, and arm64_compat_skip_faulting_instruction() handles the IT
state machine but is local to traps.c.

Since manual instruction skipping implies a trap, it's a relatively
slow path.

So, make arm64_skip_faulting_instruction() handle both compat and
native, and get rid of the arm64_compat_skip_faulting_instruction()
special case.

Signed-off-by: Dave Martin <[email protected]>
Reviewed-by: Mark Rutland <[email protected]>
Reviewed-by: Kees Cook <[email protected]>
Signed-off-by: Mark Brown <[email protected]>
---
arch/arm64/kernel/traps.c | 18 ++++++++----------
1 file changed, 8 insertions(+), 10 deletions(-)

diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c
index b8c714dda851..bc9f4292bfc3 100644
--- a/arch/arm64/kernel/traps.c
+++ b/arch/arm64/kernel/traps.c
@@ -272,6 +272,8 @@ void arm64_notify_die(const char *str, struct pt_regs *regs,
}
}

+static void advance_itstate(struct pt_regs *regs);
+
void arm64_skip_faulting_instruction(struct pt_regs *regs, unsigned long size)
{
regs->pc += size;
@@ -282,6 +284,9 @@ void arm64_skip_faulting_instruction(struct pt_regs *regs, unsigned long size)
*/
if (user_mode(regs))
user_fastforward_single_step(current);
+
+ if (regs->pstate & PSR_MODE32_BIT)
+ advance_itstate(regs);
}

static LIST_HEAD(undef_hook);
@@ -644,19 +649,12 @@ static void advance_itstate(struct pt_regs *regs)
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[] = {
@@ -676,7 +674,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[] = {
@@ -697,7 +695,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;
}

--
2.20.1

2020-03-16 16:52:48

by Mark Brown

[permalink] [raw]
Subject: [PATCH v10 05/13] arm64: elf: Enable BTI at exec based on ELF program properties

From: Dave Martin <[email protected]>

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: Dave Martin <[email protected]>
Reviewed-by: Kees Cook <[email protected]>
Signed-off-by: Mark Brown <[email protected]>
---
arch/arm64/Kconfig | 3 +++
arch/arm64/include/asm/elf.h | 50 ++++++++++++++++++++++++++++++++++++
arch/arm64/kernel/process.c | 19 ++++++++++++++
include/uapi/linux/elf.h | 6 +++++
4 files changed, 78 insertions(+)

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 0b30e884e088..8a15bc68dadd 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -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
diff --git a/arch/arm64/include/asm/elf.h b/arch/arm64/include/asm/elf.h
index b618017205a3..4f00d50585a4 100644
--- a/arch/arm64/include/asm/elf.h
+++ b/arch/arm64/include/asm/elf.h
@@ -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
diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c
index 00626057a384..b8e3faa8d406 100644
--- a/arch/arm64/kernel/process.c
+++ b/arch/arm64/kernel/process.c
@@ -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
diff --git a/include/uapi/linux/elf.h b/include/uapi/linux/elf.h
index 20900f4496b7..c6dd0215482e 100644
--- a/include/uapi/linux/elf.h
+++ b/include/uapi/linux/elf.h
@@ -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 */
--
2.20.1

2020-03-16 16:52:50

by Mark Brown

[permalink] [raw]
Subject: [PATCH v10 02/13] ELF: Add ELF program property parsing support

From: Dave Martin <[email protected]>

ELF program properties will be needed for detecting whether to
enable optional architecture or ABI features for a new ELF process.

For now, there are no generic properties that we care about, so do
nothing unless CONFIG_ARCH_USE_GNU_PROPERTY=y.

Otherwise, the presence of properties using the PT_PROGRAM_PROPERTY
phdrs entry (if any), and notify each property to the arch code.

For now, the added code is not used.

Signed-off-by: Dave Martin <[email protected]>
Reviewed-by: Kees Cook <[email protected]>
Signed-off-by: Mark Brown <[email protected]>
---
fs/binfmt_elf.c | 127 +++++++++++++++++++++++++++++++++++++++
fs/compat_binfmt_elf.c | 4 ++
include/linux/elf.h | 19 ++++++
include/uapi/linux/elf.h | 4 ++
4 files changed, 154 insertions(+)

diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index f4713ea76e82..1fb67e506b68 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -39,12 +39,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
@@ -681,6 +687,111 @@ static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex,
* 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 */
@@ -688,6 +799,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;
@@ -733,6 +845,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;

@@ -820,9 +937,14 @@ static int load_elf_binary(struct linux_binprm *bprm)
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 < loc->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(&loc->interp_elf_ex,
elf_ppnt, interpreter,
@@ -833,6 +955,11 @@ static int load_elf_binary(struct linux_binprm *bprm)
}
}

+ 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
diff --git a/fs/compat_binfmt_elf.c b/fs/compat_binfmt_elf.c
index aaad4ca1217e..13a087bc816b 100644
--- a/fs/compat_binfmt_elf.c
+++ b/fs/compat_binfmt_elf.c
@@ -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.
diff --git a/include/linux/elf.h b/include/linux/elf.h
index f7b24c5fcfb6..db5113479f5e 100644
--- a/include/linux/elf.h
+++ b/include/linux/elf.h
@@ -22,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 [];
@@ -32,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

@@ -43,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

@@ -68,4 +73,18 @@ struct gnu_property {
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
+
#endif /* _LINUX_ELF_H */
diff --git a/include/uapi/linux/elf.h b/include/uapi/linux/elf.h
index c37731407074..20900f4496b7 100644
--- a/include/uapi/linux/elf.h
+++ b/include/uapi/linux/elf.h
@@ -368,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
@@ -430,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 */
--
2.20.1

2020-03-16 16:53:03

by Mark Brown

[permalink] [raw]
Subject: [PATCH v10 06/13] arm64: BTI: Decode BYTPE bits when printing PSTATE

From: Dave Martin <[email protected]>

The current code to print PSTATE symbolically when generating
backtraces etc., does not include the BYTPE field used by Branch
Target Identification.

So, decode BYTPE and print it too.

In the interests of human-readability, print the classes of BTI
matched. The symbolic notation, BYTPE (PSTATE[11:10]) and
permitted classes of subsequent instruction are:

-- (BTYPE=0b00): any insn
jc (BTYPE=0b01): BTI jc, BTI j, BTI c, PACIxSP
-c (BYTPE=0b10): BTI jc, BTI c, PACIxSP
j- (BTYPE=0b11): BTI jc, BTI j

Signed-off-by: Dave Martin <[email protected]>
Reviewed-by: Kees Cook <[email protected]>
Signed-off-by: Mark Brown <[email protected]>
---
arch/arm64/kernel/process.c | 17 +++++++++++++++--
1 file changed, 15 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c
index b8e3faa8d406..24af13d7bde6 100644
--- a/arch/arm64/kernel/process.c
+++ b/arch/arm64/kernel/process.c
@@ -211,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;
@@ -229,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',
@@ -240,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);
}
}

--
2.20.1

2020-03-16 16:53:14

by Mark Brown

[permalink] [raw]
Subject: [PATCH v10 08/13] arm64: traps: Shuffle code to eliminate forward declarations

From: Dave Martin <[email protected]>

Hoist the IT state handling code earlier in traps.c, to avoid
accumulating forward declarations.

No functional change.

Signed-off-by: Dave Martin <[email protected]>
Reviewed-by: Kees Cook <[email protected]>
Signed-off-by: Mark Brown <[email protected]>
---
arch/arm64/kernel/traps.c | 107 ++++++++++++++++++++------------------
1 file changed, 55 insertions(+), 52 deletions(-)

diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c
index bc9f4292bfc3..3c986c8ca204 100644
--- a/arch/arm64/kernel/traps.c
+++ b/arch/arm64/kernel/traps.c
@@ -272,7 +272,60 @@ void arm64_notify_die(const char *str, struct pt_regs *regs,
}
}

-static void advance_itstate(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)
{
@@ -285,7 +338,7 @@ void arm64_skip_faulting_instruction(struct pt_regs *regs, unsigned long size)
if (user_mode(regs))
user_fastforward_single_step(current);

- if (regs->pstate & PSR_MODE32_BIT)
+ if (compat_user_mode(regs))
advance_itstate(regs);
}

@@ -578,34 +631,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;
@@ -626,29 +652,6 @@ 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 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;
--
2.20.1

2020-03-17 18:50:11

by Catalin Marinas

[permalink] [raw]
Subject: Re: [PATCH v10 00/13] arm64: Branch Target Identification support

On Mon, Mar 16, 2020 at 04:50:42PM +0000, Mark Brown wrote:
> Daniel Kiss (1):
> mm: smaps: Report arm64 guarded pages in smaps
>
> Dave Martin (11):
> ELF: UAPI and Kconfig additions for ELF program properties
> ELF: Add ELF program property parsing support
> arm64: Basic Branch Target Identification support
> elf: Allow arch to tweak initial mmap prot flags
> arm64: elf: Enable BTI at exec based on ELF program properties
> arm64: BTI: Decode BYTPE bits when printing PSTATE
> arm64: unify native/compat instruction skipping
> arm64: traps: Shuffle code to eliminate forward declarations
> arm64: BTI: Reset BTYPE when skipping emulated instructions
> KVM: arm64: BTI: Reset BTYPE when skipping emulated instructions
> arm64: BTI: Add Kconfig entry for userspace BTI
>
> Mark Brown (1):
> arm64: mm: Display guarded pages in ptdump

I provisionally pushed this patches to linux-next (and arm64
for-next/bti).

I'm not sure whether they'll make it into 5.7 yet (still missing acks on
the fs/* changes) but at least they'll get some wider exposure,
especially as they go outside arch/arm64/.

--
Catalin

2020-03-20 17:41:08

by Szabolcs Nagy

[permalink] [raw]
Subject: Re: [PATCH v10 00/13] arm64: Branch Target Identification support

The 03/16/2020 16:50, Mark Brown wrote:
> This patch series implements support for ARMv8.5-A Branch Target
> Identification (BTI), which is a control flow integrity protection
> feature introduced as part of the ARMv8.5-A extensions.

i was playing with this and it seems the kernel does not add
PROT_BTI to non-static executables (i.e. there is an interpreter).

i thought any elf that the kernel maps would get PROT_BTI from the
kernel. (i want to remove the mprotect in glibc when not necessary)

i tested by linking a hello world exe with -Wl,-z,force-bti (and
verified that the property note is there) and expected it to crash
(with SIGILL) when the dynamic linker jumps to _start in the exe,
but it executed without errors (if i do the mprotect in glibc then
i get SIGILL as expected).

is this deliberate? does the kernel map static exe and dynamic
linked exe differently?

i cant tell looking at the patches where this logic comes from.

>
> Changes:
>
> v10:
> - Fix build for !COMPAT configurations.
> v9:
> - Move Kconfig addition to final patch in series.
> - Add patch from Daniel Kiss adding BTI information to smaps, this has
> a trivial conflict with a .rst conversion in -next.
> v8:
> - Remove a redundant IS_ENABLED(CONFIG_ARM64_BTI) check.
> v7:
> - Rebase onto v5.6-rc3.
> - Move comment about keeping NT_GNU_PROPERTY_TYPE_0 internal into first
> patch.
> - Add an explicit check for system_supports_bti() when parsing BTI ELF
> property for improved robustness.
> v6:
> - Rebase onto v5.6-rc1.
> - Fix typos s/BYTPE/BTYPE/ in commit log for "arm64: BTI: Decode BYTPE
> bits when printing PSTATE".
> v5:
> - Changed a bunch of -EIO to -ENOEXEC in the ELF parsing code.
> - Move PSR_BTYPE defines to UAPI.
> - Use compat_user_mode() rather than open coding.
> - Fix a typo s/BYTPE/BTYPE/ in syscall.c
> v4:
> - Dropped patch fixing existing documentation as it has already been merged.
> - Convert WARN_ON() to WARN_ON_ONCE() in "ELF: Add ELF program property
> parsing support".
> - Added display of guarded pages to ptdump.
> - Updated for conversion of exception handling from assembler to C.
>
> Notes:
>
> * GCC 9 can compile backwards-compatible BTI-enabled code with
> -mbranch-protection=bti or -mbranch-protection=standard.
>
> * Binutils 2.33 and later support the new ELF note.
>
> Creation of a BTI-enabled binary requires _everything_ linked in to
> be BTI-enabled. For now ld --force-bti can be used to override this,
> but some things may break until the required C library support is in
> place.
>
> There is no straightforward way to mark a .s file as BTI-enabled:
> scraping the output from gcc -S works as a quick hack for now.
>
> readelf -n can be used to examing the program properties in an ELF
> file.
>
> * Runtime mmap() and mprotect() can be used to enable BTI on a
> page-by-page basis using the new PROT_BTI, but the code in the
> affected pages still needs to be written or compiled to contain the
> appropriate BTI landing pads.
>
> Daniel Kiss (1):
> mm: smaps: Report arm64 guarded pages in smaps
>
> Dave Martin (11):
> ELF: UAPI and Kconfig additions for ELF program properties
> ELF: Add ELF program property parsing support
> arm64: Basic Branch Target Identification support
> elf: Allow arch to tweak initial mmap prot flags
> arm64: elf: Enable BTI at exec based on ELF program properties
> arm64: BTI: Decode BYTPE bits when printing PSTATE
> arm64: unify native/compat instruction skipping
> arm64: traps: Shuffle code to eliminate forward declarations
> arm64: BTI: Reset BTYPE when skipping emulated instructions
> KVM: arm64: BTI: Reset BTYPE when skipping emulated instructions
> arm64: BTI: Add Kconfig entry for userspace BTI
>
> Mark Brown (1):
> arm64: mm: Display guarded pages in ptdump
>
> Documentation/arm64/cpu-feature-registers.rst | 2 +
> Documentation/arm64/elf_hwcaps.rst | 5 +
> Documentation/filesystems/proc.txt | 1 +
> arch/arm64/Kconfig | 25 +++
> arch/arm64/include/asm/cpucaps.h | 3 +-
> arch/arm64/include/asm/cpufeature.h | 6 +
> arch/arm64/include/asm/elf.h | 50 ++++++
> arch/arm64/include/asm/esr.h | 2 +-
> arch/arm64/include/asm/exception.h | 1 +
> arch/arm64/include/asm/hwcap.h | 1 +
> arch/arm64/include/asm/kvm_emulate.h | 6 +-
> arch/arm64/include/asm/mman.h | 37 +++++
> arch/arm64/include/asm/pgtable-hwdef.h | 1 +
> arch/arm64/include/asm/pgtable.h | 2 +-
> arch/arm64/include/asm/ptrace.h | 1 +
> arch/arm64/include/asm/sysreg.h | 4 +
> arch/arm64/include/uapi/asm/hwcap.h | 1 +
> arch/arm64/include/uapi/asm/mman.h | 9 ++
> arch/arm64/include/uapi/asm/ptrace.h | 9 ++
> arch/arm64/kernel/cpufeature.c | 33 ++++
> arch/arm64/kernel/cpuinfo.c | 1 +
> arch/arm64/kernel/entry-common.c | 11 ++
> arch/arm64/kernel/process.c | 36 ++++-
> arch/arm64/kernel/ptrace.c | 2 +-
> arch/arm64/kernel/signal.c | 16 ++
> arch/arm64/kernel/syscall.c | 18 +++
> arch/arm64/kernel/traps.c | 131 ++++++++--------
> arch/arm64/mm/dump.c | 5 +
> fs/Kconfig.binfmt | 6 +
> fs/binfmt_elf.c | 145 +++++++++++++++++-
> fs/compat_binfmt_elf.c | 4 +
> fs/proc/task_mmu.c | 3 +
> include/linux/elf.h | 43 ++++++
> include/linux/mm.h | 3 +
> include/uapi/linux/elf.h | 11 ++
> 35 files changed, 560 insertions(+), 74 deletions(-)
> create mode 100644 arch/arm64/include/asm/mman.h
> create mode 100644 arch/arm64/include/uapi/asm/mman.h
>
>
> base-commit: f8788d86ab28f61f7b46eb6be375f8a726783636
> --
> 2.20.1
>

--

2020-03-23 12:22:45

by Catalin Marinas

[permalink] [raw]
Subject: Re: [PATCH v10 00/13] arm64: Branch Target Identification support

On Fri, Mar 20, 2020 at 05:39:46PM +0000, Szabolcs Nagy wrote:
> The 03/16/2020 16:50, Mark Brown wrote:
> > This patch series implements support for ARMv8.5-A Branch Target
> > Identification (BTI), which is a control flow integrity protection
> > feature introduced as part of the ARMv8.5-A extensions.
>
> i was playing with this and it seems the kernel does not add
> PROT_BTI to non-static executables (i.e. there is an interpreter).
>
> i thought any elf that the kernel maps would get PROT_BTI from the
> kernel. (i want to remove the mprotect in glibc when not necessary)

I haven't followed the early discussions but I think this makes sense.

> i tested by linking a hello world exe with -Wl,-z,force-bti (and
> verified that the property note is there) and expected it to crash
> (with SIGILL) when the dynamic linker jumps to _start in the exe,
> but it executed without errors (if i do the mprotect in glibc then
> i get SIGILL as expected).
>
> is this deliberate? does the kernel map static exe and dynamic
> linked exe differently?

I think the logic is in patch 5:

+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;
+}

At a quick look, for dynamic binaries we have has_interp == true and
is_interp == false. I don't know why but, either way, the above code
needs a comment with some justification.

--
Catalin

2020-03-23 13:25:59

by Mark Brown

[permalink] [raw]
Subject: Re: [PATCH v10 00/13] arm64: Branch Target Identification support

On Mon, Mar 23, 2020 at 12:21:44PM +0000, Catalin Marinas wrote:
> On Fri, Mar 20, 2020 at 05:39:46PM +0000, Szabolcs Nagy wrote:

> +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;
> +}

> At a quick look, for dynamic binaries we have has_interp == true and
> is_interp == false. I don't know why but, either way, the above code
> needs a comment with some justification.

I don't really know for certain either, I inherited this code as is with
the understanding that this was all agreed with the toolchain and libc
people - the actual discussion that lead to the decisions being made
happened before I was involved. My understanding is that the idea was
that the dynamic linker would be responsible for mapping everything in
dynamic applications other than itself but other than consistency I
don't know why. I guess it defers more decision making to userspace but
I'm having a hard time thinking of sensible cases where one might wish
to make a decision other than enabling PROT_BTI.

I'd be perfectly happy to drop the check if that makes more sense to
people, otherwise I can send a patch adding a comment explaining the
situation.


Attachments:
(No filename) (1.48 kB)
signature.asc (499.00 B)
Download all attachments

2020-03-23 13:58:39

by Mark Rutland

[permalink] [raw]
Subject: Re: [PATCH v10 00/13] arm64: Branch Target Identification support

On Mon, Mar 23, 2020 at 01:24:12PM +0000, Mark Brown wrote:
> On Mon, Mar 23, 2020 at 12:21:44PM +0000, Catalin Marinas wrote:
> > On Fri, Mar 20, 2020 at 05:39:46PM +0000, Szabolcs Nagy wrote:
>
> > +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;
> > +}
>
> > At a quick look, for dynamic binaries we have has_interp == true and
> > is_interp == false. I don't know why but, either way, the above code
> > needs a comment with some justification.
>
> I don't really know for certain either, I inherited this code as is with
> the understanding that this was all agreed with the toolchain and libc
> people - the actual discussion that lead to the decisions being made
> happened before I was involved. My understanding is that the idea was
> that the dynamic linker would be responsible for mapping everything in
> dynamic applications other than itself but other than consistency I
> don't know why. I guess it defers more decision making to userspace but
> I'm having a hard time thinking of sensible cases where one might wish
> to make a decision other than enabling PROT_BTI.

My understanding was this had been agreed with the toolchain folk a
while back -- anything static loaded by the kernel (i.e. a static
executable or the dynamic linker) would get GP set. In other cases the
linker will mess with the permissions on the pages anyhow, and needs to
be aware of BTI in order to do the right thing, so it was better to
leave it to userspace consistently (e.g. as that had the least risk of
subtle changes in behaviour leading to ABI difficulties).

> I'd be perfectly happy to drop the check if that makes more sense to
> people, otherwise I can send a patch adding a comment explaining the
> situation.

I think it would be best to document the current behaviour, as it's a
simple ABI that we can guarantee, and the dynamic linker will have to be
aware of BTI in order to do the right thing anyhow.

Thanks,
Mark.

2020-03-23 14:41:54

by Catalin Marinas

[permalink] [raw]
Subject: Re: [PATCH v10 00/13] arm64: Branch Target Identification support

On Mon, Mar 23, 2020 at 01:57:22PM +0000, Mark Rutland wrote:
> On Mon, Mar 23, 2020 at 01:24:12PM +0000, Mark Brown wrote:
> > On Mon, Mar 23, 2020 at 12:21:44PM +0000, Catalin Marinas wrote:
> > > On Fri, Mar 20, 2020 at 05:39:46PM +0000, Szabolcs Nagy wrote:
> >
> > > +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;
> > > +}
> >
> > > At a quick look, for dynamic binaries we have has_interp == true and
> > > is_interp == false. I don't know why but, either way, the above code
> > > needs a comment with some justification.
> >
> > I don't really know for certain either, I inherited this code as is with
> > the understanding that this was all agreed with the toolchain and libc
> > people - the actual discussion that lead to the decisions being made
> > happened before I was involved. My understanding is that the idea was
> > that the dynamic linker would be responsible for mapping everything in
> > dynamic applications other than itself but other than consistency I
> > don't know why. I guess it defers more decision making to userspace but
> > I'm having a hard time thinking of sensible cases where one might wish
> > to make a decision other than enabling PROT_BTI.
>
> My understanding was this had been agreed with the toolchain folk a
> while back -- anything static loaded by the kernel (i.e. a static
> executable or the dynamic linker) would get GP set. In other cases the
> linker will mess with the permissions on the pages anyhow, and needs to
> be aware of BTI in order to do the right thing, so it was better to
> leave it to userspace consistently (e.g. as that had the least risk of
> subtle changes in behaviour leading to ABI difficulties).

So this means that the interpreter will have to mprotect(PROT_BTI) the
text section of the primary executable. For subsequent libraries, it
calls mmap() explicitly anyway but not for the main executable (IIUC).

> > I'd be perfectly happy to drop the check if that makes more sense to
> > people, otherwise I can send a patch adding a comment explaining the
> > situation.
>
> I think it would be best to document the current behaviour, as it's a
> simple ABI that we can guarantee, and the dynamic linker will have to be
> aware of BTI in order to do the right thing anyhow.

That's a valid point. If we have an old dynamic linker and the kernel
enabled BTI automatically for the main executable, could things go wrong
(e.g. does the PLT need to be BTI-aware)?

--
Catalin

2020-03-23 14:56:45

by Mark Rutland

[permalink] [raw]
Subject: Re: [PATCH v10 00/13] arm64: Branch Target Identification support

On Mon, Mar 23, 2020 at 02:39:55PM +0000, Catalin Marinas wrote:
> On Mon, Mar 23, 2020 at 01:57:22PM +0000, Mark Rutland wrote:
> > On Mon, Mar 23, 2020 at 01:24:12PM +0000, Mark Brown wrote:
> > > On Mon, Mar 23, 2020 at 12:21:44PM +0000, Catalin Marinas wrote:
> > > > On Fri, Mar 20, 2020 at 05:39:46PM +0000, Szabolcs Nagy wrote:
> > >
> > > > +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;
> > > > +}
> > >
> > > > At a quick look, for dynamic binaries we have has_interp == true and
> > > > is_interp == false. I don't know why but, either way, the above code
> > > > needs a comment with some justification.
> > >
> > > I don't really know for certain either, I inherited this code as is with
> > > the understanding that this was all agreed with the toolchain and libc
> > > people - the actual discussion that lead to the decisions being made
> > > happened before I was involved. My understanding is that the idea was
> > > that the dynamic linker would be responsible for mapping everything in
> > > dynamic applications other than itself but other than consistency I
> > > don't know why. I guess it defers more decision making to userspace but
> > > I'm having a hard time thinking of sensible cases where one might wish
> > > to make a decision other than enabling PROT_BTI.
> >
> > My understanding was this had been agreed with the toolchain folk a
> > while back -- anything static loaded by the kernel (i.e. a static
> > executable or the dynamic linker) would get GP set. In other cases the
> > linker will mess with the permissions on the pages anyhow, and needs to
> > be aware of BTI in order to do the right thing, so it was better to
> > leave it to userspace consistently (e.g. as that had the least risk of
> > subtle changes in behaviour leading to ABI difficulties).
>
> So this means that the interpreter will have to mprotect(PROT_BTI) the
> text section of the primary executable.

Yes, but after fixing up any relocations in that section it's going to
have to call mprotect() on it anyhow (e.g. in order to make it
read-only), and in doing so would throw away BTI unless it was BTI
aware.

> > I think it would be best to document the current behaviour, as it's a
> > simple ABI that we can guarantee, and the dynamic linker will have to be
> > aware of BTI in order to do the right thing anyhow.
>
> That's a valid point. If we have an old dynamic linker and the kernel
> enabled BTI automatically for the main executable, could things go wrong
> (e.g. does the PLT need to be BTI-aware)?

I believe that a PLT in an unguarded page needs no special treatment. A
PLT within a guarded page needs to be built specially for BTI.

Thanks,
Mark.

2020-03-23 15:03:10

by Mark Rutland

[permalink] [raw]
Subject: Re: [PATCH v10 00/13] arm64: Branch Target Identification support

On Mon, Mar 23, 2020 at 02:39:55PM +0000, Catalin Marinas wrote:
> On Mon, Mar 23, 2020 at 01:57:22PM +0000, Mark Rutland wrote:
> > On Mon, Mar 23, 2020 at 01:24:12PM +0000, Mark Brown wrote:
> > > On Mon, Mar 23, 2020 at 12:21:44PM +0000, Catalin Marinas wrote:
> > > > On Fri, Mar 20, 2020 at 05:39:46PM +0000, Szabolcs Nagy wrote:
> > >
> > > > +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;
> > > > +}

> > I think it would be best to document the current behaviour, as it's a
> > simple ABI that we can guarantee, and the dynamic linker will have to be
> > aware of BTI in order to do the right thing anyhow.
>
> That's a valid point. If we have an old dynamic linker and the kernel
> enabled BTI automatically for the main executable, could things go wrong
> (e.g. does the PLT need to be BTI-aware)?

Also worth noting that an old dynamic linker won't have ARM64_ELF_BTI
set, so the kernel will not enable BTI for this.

Mark.

2020-03-23 15:34:24

by Mark Brown

[permalink] [raw]
Subject: Re: [PATCH v10 00/13] arm64: Branch Target Identification support

On Mon, Mar 23, 2020 at 02:55:46PM +0000, Mark Rutland wrote:
> On Mon, Mar 23, 2020 at 02:39:55PM +0000, Catalin Marinas wrote:

> > So this means that the interpreter will have to mprotect(PROT_BTI) the
> > text section of the primary executable.

> Yes, but after fixing up any relocations in that section it's going to
> have to call mprotect() on it anyhow (e.g. in order to make it
> read-only), and in doing so would throw away BTI unless it was BTI
> aware.

Ah, of course - I forgot that's not a read/modify/write cycle. I'll
send the comment version.

> > That's a valid point. If we have an old dynamic linker and the kernel
> > enabled BTI automatically for the main executable, could things go wrong
> > (e.g. does the PLT need to be BTI-aware)?

> I believe that a PLT in an unguarded page needs no special treatment. A
> PLT within a guarded page needs to be built specially for BTI.

Unguarded stuff is unaffected.


Attachments:
(No filename) (954.00 B)
signature.asc (499.00 B)
Download all attachments

2020-03-24 15:45:20

by Szabolcs Nagy

[permalink] [raw]
Subject: Re: [PATCH v10 00/13] arm64: Branch Target Identification support

The 03/23/2020 14:55, Mark Rutland wrote:
> On Mon, Mar 23, 2020 at 02:39:55PM +0000, Catalin Marinas wrote:
> > On Mon, Mar 23, 2020 at 01:57:22PM +0000, Mark Rutland wrote:
> > > On Mon, Mar 23, 2020 at 01:24:12PM +0000, Mark Brown wrote:
> > > > On Mon, Mar 23, 2020 at 12:21:44PM +0000, Catalin Marinas wrote:
> > > > > On Fri, Mar 20, 2020 at 05:39:46PM +0000, Szabolcs Nagy wrote:
> > > >
> > > > > +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;
> > > > > +}
> > > >
> > > > > At a quick look, for dynamic binaries we have has_interp == true and
> > > > > is_interp == false. I don't know why but, either way, the above code
> > > > > needs a comment with some justification.
> > > >
> > > > I don't really know for certain either, I inherited this code as is with
> > > > the understanding that this was all agreed with the toolchain and libc
> > > > people - the actual discussion that lead to the decisions being made
> > > > happened before I was involved. My understanding is that the idea was
> > > > that the dynamic linker would be responsible for mapping everything in
> > > > dynamic applications other than itself but other than consistency I
> > > > don't know why. I guess it defers more decision making to userspace but
> > > > I'm having a hard time thinking of sensible cases where one might wish
> > > > to make a decision other than enabling PROT_BTI.
> > >
> > > My understanding was this had been agreed with the toolchain folk a
> > > while back -- anything static loaded by the kernel (i.e. a static
> > > executable or the dynamic linker) would get GP set. In other cases the
> > > linker will mess with the permissions on the pages anyhow, and needs to
> > > be aware of BTI in order to do the right thing, so it was better to
> > > leave it to userspace consistently (e.g. as that had the least risk of
> > > subtle changes in behaviour leading to ABI difficulties).
> >
> > So this means that the interpreter will have to mprotect(PROT_BTI) the
> > text section of the primary executable.
>
> Yes, but after fixing up any relocations in that section it's going to
> have to call mprotect() on it anyhow (e.g. in order to make it
> read-only), and in doing so would throw away BTI unless it was BTI
> aware.

note: on the main exe only one mprotect is used in case
there is PT_GNU_RELRO (or DF_BIND_NOW) to mark part of
the rw data segment read only. so if PROT_BTI on main
exe is ld.so responsibility that adds one more syscall
to the program startup (not a huge cost).

(currently executable segment can be mprotected by libc
in case of text relocations but those are not fully
supported and won't work under various kernel hardening
schemes that disallow exec+write mappings)

2020-04-22 15:48:38

by Mark Brown

[permalink] [raw]
Subject: Re: [PATCH v10 00/13] arm64: Branch Target Identification support

On Mon, Mar 16, 2020 at 04:50:42PM +0000, Mark Brown wrote:
> This patch series implements support for ARMv8.5-A Branch Target
> Identification (BTI), which is a control flow integrity protection
> feature introduced as part of the ARMv8.5-A extensions.

I've not resent this since the branch is still sitting in the arm64 tree
but it's also not in -next at the minute - is there anything you're
waiting for from my end here?


Attachments:
(No filename) (434.00 B)
signature.asc (499.00 B)
Download all attachments

2020-04-22 16:31:32

by Catalin Marinas

[permalink] [raw]
Subject: Re: [PATCH v10 00/13] arm64: Branch Target Identification support

On Wed, Apr 22, 2020 at 04:44:36PM +0100, Mark Brown wrote:
> On Mon, Mar 16, 2020 at 04:50:42PM +0000, Mark Brown wrote:
> > This patch series implements support for ARMv8.5-A Branch Target
> > Identification (BTI), which is a control flow integrity protection
> > feature introduced as part of the ARMv8.5-A extensions.
>
> I've not resent this since the branch is still sitting in the arm64 tree
> but it's also not in -next at the minute - is there anything you're
> waiting for from my end here?

It's up to Will whether he wants a new series posted. The for-next/bti
branch is complete AFAICT, only that normally we start queueing stuff
(and push to -next) around -rc3.

--
Catalin

2020-04-28 13:30:09

by Will Deacon

[permalink] [raw]
Subject: Re: [PATCH v10 00/13] arm64: Branch Target Identification support

On Wed, Apr 22, 2020 at 05:29:54PM +0100, Catalin Marinas wrote:
> On Wed, Apr 22, 2020 at 04:44:36PM +0100, Mark Brown wrote:
> > On Mon, Mar 16, 2020 at 04:50:42PM +0000, Mark Brown wrote:
> > > This patch series implements support for ARMv8.5-A Branch Target
> > > Identification (BTI), which is a control flow integrity protection
> > > feature introduced as part of the ARMv8.5-A extensions.
> >
> > I've not resent this since the branch is still sitting in the arm64 tree
> > but it's also not in -next at the minute - is there anything you're
> > waiting for from my end here?
>
> It's up to Will whether he wants a new series posted. The for-next/bti
> branch is complete AFAICT, only that normally we start queueing stuff
> (and push to -next) around -rc3.

I'm happy either way, but it would be nice to base other BTI patches on
top of this branch. Mark -- is it easier for you to refresh the series
against v5.7-rc3, or leave it like it is? Please just let me know either
way.

Thanks,

Will

2020-04-28 15:14:23

by Mark Brown

[permalink] [raw]
Subject: Re: [PATCH v10 00/13] arm64: Branch Target Identification support

On Tue, Apr 28, 2020 at 02:28:05PM +0100, Will Deacon wrote:

> I'm happy either way, but it would be nice to base other BTI patches on
> top of this branch. Mark -- is it easier for you to refresh the series
> against v5.7-rc3, or leave it like it is? Please just let me know either
> way.

It's probably easier for me if you just use the existing branch, I've
already got a branch based on a merge down.


Attachments:
(No filename) (415.00 B)
signature.asc (499.00 B)
Download all attachments

2020-04-28 15:21:51

by Will Deacon

[permalink] [raw]
Subject: Re: [PATCH v10 00/13] arm64: Branch Target Identification support

On Tue, Apr 28, 2020 at 04:12:05PM +0100, Mark Brown wrote:
> On Tue, Apr 28, 2020 at 02:28:05PM +0100, Will Deacon wrote:
>
> > I'm happy either way, but it would be nice to base other BTI patches on
> > top of this branch. Mark -- is it easier for you to refresh the series
> > against v5.7-rc3, or leave it like it is? Please just let me know either
> > way.
>
> It's probably easier for me if you just use the existing branch, I've
> already got a branch based on a merge down.

Okey doke, I'll funnel that in the direction of linux-next then. It does
mean that any subsequent patches for 5.8 that depend on BTI will need to
be based on this branch, so as long as you're ok with that then it's fine
by me (since I won't be able to apply patches if they refer to changes
introduced in the recent merge window).

Will

2020-04-28 16:00:29

by Mark Brown

[permalink] [raw]
Subject: Re: [PATCH v10 00/13] arm64: Branch Target Identification support

On Tue, Apr 28, 2020 at 04:18:16PM +0100, Will Deacon wrote:
> On Tue, Apr 28, 2020 at 04:12:05PM +0100, Mark Brown wrote:

> > It's probably easier for me if you just use the existing branch, I've
> > already got a branch based on a merge down.

> Okey doke, I'll funnel that in the direction of linux-next then. It does
> mean that any subsequent patches for 5.8 that depend on BTI will need to
> be based on this branch, so as long as you're ok with that then it's fine
> by me (since I won't be able to apply patches if they refer to changes
> introduced in the recent merge window).

That's not a problem, that's what I've got already and if I try to send
everything based off -rc3 directly the series would get unmanagably
large. Actually unless you think it's a bad idea I think what I'll do
is go and send out a couple of the preparatory changes (the insn updates
and the last bit of annotation conversions) separately for that branch
while I finalize the revisions of the main BTI kernel bit, hopefully
that'll make the review a bit more approachable.


Attachments:
(No filename) (1.06 kB)
signature.asc (499.00 B)
Download all attachments

2020-04-28 16:06:56

by Will Deacon

[permalink] [raw]
Subject: Re: [PATCH v10 00/13] arm64: Branch Target Identification support

On Tue, Apr 28, 2020 at 04:58:12PM +0100, Mark Brown wrote:
> On Tue, Apr 28, 2020 at 04:18:16PM +0100, Will Deacon wrote:
> > On Tue, Apr 28, 2020 at 04:12:05PM +0100, Mark Brown wrote:
>
> > > It's probably easier for me if you just use the existing branch, I've
> > > already got a branch based on a merge down.
>
> > Okey doke, I'll funnel that in the direction of linux-next then. It does
> > mean that any subsequent patches for 5.8 that depend on BTI will need to
> > be based on this branch, so as long as you're ok with that then it's fine
> > by me (since I won't be able to apply patches if they refer to changes
> > introduced in the recent merge window).
>
> That's not a problem, that's what I've got already and if I try to send
> everything based off -rc3 directly the series would get unmanagably
> large. Actually unless you think it's a bad idea I think what I'll do
> is go and send out a couple of the preparatory changes (the insn updates
> and the last bit of annotation conversions) separately for that branch
> while I finalize the revisions of the main BTI kernel bit, hopefully
> that'll make the review a bit more approachable.

Okey doke, sounds good to me. I'm queuing stuff atm, so as long you tell
me what I need to apply things against then we should be good.

Will

2020-04-30 21:28:22

by Will Deacon

[permalink] [raw]
Subject: Re: [PATCH v10 00/13] arm64: Branch Target Identification support

On Tue, Apr 28, 2020 at 05:01:43PM +0100, Will Deacon wrote:
> On Tue, Apr 28, 2020 at 04:58:12PM +0100, Mark Brown wrote:
> > On Tue, Apr 28, 2020 at 04:18:16PM +0100, Will Deacon wrote:
> > > On Tue, Apr 28, 2020 at 04:12:05PM +0100, Mark Brown wrote:
> >
> > > > It's probably easier for me if you just use the existing branch, I've
> > > > already got a branch based on a merge down.
> >
> > > Okey doke, I'll funnel that in the direction of linux-next then. It does
> > > mean that any subsequent patches for 5.8 that depend on BTI will need to
> > > be based on this branch, so as long as you're ok with that then it's fine
> > > by me (since I won't be able to apply patches if they refer to changes
> > > introduced in the recent merge window).
> >
> > That's not a problem, that's what I've got already and if I try to send
> > everything based off -rc3 directly the series would get unmanagably
> > large. Actually unless you think it's a bad idea I think what I'll do
> > is go and send out a couple of the preparatory changes (the insn updates
> > and the last bit of annotation conversions) separately for that branch
> > while I finalize the revisions of the main BTI kernel bit, hopefully
> > that'll make the review a bit more approachable.
>
> Okey doke, sounds good to me. I'm queuing stuff atm, so as long you tell
> me what I need to apply things against then we should be good.

Just a heads up: I've renamed for-next/bti to for-next/bti-user, so it
doesn't get confusing with the pending in-kernel BTI patches. All the commit
SHAs remain unchanged.

Will