From: Yu-cheng Yu <yu-cheng.yu@intel.com>
To: linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org,
linux-mm@kvack.org, linux-arch@vger.kernel.org, x86@kernel.org,
"H. Peter Anvin" <hpa@zytor.com>,
Thomas Gleixner <tglx@linutronix.de>,
Ingo Molnar <mingo@redhat.com>, "H.J. Lu" <hjl.tools@gmail.com>,
Vedvyas Shanbhogue <vedvyas.shanbhogue@intel.com>,
"Ravi V. Shankar" <ravi.v.shankar@intel.com>,
Dave Hansen <dave.hansen@linux.intel.com>,
Andy Lutomirski <luto@amacapital.net>,
Jonathan Corbet <corbet@lwn.net>, Oleg Nesterov <oleg@redhat.com>,
Arnd Bergmann <arnd@arndb.de>,
Mike Kravetz <mike.kravetz@oracle.com>
Cc: Yu-cheng Yu <yu-cheng.yu@intel.com>
Subject: [PATCH 06/10] x86/cet: Add arch_prctl functions for shadow stack
Date: Thu, 7 Jun 2018 07:38:03 -0700 [thread overview]
Message-ID: <20180607143807.3611-7-yu-cheng.yu@intel.com> (raw)
In-Reply-To: <20180607143807.3611-1-yu-cheng.yu@intel.com>
The following operations are provided.
ARCH_CET_STATUS:
return the current CET status
ARCH_CET_DISABLE:
disable CET features
ARCH_CET_LOCK:
lock out CET features
ARCH_CET_EXEC:
set CET features for exec()
ARCH_CET_ALLOC_SHSTK:
allocate a new shadow stack
ARCH_CET_PUSH_SHSTK:
put a return address on shadow stack
ARCH_CET_ALLOC_SHSTK and ARCH_CET_PUSH_SHSTK are intended only for
the implementation of GLIBC ucontext related APIs.
Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
Signed-off-by: Yu-cheng Yu <yu-cheng.yu@intel.com>
---
arch/x86/include/asm/cet.h | 7 ++
arch/x86/include/uapi/asm/prctl.h | 15 +++
arch/x86/kernel/Makefile | 2 +-
arch/x86/kernel/cet.c | 18 +++-
arch/x86/kernel/cet_prctl.c | 203 ++++++++++++++++++++++++++++++++++++++
arch/x86/kernel/elf.c | 24 ++++-
arch/x86/kernel/process.c | 7 ++
7 files changed, 270 insertions(+), 6 deletions(-)
create mode 100644 arch/x86/kernel/cet_prctl.c
diff --git a/arch/x86/include/asm/cet.h b/arch/x86/include/asm/cet.h
index c8fd87e13859..a2a53fe4d5e6 100644
--- a/arch/x86/include/asm/cet.h
+++ b/arch/x86/include/asm/cet.h
@@ -12,24 +12,31 @@ struct task_struct;
struct cet_stat {
unsigned long shstk_base;
unsigned long shstk_size;
+ unsigned long exec_shstk_size;
unsigned int shstk_enabled:1;
+ unsigned int locked:1;
+ unsigned int exec_shstk:2;
};
#ifdef CONFIG_X86_INTEL_CET
+int prctl_cet(int option, unsigned long arg2);
unsigned long cet_get_shstk_ptr(void);
int cet_push_shstk(int ia32, unsigned long ssp, unsigned long val);
int cet_setup_shstk(void);
int cet_setup_thread_shstk(struct task_struct *p);
+int cet_alloc_shstk(unsigned long *arg);
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);
#else
+static inline int prctl_cet(int option, unsigned long arg2) { return 0; }
static inline unsigned long cet_get_shstk_ptr(void) { return 0; }
static inline int cet_push_shstk(int ia32, unsigned long ssp,
unsigned long val) { return 0; }
static inline int cet_setup_shstk(void) { return 0; }
static inline int cet_setup_thread_shstk(struct task_struct *p) { return 0; }
+static inline int cet_alloc_shstk(unsigned long *arg) { return -EINVAL; }
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; }
diff --git a/arch/x86/include/uapi/asm/prctl.h b/arch/x86/include/uapi/asm/prctl.h
index 5a6aac9fa41f..f9965403b655 100644
--- a/arch/x86/include/uapi/asm/prctl.h
+++ b/arch/x86/include/uapi/asm/prctl.h
@@ -14,4 +14,19 @@
#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
+
+/*
+ * 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/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
index cbf983f44b61..80464f925a6a 100644
--- a/arch/x86/kernel/Makefile
+++ b/arch/x86/kernel/Makefile
@@ -138,7 +138,7 @@ obj-$(CONFIG_UNWINDER_ORC) += unwind_orc.o
obj-$(CONFIG_UNWINDER_FRAME_POINTER) += unwind_frame.o
obj-$(CONFIG_UNWINDER_GUESS) += unwind_guess.o
-obj-$(CONFIG_X86_INTEL_CET) += cet.o
+obj-$(CONFIG_X86_INTEL_CET) += cet.o cet_prctl.o
obj-$(CONFIG_ARCH_HAS_PROGRAM_PROPERTIES) += elf.o
diff --git a/arch/x86/kernel/cet.c b/arch/x86/kernel/cet.c
index 156f5d88ffd5..1b7089dcf1ea 100644
--- a/arch/x86/kernel/cet.c
+++ b/arch/x86/kernel/cet.c
@@ -83,6 +83,19 @@ static unsigned long shstk_mmap(unsigned long addr, unsigned long len)
return addr;
}
+int cet_alloc_shstk(unsigned long *arg)
+{
+ unsigned long size = *arg;
+ unsigned long addr;
+
+ addr = shstk_mmap(0, size);
+ if (addr >= TASK_SIZE)
+ return -ENOMEM;
+
+ *arg = addr;
+ return 0;
+}
+
int cet_setup_shstk(void)
{
unsigned long addr, size;
@@ -90,7 +103,10 @@ int cet_setup_shstk(void)
if (!cpu_feature_enabled(X86_FEATURE_SHSTK))
return -EOPNOTSUPP;
- size = SHSTK_SIZE;
+ size = current->thread.cet.exec_shstk_size;
+ if ((size > TASK_SIZE) || (size == 0))
+ size = SHSTK_SIZE;
+
addr = shstk_mmap(0, size);
if (addr >= TASK_SIZE)
diff --git a/arch/x86/kernel/cet_prctl.c b/arch/x86/kernel/cet_prctl.c
new file mode 100644
index 000000000000..326996e2ea80
--- /dev/null
+++ b/arch/x86/kernel/cet_prctl.c
@@ -0,0 +1,203 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#include <linux/errno.h>
+#include <linux/uaccess.h>
+#include <linux/prctl.h>
+#include <linux/compat.h>
+#include <asm/processor.h>
+#include <asm/prctl.h>
+#include <asm/elf.h>
+#include <asm/elf_property.h>
+#include <asm/cet.h>
+
+/*
+ * Handler of prctl for CET:
+ *
+ * ARCH_CET_STATUS: return the current status
+ * ARCH_CET_DISABLE: disable features
+ * ARCH_CET_LOCK: lock out cet features until exec()
+ * 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
+ */
+
+static int handle_get_status(unsigned long arg2)
+{
+ unsigned int features = 0, cet_exec = 0;
+ unsigned long shstk_size = 0;
+
+ if (current->thread.cet.shstk_enabled)
+ features |= GNU_PROPERTY_X86_FEATURE_1_SHSTK;
+ if (current->thread.cet.exec_shstk == CET_EXEC_ALWAYS_ON)
+ cet_exec |= GNU_PROPERTY_X86_FEATURE_1_SHSTK;
+ shstk_size = current->thread.cet.exec_shstk_size;
+
+ if (in_compat_syscall()) {
+ unsigned int buf[3];
+
+ buf[0] = features;
+ buf[1] = cet_exec;
+ buf[2] = (unsigned int)shstk_size;
+ return copy_to_user((unsigned int __user *)arg2, buf,
+ sizeof(buf));
+ } else {
+ unsigned long buf[3];
+
+ buf[0] = (unsigned long)features;
+ buf[1] = (unsigned long)cet_exec;
+ buf[2] = shstk_size;
+ return copy_to_user((unsigned long __user *)arg2, buf,
+ sizeof(buf));
+ }
+}
+
+static int handle_set_exec(unsigned long arg2)
+{
+ unsigned int features = 0, cet_exec = 0;
+ unsigned long shstk_size = 0;
+ int err = 0;
+
+ if (in_compat_syscall()) {
+ unsigned int buf[3];
+
+ err = copy_from_user(buf, (unsigned int __user *)arg2,
+ sizeof(buf));
+ if (!err) {
+ features = buf[0];
+ cet_exec = buf[1];
+ shstk_size = (unsigned long)buf[2];
+ }
+ } else {
+ unsigned long buf[3];
+
+ err = copy_from_user(buf, (unsigned long __user *)arg2,
+ sizeof(buf));
+ if (!err) {
+ features = (unsigned int)buf[0];
+ cet_exec = (unsigned int)buf[1];
+ shstk_size = buf[2];
+ }
+ }
+
+ if (err)
+ return -EFAULT;
+ if (cet_exec > CET_EXEC_MAX)
+ return -EINVAL;
+ if (shstk_size >= TASK_SIZE)
+ return -EINVAL;
+
+ if (features & GNU_PROPERTY_X86_FEATURE_1_SHSTK) {
+ if (!cpu_feature_enabled(X86_FEATURE_SHSTK))
+ return -EINVAL;
+ if ((current->thread.cet.exec_shstk == 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;
+
+ current->thread.cet.exec_shstk_size = shstk_size;
+ return 0;
+}
+
+static int handle_push_shstk(unsigned long arg2)
+{
+ unsigned long ssp = 0, ret_addr = 0;
+ int ia32, err;
+
+ ia32 = in_ia32_syscall();
+
+ if (ia32) {
+ unsigned int buf[2];
+
+ err = copy_from_user(buf, (unsigned int __user *)arg2,
+ sizeof(buf));
+ if (!err) {
+ ssp = (unsigned long)buf[0];
+ ret_addr = (unsigned long)buf[1];
+ }
+ } else {
+ unsigned long buf[2];
+
+ err = copy_from_user(buf, (unsigned long __user *)arg2,
+ sizeof(buf));
+ if (!err) {
+ ssp = buf[0];
+ ret_addr = buf[1];
+ }
+ }
+ if (err)
+ return -EFAULT;
+ err = cet_push_shstk(ia32, ssp, ret_addr);
+ if (err)
+ return -err;
+ return 0;
+}
+
+static int handle_alloc_shstk(unsigned long arg2)
+{
+ int err = 0;
+ unsigned long shstk_size = 0;
+
+ if (in_ia32_syscall()) {
+ unsigned int size;
+
+ err = get_user(size, (unsigned int __user *)arg2);
+ if (!err)
+ shstk_size = size;
+ } else {
+ err = get_user(shstk_size, (unsigned long __user *)arg2);
+ }
+
+ if (err)
+ return -EFAULT;
+
+ err = cet_alloc_shstk(&shstk_size);
+ if (err)
+ return -err;
+
+ if (in_ia32_syscall()) {
+ if (put_user(shstk_size, (unsigned int __user *)arg2))
+ return -EFAULT;
+ } else {
+ if (put_user(shstk_size, (unsigned long __user *)arg2))
+ return -EFAULT;
+ }
+ return 0;
+}
+
+int prctl_cet(int option, unsigned long arg2)
+{
+ if (!cpu_feature_enabled(X86_FEATURE_SHSTK))
+ return -EINVAL;
+
+ switch (option) {
+ case ARCH_CET_STATUS:
+ return handle_get_status(arg2);
+
+ case ARCH_CET_DISABLE:
+ if (current->thread.cet.locked)
+ return -EPERM;
+ if (arg2 & GNU_PROPERTY_X86_FEATURE_1_SHSTK)
+ cet_disable_free_shstk(current);
+
+ return 0;
+
+ case ARCH_CET_LOCK:
+ current->thread.cet.locked = 1;
+ return 0;
+
+ case ARCH_CET_EXEC:
+ return handle_set_exec(arg2);
+
+ case ARCH_CET_ALLOC_SHSTK:
+ return handle_alloc_shstk(arg2);
+
+ case ARCH_CET_PUSH_SHSTK:
+ return handle_push_shstk(arg2);
+
+ default:
+ return -EINVAL;
+ }
+}
diff --git a/arch/x86/kernel/elf.c b/arch/x86/kernel/elf.c
index 8e2719d8dc86..de08d41971f6 100644
--- a/arch/x86/kernel/elf.c
+++ b/arch/x86/kernel/elf.c
@@ -8,7 +8,10 @@
#include <asm/cet.h>
#include <asm/elf_property.h>
+#include <asm/prctl.h>
+#include <asm/processor.h>
#include <uapi/linux/elf-em.h>
+#include <uapi/linux/prctl.h>
#include <linux/binfmts.h>
#include <linux/elf.h>
#include <linux/slab.h>
@@ -208,13 +211,26 @@ 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.locked = 0;
if (cpu_feature_enabled(X86_FEATURE_SHSTK)) {
- if (shstk) {
- err = cet_setup_shstk();
- if (err < 0)
- goto out;
+ int exec = current->thread.cet.exec_shstk;
+
+ if (exec != CET_EXEC_ALWAYS_OFF) {
+ if (shstk || (exec == CET_EXEC_ALWAYS_ON)) {
+ err = cet_setup_shstk();
+ if (err < 0)
+ goto out;
+ }
}
}
+
+ /*
+ * Lockout CET features if no interpreter
+ */
+ if (!interp)
+ current->thread.cet.locked = 1;
+
+ err = 0;
out:
return err;
}
diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c
index ae56caee41f9..54ad1863c6d2 100644
--- a/arch/x86/kernel/process.c
+++ b/arch/x86/kernel/process.c
@@ -794,6 +794,13 @@ long do_arch_prctl_common(struct task_struct *task, int option,
return get_cpuid_mode();
case ARCH_SET_CPUID:
return set_cpuid_mode(task, cpuid_enabled);
+ case ARCH_CET_STATUS:
+ case ARCH_CET_DISABLE:
+ case ARCH_CET_LOCK:
+ case ARCH_CET_EXEC:
+ case ARCH_CET_ALLOC_SHSTK:
+ case ARCH_CET_PUSH_SHSTK:
+ return prctl_cet(option, cpuid_enabled);
}
return -EINVAL;
--
2.15.1
next prev parent reply other threads:[~2018-06-07 15:40 UTC|newest]
Thread overview: 98+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-06-07 14:37 [PATCH 00/10] Control Flow Enforcement - Part (3) Yu-cheng Yu
2018-06-07 14:37 ` [PATCH 01/10] x86/cet: User-mode shadow stack support Yu-cheng Yu
2018-06-07 16:37 ` Andy Lutomirski
2018-06-07 17:46 ` Yu-cheng Yu
2018-06-07 17:55 ` Dave Hansen
2018-06-07 18:23 ` Andy Lutomirski
2018-06-12 11:56 ` Balbir Singh
2018-06-12 15:03 ` Yu-cheng Yu
2018-06-07 14:37 ` [PATCH 02/10] x86/cet: Introduce WRUSS instruction Yu-cheng Yu
2018-06-07 16:40 ` Andy Lutomirski
2018-06-07 16:51 ` Yu-cheng Yu
2018-06-07 18:41 ` Peter Zijlstra
2018-06-07 20:31 ` Yu-cheng Yu
2018-06-11 8:17 ` Peter Zijlstra
2018-06-11 15:02 ` Yu-cheng Yu
2018-06-14 1:30 ` Balbir Singh
2018-06-14 14:43 ` Yu-cheng Yu
2018-06-07 14:38 ` [PATCH 03/10] x86/cet: Signal handling for shadow stack Yu-cheng Yu
2018-06-07 18:30 ` Andy Lutomirski
2018-06-07 18:58 ` Florian Weimer
2018-06-07 19:51 ` Yu-cheng Yu
2018-06-07 20:07 ` Cyrill Gorcunov
2018-06-07 20:57 ` Andy Lutomirski
2018-06-08 12:07 ` Cyrill Gorcunov
2018-06-07 20:12 ` Yu-cheng Yu
2018-06-07 20:17 ` Dave Hansen
2018-06-07 14:38 ` [PATCH 04/10] x86/cet: Handle thread " Yu-cheng Yu
2018-06-07 18:21 ` Andy Lutomirski
2018-06-07 19:47 ` Florian Weimer
2018-06-07 20:53 ` Andy Lutomirski
2018-06-08 14:53 ` Florian Weimer
2018-06-08 15:01 ` Andy Lutomirski
2018-06-08 15:50 ` Yu-cheng Yu
2018-06-07 14:38 ` [PATCH 05/10] x86/cet: ELF header parsing of Control Flow Enforcement Yu-cheng Yu
2018-06-07 18:38 ` Andy Lutomirski
2018-06-07 20:40 ` Yu-cheng Yu
2018-06-07 14:38 ` Yu-cheng Yu [this message]
2018-06-07 18:48 ` [PATCH 06/10] x86/cet: Add arch_prctl functions for shadow stack Andy Lutomirski
2018-06-07 20:30 ` Yu-cheng Yu
2018-06-07 21:01 ` Andy Lutomirski
2018-06-07 22:02 ` H.J. Lu
2018-06-07 23:01 ` Andy Lutomirski
2018-06-08 4:09 ` H.J. Lu
2018-06-08 4:38 ` Andy Lutomirski
2018-06-08 12:24 ` H.J. Lu
2018-06-08 14:57 ` Andy Lutomirski
2018-06-08 15:52 ` Cyrill Gorcunov
2018-06-08 4:22 ` H.J. Lu
2018-06-08 4:35 ` Andy Lutomirski
2018-06-08 12:17 ` H.J. Lu
2018-06-12 10:03 ` Thomas Gleixner
2018-06-12 11:43 ` H.J. Lu
2018-06-12 16:01 ` Andy Lutomirski
2018-06-12 16:05 ` H.J. Lu
2018-06-12 16:34 ` Andy Lutomirski
2018-06-12 16:51 ` H.J. Lu
2018-06-12 18:59 ` Thomas Gleixner
2018-06-12 19:34 ` H.J. Lu
2018-06-18 22:03 ` Andy Lutomirski
2018-06-19 0:52 ` Kees Cook
2018-06-19 6:40 ` Florian Weimer
2018-06-19 14:50 ` Andy Lutomirski
2018-06-19 16:44 ` Kees Cook
2018-06-19 16:59 ` Yu-cheng Yu
2018-06-19 17:07 ` Kees Cook
2018-06-19 17:20 ` Andy Lutomirski
2018-06-19 20:12 ` Kees Cook
2018-06-19 20:47 ` Andy Lutomirski
2018-06-19 22:38 ` Yu-cheng Yu
2018-06-20 0:50 ` Andy Lutomirski
2018-06-21 23:07 ` Yu-cheng Yu
2018-06-07 14:38 ` [PATCH 07/10] mm: Prevent mprotect from changing " Yu-cheng Yu
2018-06-07 14:38 ` [PATCH 08/10] mm: Prevent mremap of " Yu-cheng Yu
2018-06-07 18:48 ` Andy Lutomirski
2018-06-07 20:18 ` Yu-cheng Yu
2018-06-07 14:38 ` [PATCH 09/10] mm: Prevent madvise from changing " Yu-cheng Yu
2018-06-07 20:54 ` Andy Lutomirski
2018-06-07 21:09 ` Nadav Amit
2018-06-07 21:18 ` Yu-cheng Yu
2018-06-07 14:38 ` [PATCH 10/10] mm: Prevent munmap and remap_file_pages of " Yu-cheng Yu
2018-06-07 18:50 ` Andy Lutomirski
2018-06-07 20:15 ` Yu-cheng Yu
2018-06-12 10:56 ` [PATCH 00/10] Control Flow Enforcement - Part (3) Balbir Singh
2018-06-12 15:03 ` Yu-cheng Yu
2018-06-12 16:00 ` Andy Lutomirski
2018-06-12 16:21 ` Yu-cheng Yu
2018-06-12 16:31 ` Andy Lutomirski
2018-06-12 17:24 ` Yu-cheng Yu
2018-06-12 20:15 ` Yu-cheng Yu
2018-06-14 1:07 ` Balbir Singh
2018-06-14 14:56 ` Yu-cheng Yu
2018-06-17 3:16 ` Balbir Singh
2018-06-18 21:44 ` Andy Lutomirski
2018-06-19 8:52 ` Balbir Singh
2018-06-26 2:46 ` Jann Horn
2018-06-26 14:56 ` Yu-cheng Yu
2018-06-26 5:26 ` Andy Lutomirski
2018-06-26 14:56 ` Yu-cheng Yu
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20180607143807.3611-7-yu-cheng.yu@intel.com \
--to=yu-cheng.yu@intel.com \
--cc=arnd@arndb.de \
--cc=corbet@lwn.net \
--cc=dave.hansen@linux.intel.com \
--cc=hjl.tools@gmail.com \
--cc=hpa@zytor.com \
--cc=linux-arch@vger.kernel.org \
--cc=linux-doc@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=luto@amacapital.net \
--cc=mike.kravetz@oracle.com \
--cc=mingo@redhat.com \
--cc=oleg@redhat.com \
--cc=ravi.v.shankar@intel.com \
--cc=tglx@linutronix.de \
--cc=vedvyas.shanbhogue@intel.com \
--cc=x86@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).