This series introduces CET - indirect branch tracking
The major task of indirect branch tracking is for the compiler to
insert the ENDBR instructions at all valid branch targets.
The kernel provides:
CPUID enumeration and feature setup;
Legacy bitmap allocation;
Some basic supporting routines.
In this patch, there are also a CET command-line utility and
PTRACE support.
H.J. Lu (2):
x86: Insert endbr32/endbr64 to vDSO
tools: Add cetcmd
Yu-cheng Yu (5):
x86/cet: Add Kconfig option for user-mode Indirect Branch Tracking
x86/cet: User-mode indirect branch tracking support
mm/mmap: Add IBT bitmap size to address space limit check
x86/cet: add arcp_prctl functions for indirect branch tracking
x86/cet: Add PTRACE interface for CET
arch/x86/Kconfig | 12 +++
arch/x86/entry/vdso/.gitignore | 4 +
arch/x86/entry/vdso/Makefile | 34 +++++++
arch/x86/entry/vdso/endbr.sh | 32 ++++++
arch/x86/include/asm/cet.h | 9 ++
arch/x86/include/asm/disabled-features.h | 8 +-
arch/x86/include/asm/fpu/regset.h | 7 +-
arch/x86/include/uapi/asm/prctl.h | 1 +
arch/x86/include/uapi/asm/resource.h | 5 +
arch/x86/kernel/cet.c | 73 ++++++++++++++
arch/x86/kernel/cet_prctl.c | 54 +++++++++-
arch/x86/kernel/cpu/common.c | 20 +++-
arch/x86/kernel/elf.c | 19 +++-
arch/x86/kernel/fpu/regset.c | 41 ++++++++
arch/x86/kernel/process.c | 2 +
arch/x86/kernel/ptrace.c | 16 +++
include/uapi/asm-generic/resource.h | 3 +
include/uapi/linux/elf.h | 1 +
mm/mmap.c | 8 +-
tools/Makefile | 13 +--
tools/arch/x86/include/uapi/asm/elf_property.h | 16 +++
tools/arch/x86/include/uapi/asm/prctl.h | 33 ++++++
tools/cet/.gitignore | 1 +
tools/cet/Makefile | 11 ++
tools/cet/cetcmd.c | 134 +++++++++++++++++++++++++
tools/include/uapi/asm/elf_property.h | 4 +
tools/include/uapi/asm/prctl.h | 4 +
27 files changed, 549 insertions(+), 16 deletions(-)
create mode 100644 arch/x86/entry/vdso/endbr.sh
create mode 100644 tools/arch/x86/include/uapi/asm/elf_property.h
create mode 100644 tools/arch/x86/include/uapi/asm/prctl.h
create mode 100644 tools/cet/.gitignore
create mode 100644 tools/cet/Makefile
create mode 100644 tools/cet/cetcmd.c
create mode 100644 tools/include/uapi/asm/elf_property.h
create mode 100644 tools/include/uapi/asm/prctl.h
--
2.15.1
Signed-off-by: H.J. Lu <[email protected]>
Signed-off-by: Yu-cheng Yu <[email protected]>
---
arch/x86/include/asm/cet.h | 1 +
arch/x86/include/uapi/asm/prctl.h | 1 +
arch/x86/kernel/cet_prctl.c | 54 ++++++++++++++++++++++++++++++++++++---
arch/x86/kernel/elf.c | 12 ++++++---
arch/x86/kernel/process.c | 1 +
5 files changed, 62 insertions(+), 7 deletions(-)
diff --git a/arch/x86/include/asm/cet.h b/arch/x86/include/asm/cet.h
index d07bdeb27db4..5b71a2b44eb1 100644
--- a/arch/x86/include/asm/cet.h
+++ b/arch/x86/include/asm/cet.h
@@ -19,6 +19,7 @@ struct cet_stat {
unsigned int ibt_enabled:1;
unsigned int locked:1;
unsigned int exec_shstk:2;
+ unsigned int exec_ibt:2;
};
#ifdef CONFIG_X86_INTEL_CET
diff --git a/arch/x86/include/uapi/asm/prctl.h b/arch/x86/include/uapi/asm/prctl.h
index f9965403b655..fef476d2d2f6 100644
--- a/arch/x86/include/uapi/asm/prctl.h
+++ b/arch/x86/include/uapi/asm/prctl.h
@@ -20,6 +20,7 @@
#define ARCH_CET_EXEC 0x3004
#define ARCH_CET_ALLOC_SHSTK 0x3005
#define ARCH_CET_PUSH_SHSTK 0x3006
+#define ARCH_CET_LEGACY_BITMAP 0x3007
/*
* Settings for ARCH_CET_EXEC
diff --git a/arch/x86/kernel/cet_prctl.c b/arch/x86/kernel/cet_prctl.c
index 326996e2ea80..948f7ba98dc2 100644
--- a/arch/x86/kernel/cet_prctl.c
+++ b/arch/x86/kernel/cet_prctl.c
@@ -19,6 +19,7 @@
* ARCH_CET_EXEC: set default features for exec()
* ARCH_CET_ALLOC_SHSTK: allocate shadow stack
* ARCH_CET_PUSH_SHSTK: put a return address on shadow stack
+ * ARCH_CET_LEGACY_BITMAP: allocate legacy bitmap
*/
static int handle_get_status(unsigned long arg2)
@@ -28,8 +29,12 @@ static int handle_get_status(unsigned long arg2)
if (current->thread.cet.shstk_enabled)
features |= GNU_PROPERTY_X86_FEATURE_1_SHSTK;
+ if (current->thread.cet.ibt_enabled)
+ features |= GNU_PROPERTY_X86_FEATURE_1_IBT;
if (current->thread.cet.exec_shstk == CET_EXEC_ALWAYS_ON)
cet_exec |= GNU_PROPERTY_X86_FEATURE_1_SHSTK;
+ if (current->thread.cet.exec_ibt == CET_EXEC_ALWAYS_ON)
+ cet_exec |= GNU_PROPERTY_X86_FEATURE_1_IBT;
shstk_size = current->thread.cet.exec_shstk_size;
if (in_compat_syscall()) {
@@ -94,9 +99,18 @@ static int handle_set_exec(unsigned long arg2)
return -EPERM;
}
+ if (features & GNU_PROPERTY_X86_FEATURE_1_IBT) {
+ if (!cpu_feature_enabled(X86_FEATURE_IBT))
+ return -EINVAL;
+ if ((current->thread.cet.exec_ibt == CET_EXEC_ALWAYS_ON) &&
+ (cet_exec != CET_EXEC_ALWAYS_ON))
+ return -EPERM;
+ }
+
if (features & GNU_PROPERTY_X86_FEATURE_1_SHSTK)
current->thread.cet.exec_shstk = cet_exec;
-
+ if (features & GNU_PROPERTY_X86_FEATURE_1_IBT)
+ current->thread.cet.exec_ibt = cet_exec;
current->thread.cet.exec_shstk_size = shstk_size;
return 0;
}
@@ -167,9 +181,36 @@ static int handle_alloc_shstk(unsigned long arg2)
return 0;
}
+static int handle_bitmap(unsigned long arg2)
+{
+ unsigned long addr, size;
+
+ if (current->thread.cet.ibt_enabled) {
+ if (!current->thread.cet.ibt_bitmap_addr)
+ cet_setup_ibt_bitmap();
+ addr = current->thread.cet.ibt_bitmap_addr;
+ size = current->thread.cet.ibt_bitmap_size;
+ } else {
+ addr = 0;
+ size = 0;
+ }
+
+ if (in_compat_syscall()) {
+ if (put_user(addr, (unsigned int __user *)arg2) ||
+ put_user(size, (unsigned int __user *)arg2 + 1))
+ return -EFAULT;
+ } else {
+ if (put_user(addr, (unsigned long __user *)arg2) ||
+ put_user(size, (unsigned long __user *)arg2 + 1))
+ return -EFAULT;
+ }
+ return 0;
+}
+
int prctl_cet(int option, unsigned long arg2)
{
- if (!cpu_feature_enabled(X86_FEATURE_SHSTK))
+ if (!cpu_feature_enabled(X86_FEATURE_SHSTK) &&
+ !cpu_feature_enabled(X86_FEATURE_IBT))
return -EINVAL;
switch (option) {
@@ -181,7 +222,8 @@ int prctl_cet(int option, unsigned long arg2)
return -EPERM;
if (arg2 & GNU_PROPERTY_X86_FEATURE_1_SHSTK)
cet_disable_free_shstk(current);
-
+ if (arg2 & GNU_PROPERTY_X86_FEATURE_1_IBT)
+ cet_disable_ibt();
return 0;
case ARCH_CET_LOCK:
@@ -197,6 +239,12 @@ int prctl_cet(int option, unsigned long arg2)
case ARCH_CET_PUSH_SHSTK:
return handle_push_shstk(arg2);
+ /*
+ * Allocate legacy bitmap and return address & size to user.
+ */
+ case ARCH_CET_LEGACY_BITMAP:
+ return handle_bitmap(arg2);
+
default:
return -EINVAL;
}
diff --git a/arch/x86/kernel/elf.c b/arch/x86/kernel/elf.c
index a3995c8c2fc2..c2a89f3c7186 100644
--- a/arch/x86/kernel/elf.c
+++ b/arch/x86/kernel/elf.c
@@ -230,10 +230,14 @@ int arch_setup_features(void *ehdr_p, void *phdr_p,
}
if (cpu_feature_enabled(X86_FEATURE_IBT)) {
- if (ibt) {
- err = cet_setup_ibt();
- if (err < 0)
- goto out;
+ int exec = current->thread.cet.exec_ibt;
+
+ if (exec != CET_EXEC_ALWAYS_OFF) {
+ if (ibt || (exec == CET_EXEC_ALWAYS_ON)) {
+ err = cet_setup_ibt();
+ if (err < 0)
+ goto out;
+ }
}
}
diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c
index 9bec164e7958..c69576b4abd1 100644
--- a/arch/x86/kernel/process.c
+++ b/arch/x86/kernel/process.c
@@ -801,6 +801,7 @@ long do_arch_prctl_common(struct task_struct *task, int option,
case ARCH_CET_EXEC:
case ARCH_CET_ALLOC_SHSTK:
case ARCH_CET_PUSH_SHSTK:
+ case ARCH_CET_LEGACY_BITMAP:
return prctl_cet(option, cpuid_enabled);
}
--
2.15.1
The indirect branch tracking legacy bitmap takes a large address
space. This causes may_expand_vm() failure on the address limit
check. For a IBT-enabled task, add the bitmap size to the
address limit.
Signed-off-by: Yu-cheng Yu <[email protected]>
---
arch/x86/include/uapi/asm/resource.h | 5 +++++
include/uapi/asm-generic/resource.h | 3 +++
mm/mmap.c | 8 +++++++-
3 files changed, 15 insertions(+), 1 deletion(-)
diff --git a/arch/x86/include/uapi/asm/resource.h b/arch/x86/include/uapi/asm/resource.h
index 04bc4db8921b..0741b2a6101a 100644
--- a/arch/x86/include/uapi/asm/resource.h
+++ b/arch/x86/include/uapi/asm/resource.h
@@ -1 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
+#ifdef CONFIG_X86_INTEL_CET
+#define rlimit_as_extra() current->thread.cet.ibt_bitmap_size
+#endif
+
#include <asm-generic/resource.h>
diff --git a/include/uapi/asm-generic/resource.h b/include/uapi/asm-generic/resource.h
index f12db7a0da64..8a7608a09700 100644
--- a/include/uapi/asm-generic/resource.h
+++ b/include/uapi/asm-generic/resource.h
@@ -58,5 +58,8 @@
# define RLIM_INFINITY (~0UL)
#endif
+#ifndef rlimit_as_extra
+#define rlimit_as_extra() 0
+#endif
#endif /* _UAPI_ASM_GENERIC_RESOURCE_H */
diff --git a/mm/mmap.c b/mm/mmap.c
index e7d1fcb7ec58..5c07f052bed7 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -3255,7 +3255,13 @@ struct vm_area_struct *copy_vma(struct vm_area_struct **vmap,
*/
bool may_expand_vm(struct mm_struct *mm, vm_flags_t flags, unsigned long npages)
{
- if (mm->total_vm + npages > rlimit(RLIMIT_AS) >> PAGE_SHIFT)
+ unsigned long as_limit = rlimit(RLIMIT_AS);
+ unsigned long as_limit_plus = as_limit + rlimit_as_extra();
+
+ if (as_limit_plus > as_limit)
+ as_limit = as_limit_plus;
+
+ if (mm->total_vm + npages > as_limit >> PAGE_SHIFT)
return false;
if (is_data_mapping(flags) &&
--
2.15.1
Add user-mode indirect branch tracking enabling/disabling
and supporting routines.
Signed-off-by: H.J. Lu <[email protected]>
Signed-off-by: Yu-cheng Yu <[email protected]>
---
arch/x86/include/asm/cet.h | 8 ++++
arch/x86/include/asm/disabled-features.h | 8 +++-
arch/x86/kernel/cet.c | 73 ++++++++++++++++++++++++++++++++
arch/x86/kernel/cpu/common.c | 20 ++++++++-
arch/x86/kernel/elf.c | 15 ++++++-
arch/x86/kernel/process.c | 1 +
6 files changed, 122 insertions(+), 3 deletions(-)
diff --git a/arch/x86/include/asm/cet.h b/arch/x86/include/asm/cet.h
index a2a53fe4d5e6..d07bdeb27db4 100644
--- a/arch/x86/include/asm/cet.h
+++ b/arch/x86/include/asm/cet.h
@@ -13,7 +13,10 @@ struct cet_stat {
unsigned long shstk_base;
unsigned long shstk_size;
unsigned long exec_shstk_size;
+ unsigned long ibt_bitmap_addr;
+ unsigned long ibt_bitmap_size;
unsigned int shstk_enabled:1;
+ unsigned int ibt_enabled:1;
unsigned int locked:1;
unsigned int exec_shstk:2;
};
@@ -29,6 +32,9 @@ void cet_disable_shstk(void);
void cet_disable_free_shstk(struct task_struct *p);
int cet_restore_signal(unsigned long ssp);
int cet_setup_signal(int ia32, unsigned long addr);
+int cet_setup_ibt(void);
+int cet_setup_ibt_bitmap(void);
+void cet_disable_ibt(void);
#else
static inline int prctl_cet(int option, unsigned long arg2) { return 0; }
static inline unsigned long cet_get_shstk_ptr(void) { return 0; }
@@ -41,6 +47,8 @@ static inline void cet_disable_shstk(void) {}
static inline void cet_disable_free_shstk(struct task_struct *p) {}
static inline int cet_restore_signal(unsigned long ssp) { return 0; }
static inline int cet_setup_signal(int ia32, unsigned long addr) { return 0; }
+static inline int cet_setup_ibt(void) { return 0; }
+static inline void cet_disable_ibt(void) {}
#endif
#endif /* __ASSEMBLY__ */
diff --git a/arch/x86/include/asm/disabled-features.h b/arch/x86/include/asm/disabled-features.h
index 3624a11e5ba6..ce5bdaf0f1ff 100644
--- a/arch/x86/include/asm/disabled-features.h
+++ b/arch/x86/include/asm/disabled-features.h
@@ -62,6 +62,12 @@
#define DISABLE_SHSTK (1<<(X86_FEATURE_SHSTK & 31))
#endif
+#ifdef CONFIG_X86_INTEL_BRANCH_TRACKING_USER
+#define DISABLE_IBT 0
+#else
+#define DISABLE_IBT (1<<(X86_FEATURE_IBT & 31))
+#endif
+
/*
* Make sure to add features to the correct mask
*/
@@ -72,7 +78,7 @@
#define DISABLED_MASK4 (DISABLE_PCID)
#define DISABLED_MASK5 0
#define DISABLED_MASK6 0
-#define DISABLED_MASK7 (DISABLE_PTI)
+#define DISABLED_MASK7 (DISABLE_PTI|DISABLE_IBT)
#define DISABLED_MASK8 0
#define DISABLED_MASK9 (DISABLE_MPX)
#define DISABLED_MASK10 0
diff --git a/arch/x86/kernel/cet.c b/arch/x86/kernel/cet.c
index 1b7089dcf1ea..4df4b583311f 100644
--- a/arch/x86/kernel/cet.c
+++ b/arch/x86/kernel/cet.c
@@ -12,6 +12,8 @@
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/sched/signal.h>
+#include <linux/vmalloc.h>
+#include <linux/bitops.h>
#include <asm/msr.h>
#include <asm/user.h>
#include <asm/fpu/xstate.h>
@@ -222,3 +224,74 @@ int cet_setup_signal(int ia32, unsigned long rstor_addr)
return cet_push_shstk(ia32, ssp, rstor_addr);
}
+
+static unsigned long ibt_mmap(unsigned long addr, unsigned long len)
+{
+ struct mm_struct *mm = current->mm;
+ unsigned long populate;
+
+ down_write(&mm->mmap_sem);
+ addr = do_mmap(NULL, addr, len, PROT_READ | PROT_WRITE,
+ MAP_ANONYMOUS | MAP_PRIVATE,
+ VM_DONTDUMP, 0, &populate, NULL);
+ up_write(&mm->mmap_sem);
+
+ if (populate)
+ mm_populate(addr, populate);
+
+ return addr;
+}
+
+int cet_setup_ibt(void)
+{
+ u64 r;
+
+ if (!cpu_feature_enabled(X86_FEATURE_IBT))
+ return -EOPNOTSUPP;
+
+ rdmsrl(MSR_IA32_U_CET, r);
+ r |= (MSR_IA32_CET_ENDBR_EN | MSR_IA32_CET_NO_TRACK_EN);
+ wrmsrl(MSR_IA32_U_CET, r);
+ current->thread.cet.ibt_enabled = 1;
+ return 0;
+}
+
+int cet_setup_ibt_bitmap(void)
+{
+ u64 r;
+ unsigned long bitmap;
+ unsigned long size;
+
+ if (!cpu_feature_enabled(X86_FEATURE_IBT))
+ return -EOPNOTSUPP;
+
+ size = TASK_SIZE / PAGE_SIZE / BITS_PER_BYTE;
+ bitmap = ibt_mmap(0, size);
+
+ if (bitmap >= TASK_SIZE)
+ return -ENOMEM;
+
+ bitmap &= PAGE_MASK;
+
+ rdmsrl(MSR_IA32_U_CET, r);
+ r |= (MSR_IA32_CET_LEG_IW_EN | bitmap);
+ wrmsrl(MSR_IA32_U_CET, r);
+
+ current->thread.cet.ibt_bitmap_addr = bitmap;
+ current->thread.cet.ibt_bitmap_size = size;
+ return 0;
+}
+
+void cet_disable_ibt(void)
+{
+ u64 r;
+
+ if (!cpu_feature_enabled(X86_FEATURE_IBT))
+ return;
+
+ rdmsrl(MSR_IA32_U_CET, r);
+ r &= ~(MSR_IA32_CET_ENDBR_EN | MSR_IA32_CET_LEG_IW_EN |
+ MSR_IA32_CET_NO_TRACK_EN);
+ wrmsrl(MSR_IA32_U_CET, r);
+ current->thread.cet.ibt_enabled = 0;
+}
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index f54fabdaef60..4041d6b94455 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -403,7 +403,8 @@ __setup("nopku", setup_disable_pku);
static __always_inline void setup_cet(struct cpuinfo_x86 *c)
{
- if (cpu_feature_enabled(X86_FEATURE_SHSTK))
+ if (cpu_feature_enabled(X86_FEATURE_SHSTK) ||
+ cpu_feature_enabled(X86_FEATURE_IBT))
cr4_set_bits(X86_CR4_CET);
}
@@ -424,6 +425,23 @@ static __init int setup_disable_shstk(char *s)
__setup("noshstk", setup_disable_shstk);
#endif
+#ifdef CONFIG_X86_INTEL_BRANCH_TRACKING_USER
+static __init int setup_disable_ibt(char *s)
+{
+ /* require an exact match without trailing characters */
+ if (strlen(s))
+ return 0;
+
+ if (!boot_cpu_has(X86_FEATURE_IBT))
+ return 1;
+
+ setup_clear_cpu_cap(X86_FEATURE_IBT);
+ pr_info("x86: 'noibt' specified, disabling Branch Tracking\n");
+ return 1;
+}
+__setup("noibt", setup_disable_ibt);
+#endif
+
/*
* Some CPU features depend on higher CPUID levels, which may not always
* be available due to CPUID level capping or broken virtualization
diff --git a/arch/x86/kernel/elf.c b/arch/x86/kernel/elf.c
index de08d41971f6..a3995c8c2fc2 100644
--- a/arch/x86/kernel/elf.c
+++ b/arch/x86/kernel/elf.c
@@ -18,6 +18,7 @@
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/string.h>
+#include <linux/compat.h>
#define ELF_NOTE_DESC_OFFSET(n, align) \
round_up(sizeof(*n) + n->n_namesz, (align))
@@ -183,7 +184,8 @@ int arch_setup_features(void *ehdr_p, void *phdr_p,
struct elf64_hdr *ehdr64 = ehdr_p;
- if (!cpu_feature_enabled(X86_FEATURE_SHSTK))
+ if (!cpu_feature_enabled(X86_FEATURE_SHSTK) &&
+ !cpu_feature_enabled(X86_FEATURE_IBT))
return 0;
if (ehdr64->e_ident[EI_CLASS] == ELFCLASS64) {
@@ -211,6 +213,9 @@ int arch_setup_features(void *ehdr_p, void *phdr_p,
current->thread.cet.shstk_enabled = 0;
current->thread.cet.shstk_base = 0;
current->thread.cet.shstk_size = 0;
+ current->thread.cet.ibt_enabled = 0;
+ current->thread.cet.ibt_bitmap_addr = 0;
+ current->thread.cet.ibt_bitmap_size = 0;
current->thread.cet.locked = 0;
if (cpu_feature_enabled(X86_FEATURE_SHSTK)) {
int exec = current->thread.cet.exec_shstk;
@@ -224,6 +229,14 @@ int arch_setup_features(void *ehdr_p, void *phdr_p,
}
}
+ if (cpu_feature_enabled(X86_FEATURE_IBT)) {
+ if (ibt) {
+ err = cet_setup_ibt();
+ if (err < 0)
+ goto out;
+ }
+ }
+
/*
* Lockout CET features if no interpreter
*/
diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c
index 54ad1863c6d2..9bec164e7958 100644
--- a/arch/x86/kernel/process.c
+++ b/arch/x86/kernel/process.c
@@ -139,6 +139,7 @@ void flush_thread(void)
memset(tsk->thread.tls_array, 0, sizeof(tsk->thread.tls_array));
cet_disable_shstk();
+ cet_disable_ibt();
fpu__clear(&tsk->thread.fpu);
}
--
2.15.1
Add PTRACE interface for CET MSRs.
Signed-off-by: Yu-cheng Yu <[email protected]>
---
arch/x86/include/asm/fpu/regset.h | 7 ++++---
arch/x86/kernel/fpu/regset.c | 41 +++++++++++++++++++++++++++++++++++++++
arch/x86/kernel/ptrace.c | 16 +++++++++++++++
include/uapi/linux/elf.h | 1 +
4 files changed, 62 insertions(+), 3 deletions(-)
diff --git a/arch/x86/include/asm/fpu/regset.h b/arch/x86/include/asm/fpu/regset.h
index d5bdffb9d27f..edad0d889084 100644
--- a/arch/x86/include/asm/fpu/regset.h
+++ b/arch/x86/include/asm/fpu/regset.h
@@ -7,11 +7,12 @@
#include <linux/regset.h>
-extern user_regset_active_fn regset_fpregs_active, regset_xregset_fpregs_active;
+extern user_regset_active_fn regset_fpregs_active, regset_xregset_fpregs_active,
+ cetregs_active;
extern user_regset_get_fn fpregs_get, xfpregs_get, fpregs_soft_get,
- xstateregs_get;
+ xstateregs_get, cetregs_get;
extern user_regset_set_fn fpregs_set, xfpregs_set, fpregs_soft_set,
- xstateregs_set;
+ xstateregs_set, cetregs_set;
/*
* xstateregs_active == regset_fpregs_active. Please refer to the comment
diff --git a/arch/x86/kernel/fpu/regset.c b/arch/x86/kernel/fpu/regset.c
index bc02f5144b95..7008eb084d36 100644
--- a/arch/x86/kernel/fpu/regset.c
+++ b/arch/x86/kernel/fpu/regset.c
@@ -160,6 +160,47 @@ int xstateregs_set(struct task_struct *target, const struct user_regset *regset,
return ret;
}
+int cetregs_active(struct task_struct *target, const struct user_regset *regset)
+{
+#ifdef CONFIG_X86_INTEL_CET
+ if (target->thread.cet.shstk_enabled || target->thread.cet.ibt_enabled)
+ return regset->n;
+#endif
+ return 0;
+}
+
+int cetregs_get(struct task_struct *target, const struct user_regset *regset,
+ unsigned int pos, unsigned int count,
+ void *kbuf, void __user *ubuf)
+{
+ struct fpu *fpu = &target->thread.fpu;
+ struct cet_user_state *cetregs;
+
+ if (!boot_cpu_has(X86_FEATURE_SHSTK))
+ return -ENODEV;
+
+ cetregs = get_xsave_addr(&fpu->state.xsave, XFEATURE_MASK_SHSTK_USER);
+
+ fpu__prepare_read(fpu);
+ return user_regset_copyout(&pos, &count, &kbuf, &ubuf, cetregs, 0, -1);
+}
+
+int cetregs_set(struct task_struct *target, const struct user_regset *regset,
+ unsigned int pos, unsigned int count,
+ const void *kbuf, const void __user *ubuf)
+{
+ struct fpu *fpu = &target->thread.fpu;
+ struct cet_user_state *cetregs;
+
+ if (!boot_cpu_has(X86_FEATURE_SHSTK))
+ return -ENODEV;
+
+ cetregs = get_xsave_addr(&fpu->state.xsave, XFEATURE_MASK_SHSTK_USER);
+
+ fpu__prepare_write(fpu);
+ return user_regset_copyin(&pos, &count, &kbuf, &ubuf, cetregs, 0, -1);
+}
+
#if defined CONFIG_X86_32 || defined CONFIG_IA32_EMULATION
/*
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c
index ed5c4cdf0a34..a4501b8d086a 100644
--- a/arch/x86/kernel/ptrace.c
+++ b/arch/x86/kernel/ptrace.c
@@ -49,7 +49,9 @@ enum x86_regset {
REGSET_IOPERM64 = REGSET_XFP,
REGSET_XSTATE,
REGSET_TLS,
+ REGSET_CET64 = REGSET_TLS,
REGSET_IOPERM32,
+ REGSET_CET32,
};
struct pt_regs_offset {
@@ -1276,6 +1278,13 @@ static struct user_regset x86_64_regsets[] __ro_after_init = {
.size = sizeof(long), .align = sizeof(long),
.active = ioperm_active, .get = ioperm_get
},
+ [REGSET_CET64] = {
+ .core_note_type = NT_X86_CET,
+ .n = sizeof(struct cet_user_state) / sizeof(u64),
+ .size = sizeof(u64), .align = sizeof(u64),
+ .active = cetregs_active, .get = cetregs_get,
+ .set = cetregs_set
+ },
};
static const struct user_regset_view user_x86_64_view = {
@@ -1331,6 +1340,13 @@ static struct user_regset x86_32_regsets[] __ro_after_init = {
.size = sizeof(u32), .align = sizeof(u32),
.active = ioperm_active, .get = ioperm_get
},
+ [REGSET_CET32] = {
+ .core_note_type = NT_X86_CET,
+ .n = sizeof(struct cet_user_state) / sizeof(u64),
+ .size = sizeof(u64), .align = sizeof(u64),
+ .active = cetregs_active, .get = cetregs_get,
+ .set = cetregs_set
+ },
};
static const struct user_regset_view user_x86_32_view = {
diff --git a/include/uapi/linux/elf.h b/include/uapi/linux/elf.h
index f69ed8702271..0dd1f9dc6e14 100644
--- a/include/uapi/linux/elf.h
+++ b/include/uapi/linux/elf.h
@@ -401,6 +401,7 @@ typedef struct elf64_shdr {
#define NT_386_TLS 0x200 /* i386 TLS slots (struct user_desc) */
#define NT_386_IOPERM 0x201 /* x86 io permission bitmap (1=deny) */
#define NT_X86_XSTATE 0x202 /* x86 extended state using xsave */
+#define NT_X86_CET 0x203 /* x86 cet state */
#define NT_S390_HIGH_GPRS 0x300 /* s390 upper register halves */
#define NT_S390_TIMER 0x301 /* s390 timer register */
#define NT_S390_TODCMP 0x302 /* s390 TOD clock comparator register */
--
2.15.1
The user-mode indirect branch tracking support is done mostly by
GCC to insert ENDBR64/ENDBR32 instructions at branch targets.
The kernel provides CPUID enumeration, feature MSR setup and
the allocation of legacy bitmap.
Signed-off-by: Yu-cheng Yu <[email protected]>
---
arch/x86/Kconfig | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 24339a5299da..27bfbd137fbe 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -1953,6 +1953,18 @@ config X86_INTEL_SHADOW_STACK_USER
If unsure, say y.
+config X86_INTEL_BRANCH_TRACKING_USER
+ prompt "Intel Indirect Branch Tracking for user-mode"
+ def_bool n
+ depends on CPU_SUP_INTEL && X86_64
+ select X86_INTEL_CET
+ select ARCH_HAS_PROGRAM_PROPERTIES
+ ---help---
+ Indirect Branch Tracking provides hardware protection against return-/jmp-
+ oriented programing attacks.
+
+ If unsure, say y
+
config EFI
bool "EFI runtime service support"
depends on ACPI
--
2.15.1
From: "H.J. Lu" <[email protected]>
When Intel indirect branch tracking is enabled, functions in vDSO which
may be called indirectly should have endbr32 or endbr64 as the first
instruction. We try to compile vDSO with -fcf-protection=branch -mibt
if possible. Otherwise, we insert endbr32 or endbr64 by hand to assembly
codes generated by the compiler.
Signed-off-by: H.J. Lu <[email protected]>
---
arch/x86/entry/vdso/.gitignore | 4 ++++
arch/x86/entry/vdso/Makefile | 34 ++++++++++++++++++++++++++++++++++
arch/x86/entry/vdso/endbr.sh | 32 ++++++++++++++++++++++++++++++++
3 files changed, 70 insertions(+)
create mode 100644 arch/x86/entry/vdso/endbr.sh
diff --git a/arch/x86/entry/vdso/.gitignore b/arch/x86/entry/vdso/.gitignore
index aae8ffdd5880..552941fdfae0 100644
--- a/arch/x86/entry/vdso/.gitignore
+++ b/arch/x86/entry/vdso/.gitignore
@@ -5,3 +5,7 @@ vdso32-sysenter-syms.lds
vdso32-int80-syms.lds
vdso-image-*.c
vdso2c
+vclock_gettime.S
+vgetcpu.S
+vclock_gettime.asm
+vgetcpu.asm
diff --git a/arch/x86/entry/vdso/Makefile b/arch/x86/entry/vdso/Makefile
index d998a487c9b1..cccafc36a831 100644
--- a/arch/x86/entry/vdso/Makefile
+++ b/arch/x86/entry/vdso/Makefile
@@ -118,6 +118,40 @@ $(obj)/%-x32.o: $(obj)/%.o FORCE
targets += vdsox32.lds $(vobjx32s-y)
+ifdef CONFIG_X86_INTEL_BRANCH_TRACKING_USER
+ ifeq ($(call cc-option-yn, -fcf-protection=branch -mibt), y)
+ $(obj)/vclock_gettime.o $(obj)/vgetcpu.o $(obj)/vdso32/vclock_gettime.o: KBUILD_CFLAGS += -fcf-protection=branch -mibt
+ else
+ endbr := $(srctree)/$(src)/endbr.sh
+ quiet_cmd_endbr = ENDBR $@
+ cmd_endbr = $(CONFIG_SHELL) '$(endbr)' $< $@
+
+ quiet_cmd_cc_asm_c = CC $(quiet_modtag) $@
+ cmd_cc_asm_c = $(CC) $(c_flags) $(DISABLE_LTO) -S -o $@ $<
+
+$(obj)/%.asm: $(src)/%.c
+ $(call if_changed_dep,cc_asm_c)
+
+$(obj)/vclock_gettime.S: $(obj)/vclock_gettime.asm
+ $(call if_changed,endbr)
+
+$(obj)/vgetcpu.S: $(obj)/vgetcpu.asm
+ $(call if_changed,endbr)
+
+$(obj)/vclock_gettime.o: $(obj)/vclock_gettime.S
+ $(call if_changed_rule,as_o_S)
+
+$(obj)/vgetcpu.o: $(obj)/vgetcpu.S
+ $(call if_changed_rule,as_o_S)
+
+$(obj)/vdso32/vclock_gettime.S: $(obj)/vdso32/vclock_gettime.asm
+ $(call if_changed,endbr)
+
+$(obj)/vdso32/vclock_gettime.o: $(obj)/vdso32/vclock_gettime.S
+ $(call if_changed_rule,as_o_S)
+ endif
+endif
+
$(obj)/%.so: OBJCOPYFLAGS := -S
$(obj)/%.so: $(obj)/%.so.dbg
$(call if_changed,objcopy)
diff --git a/arch/x86/entry/vdso/endbr.sh b/arch/x86/entry/vdso/endbr.sh
new file mode 100644
index 000000000000..983dbec182f2
--- /dev/null
+++ b/arch/x86/entry/vdso/endbr.sh
@@ -0,0 +1,32 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+
+in="$1"
+out="$2"
+
+case "$in" in
+*/vdso32/*)
+ endbr=".byte 0xf3,0x0f,0x1e,0xfb"
+ ;;
+*)
+ endbr=".byte 0xf3,0x0f,0x1e,0xfa"
+ ;;
+esac
+
+need_endbr=no
+while IFS= read line ; do
+ case "$line" in
+ __vdso_clock_gettime:|__vdso_getcpu:|__vdso_gettimeofday:|__vdso_time:)
+ need_endbr=yes
+ ;;
+ " ."*)
+ ;;
+ " "*)
+ if [ "$need_endbr" = "yes" ]; then
+ need_endbr=no
+ echo " $endbr"
+ fi
+ ;;
+ esac
+ echo "$line"
+done < "$in" > "$out"
--
2.15.1
From: "H.J. Lu" <[email protected]>
Introduce CET command-line utility. This utility allows system admin
to enable/disable CET features and set default shadow stack size.
Signed-off-by: H.J. Lu <[email protected]>
---
tools/Makefile | 13 +--
tools/arch/x86/include/uapi/asm/elf_property.h | 16 +++
tools/arch/x86/include/uapi/asm/prctl.h | 33 ++++++
tools/cet/.gitignore | 1 +
tools/cet/Makefile | 11 ++
tools/cet/cetcmd.c | 134 +++++++++++++++++++++++++
tools/include/uapi/asm/elf_property.h | 4 +
tools/include/uapi/asm/prctl.h | 4 +
8 files changed, 210 insertions(+), 6 deletions(-)
create mode 100644 tools/arch/x86/include/uapi/asm/elf_property.h
create mode 100644 tools/arch/x86/include/uapi/asm/prctl.h
create mode 100644 tools/cet/.gitignore
create mode 100644 tools/cet/Makefile
create mode 100644 tools/cet/cetcmd.c
create mode 100644 tools/include/uapi/asm/elf_property.h
create mode 100644 tools/include/uapi/asm/prctl.h
diff --git a/tools/Makefile b/tools/Makefile
index be02c8b904db..bdca71e61d22 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -10,6 +10,7 @@ help:
@echo 'Possible targets:'
@echo ''
@echo ' acpi - ACPI tools'
+ @echo ' cet - Intel CET tools'
@echo ' cgroup - cgroup tools'
@echo ' cpupower - a tool for all things x86 CPU power'
@echo ' firewire - the userspace part of nosy, an IEEE-1394 traffic sniffer'
@@ -59,7 +60,7 @@ acpi: FORCE
cpupower: FORCE
$(call descend,power/$@)
-cgroup firewire hv guest spi usb virtio vm bpf iio gpio objtool leds wmi: FORCE
+cet cgroup firewire hv guest spi usb virtio vm bpf iio gpio objtool leds wmi: FORCE
$(call descend,$@)
liblockdep: FORCE
@@ -91,7 +92,7 @@ freefall: FORCE
kvm_stat: FORCE
$(call descend,kvm/$@)
-all: acpi cgroup cpupower gpio hv firewire liblockdep \
+all: acpi cet cgroup cpupower gpio hv firewire liblockdep \
perf selftests spi turbostat usb \
virtio vm bpf x86_energy_perf_policy \
tmon freefall iio objtool kvm_stat wmi
@@ -102,7 +103,7 @@ acpi_install:
cpupower_install:
$(call descend,power/$(@:_install=),install)
-cgroup_install firewire_install gpio_install hv_install iio_install perf_install spi_install usb_install virtio_install vm_install bpf_install objtool_install wmi_install:
+cet_install cgroup_install firewire_install gpio_install hv_install iio_install perf_install spi_install usb_install virtio_install vm_install bpf_install objtool_install wmi_install:
$(call descend,$(@:_install=),install)
liblockdep_install:
@@ -123,7 +124,7 @@ freefall_install:
kvm_stat_install:
$(call descend,kvm/$(@:_install=),install)
-install: acpi_install cgroup_install cpupower_install gpio_install \
+install: acpi_install cet_install cgroup_install cpupower_install gpio_install \
hv_install firewire_install iio_install liblockdep_install \
perf_install selftests_install turbostat_install usb_install \
virtio_install vm_install bpf_install x86_energy_perf_policy_install \
@@ -136,7 +137,7 @@ acpi_clean:
cpupower_clean:
$(call descend,power/cpupower,clean)
-cgroup_clean hv_clean firewire_clean spi_clean usb_clean virtio_clean vm_clean wmi_clean bpf_clean iio_clean gpio_clean objtool_clean leds_clean:
+cet_clean cgroup_clean hv_clean firewire_clean spi_clean usb_clean virtio_clean vm_clean wmi_clean bpf_clean iio_clean gpio_clean objtool_clean leds_clean:
$(call descend,$(@:_clean=),clean)
liblockdep_clean:
@@ -170,7 +171,7 @@ freefall_clean:
build_clean:
$(call descend,build,clean)
-clean: acpi_clean cgroup_clean cpupower_clean hv_clean firewire_clean \
+clean: acpi_clean cet_clean cgroup_clean cpupower_clean hv_clean firewire_clean \
perf_clean selftests_clean turbostat_clean spi_clean usb_clean virtio_clean \
vm_clean bpf_clean iio_clean x86_energy_perf_policy_clean tmon_clean \
freefall_clean build_clean libbpf_clean libsubcmd_clean liblockdep_clean \
diff --git a/tools/arch/x86/include/uapi/asm/elf_property.h b/tools/arch/x86/include/uapi/asm/elf_property.h
new file mode 100644
index 000000000000..343a871b8fc1
--- /dev/null
+++ b/tools/arch/x86/include/uapi/asm/elf_property.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _UAPI_ASM_X86_ELF_PROPERTY_H
+#define _UAPI_ASM_X86_ELF_PROPERTY_H
+
+/*
+ * pr_type
+ */
+#define GNU_PROPERTY_X86_FEATURE_1_AND (0xc0000002)
+
+/*
+ * Bits for GNU_PROPERTY_X86_FEATURE_1_AND
+ */
+#define GNU_PROPERTY_X86_FEATURE_1_SHSTK (0x00000002)
+#define GNU_PROPERTY_X86_FEATURE_1_IBT (0x00000001)
+
+#endif /* _UAPI_ASM_X86_ELF_PROPERTY_H */
diff --git a/tools/arch/x86/include/uapi/asm/prctl.h b/tools/arch/x86/include/uapi/asm/prctl.h
new file mode 100644
index 000000000000..fef476d2d2f6
--- /dev/null
+++ b/tools/arch/x86/include/uapi/asm/prctl.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _ASM_X86_PRCTL_H
+#define _ASM_X86_PRCTL_H
+
+#define ARCH_SET_GS 0x1001
+#define ARCH_SET_FS 0x1002
+#define ARCH_GET_FS 0x1003
+#define ARCH_GET_GS 0x1004
+
+#define ARCH_GET_CPUID 0x1011
+#define ARCH_SET_CPUID 0x1012
+
+#define ARCH_MAP_VDSO_X32 0x2001
+#define ARCH_MAP_VDSO_32 0x2002
+#define ARCH_MAP_VDSO_64 0x2003
+
+#define ARCH_CET_STATUS 0x3001
+#define ARCH_CET_DISABLE 0x3002
+#define ARCH_CET_LOCK 0x3003
+#define ARCH_CET_EXEC 0x3004
+#define ARCH_CET_ALLOC_SHSTK 0x3005
+#define ARCH_CET_PUSH_SHSTK 0x3006
+#define ARCH_CET_LEGACY_BITMAP 0x3007
+
+/*
+ * Settings for ARCH_CET_EXEC
+ */
+#define CET_EXEC_ELF_PROPERTY 0
+#define CET_EXEC_ALWAYS_OFF 1
+#define CET_EXEC_ALWAYS_ON 2
+#define CET_EXEC_MAX CET_EXEC_ALWAYS_ON
+
+#endif /* _ASM_X86_PRCTL_H */
diff --git a/tools/cet/.gitignore b/tools/cet/.gitignore
new file mode 100644
index 000000000000..bd100f593454
--- /dev/null
+++ b/tools/cet/.gitignore
@@ -0,0 +1 @@
+cetcmd
diff --git a/tools/cet/Makefile b/tools/cet/Makefile
new file mode 100644
index 000000000000..fae42b84d796
--- /dev/null
+++ b/tools/cet/Makefile
@@ -0,0 +1,11 @@
+# SPDX-License-Identifier: GPL-2.0
+# Makefile for CET tools
+
+CFLAGS = -O2 -g -Wall -Wextra -I../include/uapi
+
+all: cetcmd
+%: %.c
+ $(CC) $(CFLAGS) -o $@ $^
+
+clean:
+ $(RM) cetcmd
diff --git a/tools/cet/cetcmd.c b/tools/cet/cetcmd.c
new file mode 100644
index 000000000000..dbbfb5267c1f
--- /dev/null
+++ b/tools/cet/cetcmd.c
@@ -0,0 +1,134 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#define _GNU_SOURCE
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include <errno.h>
+#include <error.h>
+#include <asm/elf_property.h>
+#include <asm/prctl.h>
+
+enum command_line_switch {
+ OPTION_ELF_PROPERTY = 150,
+ OPTION_ALWAYS_OFF,
+ OPTION_ALWAYS_ON,
+ OPTION_SHSTK_SIZE
+};
+
+static const struct option options[] = {
+ {"property", no_argument, 0, OPTION_ELF_PROPERTY},
+ {"off", no_argument, 0, OPTION_ALWAYS_OFF},
+ {"on", no_argument, 0, OPTION_ALWAYS_ON},
+ {"shstk-size", required_argument, 0, OPTION_SHSTK_SIZE},
+ {"feature", required_argument, 0, 'f'},
+ {"help", no_argument, 0, 'h'},
+ {0, no_argument, 0, 0}
+};
+
+__attribute__((__noreturn__))
+static void
+usage(FILE *stream, int exit_status)
+{
+ fprintf(stream, "Usage: %s <option(s)> -- command [args]\n",
+ program_invocation_short_name);
+ fprintf(stream, " Run command with CET features\n");
+ fprintf(stream, " The options are:\n");
+ fprintf(stream,
+ "\t--property Enable CET features based on ELF property note\n"
+ "\t--off Always disable CET features\n"
+ "\t--on Always enable CET features\n"
+ "\t-f, --feature [ibt|shstk] Control CET [IBT|SHSTK] feature\n"
+ "\t--shstk-size SIZE Set shadow stack size\n"
+ "\t-h --help Display this information\n");
+
+ exit(exit_status);
+}
+
+extern int arch_prctl(int, unsigned long *);
+
+int
+main(int argc, char *const *argv, char *const *envp)
+{
+ int c;
+ unsigned long values[3] = {0, -1, 0};
+ unsigned long status[3];
+ unsigned long shstk_size = -1;
+ char **args;
+ size_t i, num_of_args;
+
+ while ((c = getopt_long(argc, argv, "f:h",
+ options, (int *) 0)) != EOF) {
+ switch (c) {
+ case OPTION_ELF_PROPERTY:
+ values[1] = CET_EXEC_ELF_PROPERTY;
+ break;
+
+ case OPTION_ALWAYS_OFF:
+ values[1] = CET_EXEC_ALWAYS_OFF;
+ break;
+
+ case OPTION_ALWAYS_ON:
+ values[1] = CET_EXEC_ALWAYS_ON;
+ break;
+
+ case OPTION_SHSTK_SIZE:
+ shstk_size = strtol(optarg, NULL, 0);
+ break;
+
+ case 'f':
+ if (strcasecmp(optarg, "ibt") == 0)
+ values[0] = GNU_PROPERTY_X86_FEATURE_1_IBT;
+ else if (strcasecmp(optarg, "shstk") == 0)
+ values[0] = GNU_PROPERTY_X86_FEATURE_1_SHSTK;
+ else
+ usage(stderr, EXIT_FAILURE);
+ break;
+
+ case 'h':
+ usage(stdout, EXIT_SUCCESS);
+
+ default:
+ usage(stderr, EXIT_FAILURE);
+ }
+ }
+
+ if ((optind + 1) > argc ||
+ (values[1] == (unsigned long)-1 &&
+ shstk_size == (unsigned long)-1))
+ usage(stderr, EXIT_FAILURE);
+
+ /* If --shstk-size isn't used, get the current shadow stack size. */
+ if (shstk_size == (unsigned long)-1) {
+ if (arch_prctl(ARCH_CET_STATUS, status) < 0)
+ error(EXIT_FAILURE, errno, "arch_prctl failed\n");
+ shstk_size = status[2];
+ }
+
+ /* If --property/--off/--on aren't used, clear all features. */
+ if (values[1] == (unsigned long)-1) {
+ values[0] = 0;
+ values[1] = 0;
+ } else {
+ if (values[0] == 0)
+ values[0] = (GNU_PROPERTY_X86_FEATURE_1_IBT |
+ GNU_PROPERTY_X86_FEATURE_1_SHSTK);
+ }
+
+ values[2] = shstk_size;
+ if (arch_prctl(ARCH_CET_EXEC, values) < 0)
+ error(EXIT_FAILURE, errno, "arch_prctl failed\n");
+
+ num_of_args = argc - optind + 1;
+ args = malloc(num_of_args * sizeof(char *));
+ if (args == NULL)
+ error(EXIT_FAILURE, errno, "malloc failed\n");
+
+ for (i = 0; i < num_of_args; i++)
+ args[i] = argv[optind + i];
+ args[i] = NULL;
+
+ return execvpe(argv[optind], args, envp);
+}
diff --git a/tools/include/uapi/asm/elf_property.h b/tools/include/uapi/asm/elf_property.h
new file mode 100644
index 000000000000..1281b4e1a578
--- /dev/null
+++ b/tools/include/uapi/asm/elf_property.h
@@ -0,0 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#if defined(__i386__) || defined(__x86_64__)
+#include "../../arch/x86/include/uapi/asm/elf_property.h"
+#endif
\ No newline at end of file
diff --git a/tools/include/uapi/asm/prctl.h b/tools/include/uapi/asm/prctl.h
new file mode 100644
index 000000000000..b0894b828b06
--- /dev/null
+++ b/tools/include/uapi/asm/prctl.h
@@ -0,0 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#if defined(__i386__) || defined(__x86_64__)
+#include "../../arch/x86/include/uapi/asm/prctl.h"
+#endif
\ No newline at end of file
--
2.15.1
On 06/07/2018 07:38 AM, Yu-cheng Yu wrote:
> The user-mode indirect branch tracking support is done mostly by
> GCC to insert ENDBR64/ENDBR32 instructions at branch targets.
> The kernel provides CPUID enumeration, feature MSR setup and
> the allocation of legacy bitmap.
>
> Signed-off-by: Yu-cheng Yu <[email protected]>
> ---
> arch/x86/Kconfig | 12 ++++++++++++
> 1 file changed, 12 insertions(+)
>
> diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
> index 24339a5299da..27bfbd137fbe 100644
> --- a/arch/x86/Kconfig
> +++ b/arch/x86/Kconfig
> @@ -1953,6 +1953,18 @@ config X86_INTEL_SHADOW_STACK_USER
>
> If unsure, say y.
>
> +config X86_INTEL_BRANCH_TRACKING_USER
> + prompt "Intel Indirect Branch Tracking for user-mode"
> + def_bool n
> + depends on CPU_SUP_INTEL && X86_64
> + select X86_INTEL_CET
> + select ARCH_HAS_PROGRAM_PROPERTIES
> + ---help---
> + Indirect Branch Tracking provides hardware protection against
> + oriented programing attacks.
programming
and please just move the return/jmp parts to the next line also:
protection against
return-/jmp-oriented programming attacks.
> +
> + If unsure, say y
> +
> config EFI
> bool "EFI runtime service support"
> depends on ACPI
>
--
~Randy
On Thu, Jun 7, 2018 at 7:42 AM Yu-cheng Yu <[email protected]> wrote:
>
> The indirect branch tracking legacy bitmap takes a large address
> space. This causes may_expand_vm() failure on the address limit
> check. For a IBT-enabled task, add the bitmap size to the
> address limit.
>
> Signed-off-by: Yu-cheng Yu <[email protected]>
> ---
> arch/x86/include/uapi/asm/resource.h | 5 +++++
> include/uapi/asm-generic/resource.h | 3 +++
> mm/mmap.c | 8 +++++++-
> 3 files changed, 15 insertions(+), 1 deletion(-)
>
> diff --git a/arch/x86/include/uapi/asm/resource.h b/arch/x86/include/uapi/asm/resource.h
> index 04bc4db8921b..0741b2a6101a 100644
> --- a/arch/x86/include/uapi/asm/resource.h
> +++ b/arch/x86/include/uapi/asm/resource.h
> @@ -1 +1,6 @@
> +/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
> +#ifdef CONFIG_X86_INTEL_CET
> +#define rlimit_as_extra() current->thread.cet.ibt_bitmap_size
> +#endif
> +
> #include <asm-generic/resource.h>
> diff --git a/include/uapi/asm-generic/resource.h b/include/uapi/asm-generic/resource.h
> index f12db7a0da64..8a7608a09700 100644
> --- a/include/uapi/asm-generic/resource.h
> +++ b/include/uapi/asm-generic/resource.h
> @@ -58,5 +58,8 @@
> # define RLIM_INFINITY (~0UL)
> #endif
>
> +#ifndef rlimit_as_extra
> +#define rlimit_as_extra() 0
> +#endif
>
> #endif /* _UAPI_ASM_GENERIC_RESOURCE_H */
> diff --git a/mm/mmap.c b/mm/mmap.c
> index e7d1fcb7ec58..5c07f052bed7 100644
> --- a/mm/mmap.c
> +++ b/mm/mmap.c
> @@ -3255,7 +3255,13 @@ struct vm_area_struct *copy_vma(struct vm_area_struct **vmap,
> */
> bool may_expand_vm(struct mm_struct *mm, vm_flags_t flags, unsigned long npages)
> {
> - if (mm->total_vm + npages > rlimit(RLIMIT_AS) >> PAGE_SHIFT)
> + unsigned long as_limit = rlimit(RLIMIT_AS);
> + unsigned long as_limit_plus = as_limit + rlimit_as_extra();
> +
> + if (as_limit_plus > as_limit)
> + as_limit = as_limit_plus;
> +
What happens if as_limit_plus overflows? I guess it's probably okay here.
On Thu, Jun 7, 2018 at 7:42 AM Yu-cheng Yu <[email protected]> wrote:
>
> Add PTRACE interface for CET MSRs.
>
> Signed-off-by: Yu-cheng Yu <[email protected]>
> ---
> arch/x86/include/asm/fpu/regset.h | 7 ++++---
> arch/x86/kernel/fpu/regset.c | 41 +++++++++++++++++++++++++++++++++++++++
> arch/x86/kernel/ptrace.c | 16 +++++++++++++++
> include/uapi/linux/elf.h | 1 +
> 4 files changed, 62 insertions(+), 3 deletions(-)
>
> diff --git a/arch/x86/include/asm/fpu/regset.h b/arch/x86/include/asm/fpu/regset.h
> index d5bdffb9d27f..edad0d889084 100644
> --- a/arch/x86/include/asm/fpu/regset.h
> +++ b/arch/x86/include/asm/fpu/regset.h
> @@ -7,11 +7,12 @@
>
> #include <linux/regset.h>
>
> -extern user_regset_active_fn regset_fpregs_active, regset_xregset_fpregs_active;
> +extern user_regset_active_fn regset_fpregs_active, regset_xregset_fpregs_active,
> + cetregs_active;
> extern user_regset_get_fn fpregs_get, xfpregs_get, fpregs_soft_get,
> - xstateregs_get;
> + xstateregs_get, cetregs_get;
> extern user_regset_set_fn fpregs_set, xfpregs_set, fpregs_soft_set,
> - xstateregs_set;
> + xstateregs_set, cetregs_set;
>
> /*
> * xstateregs_active == regset_fpregs_active. Please refer to the comment
> diff --git a/arch/x86/kernel/fpu/regset.c b/arch/x86/kernel/fpu/regset.c
> index bc02f5144b95..7008eb084d36 100644
> --- a/arch/x86/kernel/fpu/regset.c
> +++ b/arch/x86/kernel/fpu/regset.c
> @@ -160,6 +160,47 @@ int xstateregs_set(struct task_struct *target, const struct user_regset *regset,
> return ret;
> }
>
> +int cetregs_active(struct task_struct *target, const struct user_regset *regset)
> +{
> +#ifdef CONFIG_X86_INTEL_CET
> + if (target->thread.cet.shstk_enabled || target->thread.cet.ibt_enabled)
> + return regset->n;
> +#endif
> + return 0;
> +}
> +
> +int cetregs_get(struct task_struct *target, const struct user_regset *regset,
> + unsigned int pos, unsigned int count,
> + void *kbuf, void __user *ubuf)
> +{
> + struct fpu *fpu = &target->thread.fpu;
> + struct cet_user_state *cetregs;
> +
> + if (!boot_cpu_has(X86_FEATURE_SHSTK))
> + return -ENODEV;
This whole series has a boot_cpu_has, static_cpu_has, and
cpu_feature_enabled all over. Please settle on just one, preferably
static_cpu_has.
> +
> + cetregs = get_xsave_addr(&fpu->state.xsave, XFEATURE_MASK_SHSTK_USER);
> +
> + fpu__prepare_read(fpu);
> + return user_regset_copyout(&pos, &count, &kbuf, &ubuf, cetregs, 0, -1);
> +}
> +
> +int cetregs_set(struct task_struct *target, const struct user_regset *regset,
> + unsigned int pos, unsigned int count,
> + const void *kbuf, const void __user *ubuf)
> +{
> + struct fpu *fpu = &target->thread.fpu;
> + struct cet_user_state *cetregs;
> +
> + if (!boot_cpu_has(X86_FEATURE_SHSTK))
> + return -ENODEV;
> +
> + cetregs = get_xsave_addr(&fpu->state.xsave, XFEATURE_MASK_SHSTK_USER);
> +
> + fpu__prepare_write(fpu);
> + return user_regset_copyin(&pos, &count, &kbuf, &ubuf, cetregs, 0, -1);
Is this called for core dumping on current? If so, please make sure
it's correct. (I think it is for get but maybe not for set.)
On Thu, Jun 7, 2018 at 7:42 AM Yu-cheng Yu <[email protected]> wrote:
>
> From: "H.J. Lu" <[email protected]>
>
> When Intel indirect branch tracking is enabled, functions in vDSO which
> may be called indirectly should have endbr32 or endbr64 as the first
> instruction. We try to compile vDSO with -fcf-protection=branch -mibt
> if possible. Otherwise, we insert endbr32 or endbr64 by hand to assembly
> codes generated by the compiler.
Wow, that's... a genuine abomination. Do we really need to support
CET on kernels built with old toolchains?
--Andy
On Thu, Jun 7, 2018 at 1:50 PM, Andy Lutomirski <[email protected]> wrote:
> On Thu, Jun 7, 2018 at 7:42 AM Yu-cheng Yu <[email protected]> wrote:
>>
>> From: "H.J. Lu" <[email protected]>
>>
>> When Intel indirect branch tracking is enabled, functions in vDSO which
>> may be called indirectly should have endbr32 or endbr64 as the first
>> instruction. We try to compile vDSO with -fcf-protection=branch -mibt
>> if possible. Otherwise, we insert endbr32 or endbr64 by hand to assembly
>> codes generated by the compiler.
>
> Wow, that's... a genuine abomination. Do we really need to support
> CET on kernels built with old toolchains?
>
Yes. GCC 7 should be able to build CET kernel.
--
H.J.
On Thu, Jun 7, 2018 at 3:03 PM H.J. Lu <[email protected]> wrote:
>
> On Thu, Jun 7, 2018 at 1:50 PM, Andy Lutomirski <[email protected]> wrote:
> > On Thu, Jun 7, 2018 at 7:42 AM Yu-cheng Yu <[email protected]> wrote:
> >>
> >> From: "H.J. Lu" <[email protected]>
> >>
> >> When Intel indirect branch tracking is enabled, functions in vDSO which
> >> may be called indirectly should have endbr32 or endbr64 as the first
> >> instruction. We try to compile vDSO with -fcf-protection=branch -mibt
> >> if possible. Otherwise, we insert endbr32 or endbr64 by hand to assembly
> >> codes generated by the compiler.
> >
> > Wow, that's... a genuine abomination. Do we really need to support
> > CET on kernels built with old toolchains?
> >
>
> Yes. GCC 7 should be able to build CET kernel.
>
Why? Presumably people running distros that use CET are going to have
kernels build with a CET-supporting compiler.
If we really really need this patch, then I want some kind of
assurance that selftests will catch the failure if something breaks it
or a new vDSO entry point is added. But my inclination is to NAK this
patch and let the distros carry it if they really really want it. As
it stands, this sucks for maintainability.
On Thu, Jun 7, 2018 at 4:00 PM, Andy Lutomirski <[email protected]> wrote:
> On Thu, Jun 7, 2018 at 3:03 PM H.J. Lu <[email protected]> wrote:
>>
>> On Thu, Jun 7, 2018 at 1:50 PM, Andy Lutomirski <[email protected]> wrote:
>> > On Thu, Jun 7, 2018 at 7:42 AM Yu-cheng Yu <[email protected]> wrote:
>> >>
>> >> From: "H.J. Lu" <[email protected]>
>> >>
>> >> When Intel indirect branch tracking is enabled, functions in vDSO which
>> >> may be called indirectly should have endbr32 or endbr64 as the first
>> >> instruction. We try to compile vDSO with -fcf-protection=branch -mibt
>> >> if possible. Otherwise, we insert endbr32 or endbr64 by hand to assembly
>> >> codes generated by the compiler.
>> >
>> > Wow, that's... a genuine abomination. Do we really need to support
>> > CET on kernels built with old toolchains?
>> >
>>
>> Yes. GCC 7 should be able to build CET kernel.
>>
>
> Why? Presumably people running distros that use CET are going to have
> kernels build with a CET-supporting compiler.
>
Good point. It was needed before GCC 8 was released. We can drop
arch/x86/entry/vdso/endbr.sh now.
--
H.J.
On Thu, Jun 7, 2018 at 5:31 PM H.J. Lu <[email protected]> wrote:
>
> On Thu, Jun 7, 2018 at 4:00 PM, Andy Lutomirski <[email protected]> wrote:
> > On Thu, Jun 7, 2018 at 3:03 PM H.J. Lu <[email protected]> wrote:
> >>
> >> On Thu, Jun 7, 2018 at 1:50 PM, Andy Lutomirski <[email protected]> wrote:
> >> > On Thu, Jun 7, 2018 at 7:42 AM Yu-cheng Yu <[email protected]> wrote:
> >> >>
> >> >> From: "H.J. Lu" <[email protected]>
> >> >>
> >> >> When Intel indirect branch tracking is enabled, functions in vDSO which
> >> >> may be called indirectly should have endbr32 or endbr64 as the first
> >> >> instruction. We try to compile vDSO with -fcf-protection=branch -mibt
> >> >> if possible. Otherwise, we insert endbr32 or endbr64 by hand to assembly
> >> >> codes generated by the compiler.
> >> >
> >> > Wow, that's... a genuine abomination. Do we really need to support
> >> > CET on kernels built with old toolchains?
> >> >
> >>
> >> Yes. GCC 7 should be able to build CET kernel.
> >>
> >
> > Why? Presumably people running distros that use CET are going to have
> > kernels build with a CET-supporting compiler.
> >
>
> Good point. It was needed before GCC 8 was released. We can drop
> arch/x86/entry/vdso/endbr.sh now.
>
Phew! We'll still need a patch to prevent configuring CET on a
compiler that can't support it.