lkml.org 
[lkml]   [2019]   [Aug]   [13]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH v8 26/27] x86/cet/shstk: Add arch_prctl functions for Shadow Stack
    Date
    arch_prctl(ARCH_X86_CET_STATUS, unsigned long *addr)
    Return CET feature status.

    The parameter 'addr' is a pointer to a user buffer.
    On returning to the caller, the kernel fills the following
    information:

    *addr = SHSTK/IBT status
    *(addr + 1) = SHSTK base address
    *(addr + 2) = SHSTK size

    arch_prctl(ARCH_X86_CET_DISABLE, unsigned long features)
    Disable CET features specified in 'features'. Return
    -EPERM if CET is locked.

    arch_prctl(ARCH_X86_CET_LOCK)
    Lock in CET feature.

    arch_prctl(ARCH_X86_CET_ALLOC_SHSTK, unsigned long *addr)
    Allocate a new SHSTK.

    The parameter 'addr' is a pointer to a user buffer and indicates
    the desired SHSTK size to allocate. On returning to the caller
    the buffer contains the address of the new SHSTK.

    There is no CET enabling arch_prctl function. By design, CET is
    enabled automatically if the binary and the system can support it.

    The parameters passed are always unsigned 64-bit. When an ia32
    application passing pointers, it should only use the lower 32 bits.

    Signed-off-by: Yu-cheng Yu <yu-cheng.yu@intel.com>
    ---
    arch/x86/include/asm/cet.h | 5 ++
    arch/x86/include/uapi/asm/prctl.h | 5 ++
    arch/x86/kernel/Makefile | 2 +-
    arch/x86/kernel/cet.c | 29 +++++++++++
    arch/x86/kernel/cet_prctl.c | 85 +++++++++++++++++++++++++++++++
    arch/x86/kernel/process.c | 4 +-
    6 files changed, 127 insertions(+), 3 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 52c506a68848..2df357dffd24 100644
    --- a/arch/x86/include/asm/cet.h
    +++ b/arch/x86/include/asm/cet.h
    @@ -14,19 +14,24 @@ struct sc_ext;
    struct cet_status {
    unsigned long shstk_base;
    unsigned long shstk_size;
    + unsigned int locked:1;
    unsigned int shstk_enabled:1;
    };

    #ifdef CONFIG_X86_INTEL_CET
    +int prctl_cet(int option, unsigned long arg2);
    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(bool ia32, struct sc_ext *sc);
    int cet_setup_signal(bool ia32, unsigned long rstor, struct sc_ext *sc);
    #else
    +static inline int prctl_cet(int option, unsigned long arg2) { return -EINVAL; }
    static inline int cet_setup_shstk(void) { return -EINVAL; }
    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(bool ia32, struct sc_ext *sc) { return -EINVAL; }
    diff --git a/arch/x86/include/uapi/asm/prctl.h b/arch/x86/include/uapi/asm/prctl.h
    index 5a6aac9fa41f..d962f0ec9ccf 100644
    --- a/arch/x86/include/uapi/asm/prctl.h
    +++ b/arch/x86/include/uapi/asm/prctl.h
    @@ -14,4 +14,9 @@
    #define ARCH_MAP_VDSO_32 0x2002
    #define ARCH_MAP_VDSO_64 0x2003

    +#define ARCH_X86_CET_STATUS 0x3001
    +#define ARCH_X86_CET_DISABLE 0x3002
    +#define ARCH_X86_CET_LOCK 0x3003
    +#define ARCH_X86_CET_ALLOC_SHSTK 0x3004
    +
    #endif /* _ASM_X86_PRCTL_H */
    diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
    index c7d918a87cac..311829335521 100644
    --- a/arch/x86/kernel/Makefile
    +++ b/arch/x86/kernel/Makefile
    @@ -140,7 +140,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

    ###
    # 64 bit specific files
    diff --git a/arch/x86/kernel/cet.c b/arch/x86/kernel/cet.c
    index e876150178ca..e4e20d6ab07b 100644
    --- a/arch/x86/kernel/cet.c
    +++ b/arch/x86/kernel/cet.c
    @@ -127,6 +127,35 @@ static int create_rstor_token(bool ia32, unsigned long ssp,
    return 0;
    }

    +int cet_alloc_shstk(unsigned long *arg)
    +{
    + unsigned long len = *arg;
    + unsigned long addr;
    + unsigned long token;
    + unsigned long ssp;
    +
    + addr = do_mmap_locked(NULL, 0, len, PROT_READ,
    + MAP_ANONYMOUS | MAP_PRIVATE, VM_SHSTK, NULL);
    + if (addr >= TASK_SIZE_MAX)
    + return -ENOMEM;
    +
    + /* Restore token is 8 bytes and aligned to 8 bytes */
    + ssp = addr + len;
    + token = ssp;
    +
    + if (!in_ia32_syscall())
    + token |= TOKEN_MODE_64;
    + ssp -= 8;
    +
    + if (write_user_shstk_64(ssp, token)) {
    + vm_munmap(addr, len);
    + return -EINVAL;
    + }
    +
    + *arg = addr;
    + return 0;
    +}
    +
    int cet_setup_shstk(void)
    {
    unsigned long addr, size;
    diff --git a/arch/x86/kernel/cet_prctl.c b/arch/x86/kernel/cet_prctl.c
    new file mode 100644
    index 000000000000..9c9d4262b07e
    --- /dev/null
    +++ b/arch/x86/kernel/cet_prctl.c
    @@ -0,0 +1,85 @@
    +/* SPDX-License-Identifier: GPL-2.0 */
    +
    +#include <linux/errno.h>
    +#include <linux/uaccess.h>
    +#include <linux/prctl.h>
    +#include <linux/compat.h>
    +#include <linux/mman.h>
    +#include <linux/elfcore.h>
    +#include <asm/processor.h>
    +#include <asm/prctl.h>
    +#include <asm/cet.h>
    +
    +/* See Documentation/x86/intel_cet.rst. */
    +
    +static int handle_get_status(unsigned long arg2)
    +{
    + unsigned int features = 0;
    + unsigned long shstk_base, shstk_size;
    + unsigned long buf[3];
    +
    + if (current->thread.cet.shstk_enabled)
    + features |= GNU_PROPERTY_X86_FEATURE_1_SHSTK;
    +
    + shstk_base = current->thread.cet.shstk_base;
    + shstk_size = current->thread.cet.shstk_size;
    +
    + buf[0] = (unsigned long)features;
    + buf[1] = shstk_base;
    + buf[2] = shstk_size;
    + return copy_to_user((unsigned long __user *)arg2, buf,
    + sizeof(buf));
    +}
    +
    +static int handle_alloc_shstk(unsigned long arg2)
    +{
    + int err = 0;
    + unsigned long arg;
    + unsigned long addr = 0;
    + unsigned long size = 0;
    +
    + if (get_user(arg, (unsigned long __user *)arg2))
    + return -EFAULT;
    +
    + size = arg;
    + err = cet_alloc_shstk(&arg);
    + if (err)
    + return err;
    +
    + addr = arg;
    + if (put_user(addr, (unsigned long __user *)arg2)) {
    + vm_munmap(addr, size);
    + return -EFAULT;
    + }
    +
    + return 0;
    +}
    +
    +int prctl_cet(int option, unsigned long arg2)
    +{
    + if (!cpu_x86_cet_enabled())
    + return -EINVAL;
    +
    + switch (option) {
    + case ARCH_X86_CET_STATUS:
    + return handle_get_status(arg2);
    +
    + case ARCH_X86_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_X86_CET_LOCK:
    + current->thread.cet.locked = 1;
    + return 0;
    +
    + case ARCH_X86_CET_ALLOC_SHSTK:
    + return handle_alloc_shstk(arg2);
    +
    + default:
    + return -EINVAL;
    + }
    +}
    diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c
    index 58b1c52b38b5..e0090f2790df 100644
    --- a/arch/x86/kernel/process.c
    +++ b/arch/x86/kernel/process.c
    @@ -873,7 +873,7 @@ 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);
    + default:
    + return prctl_cet(option, cpuid_enabled);
    }
    -
    - return -EINVAL;
    }
    --
    2.17.1
    \
     
     \ /
      Last update: 2019-08-13 23:03    [W:4.221 / U:0.204 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site