Add REGSET_CET64/REGSET_CET32 to get/set CET MSRs:

    IA32_U_CET (user-mode CET settings) and
    IA32_PL3_SSP (user-mode Shadow Stack)

Signed-off-by: Yu-cheng Yu <[email protected]>
---
 arch/x86/include/asm/fpu/regset.h |  7 ++---
 arch/x86/kernel/fpu/regset.c      | 44 +++++++++++++++++++++++++++++++
 arch/x86/kernel/ptrace.c          | 16 +++++++++++
 include/uapi/linux/elf.h          |  1 +
 4 files changed, 65 insertions(+), 3 deletions(-)

diff --git a/arch/x86/include/asm/fpu/regset.h 
b/arch/x86/include/asm/fpu/regset.h
index 4f928d6a367b..8622184d87f5 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_get2_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 c413756ba89f..8860d57eed35 100644
--- a/arch/x86/kernel/fpu/regset.c
+++ b/arch/x86/kernel/fpu/regset.c
@@ -149,6 +149,50 @@ 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_size || target->thread.cet.ibt_enabled)
+               return regset->n;
+#endif
+       return 0;
+}
+
+int cetregs_get(struct task_struct *target, const struct user_regset *regset,
+               struct membuf to)
+{
+       struct fpu *fpu = &target->thread.fpu;
+       struct cet_user_state *cetregs;
+
+       if (!boot_cpu_has(X86_FEATURE_SHSTK))
+               return -ENODEV;
+
+       fpu__prepare_read(fpu);
+       cetregs = get_xsave_addr(&fpu->state.xsave, XFEATURE_CET_USER);
+       if (!cetregs)
+               return -EFAULT;
+
+       return membuf_write(&to, cetregs, sizeof(struct cet_user_state));
+}
+
+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;
+
+       fpu__prepare_write(fpu);
+       cetregs = get_xsave_addr(&fpu->state.xsave, XFEATURE_CET_USER);
+       if (!cetregs)
+               return -EFAULT;
+
+       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 5679aa3fdcb8..ea54317f087e 100644
--- a/arch/x86/kernel/ptrace.c
+++ b/arch/x86/kernel/ptrace.c
@@ -52,7 +52,9 @@ enum x86_regset {
        REGSET_IOPERM64 = REGSET_XFP,
        REGSET_XSTATE,
        REGSET_TLS,
+       REGSET_CET64 = REGSET_TLS,
        REGSET_IOPERM32,
+       REGSET_CET32,
 };
 
 struct pt_regs_offset {
@@ -1229,6 +1231,13 @@ static struct user_regset x86_64_regsets[] 
__ro_after_init = {
                .size = sizeof(long), .align = sizeof(long),
                .active = ioperm_active, .regset_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, .regset_get = cetregs_get,
+               .set = cetregs_set
+       },
 };
 
 static const struct user_regset_view user_x86_64_view = {
@@ -1284,6 +1293,13 @@ static struct user_regset x86_32_regsets[] 
__ro_after_init = {
                .size = sizeof(u32), .align = sizeof(u32),
                .active = ioperm_active, .regset_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, .regset_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 ca5875f384f6..d2a895369bcc 100644
--- a/include/uapi/linux/elf.h
+++ b/include/uapi/linux/elf.h
@@ -402,6 +402,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.21.0

Reply via email to