If a page fault is triggered by a shadow stack access (e.g.
call/ret) or shadow stack management instructions (e.g.
wrussq), then bit[6] of the page fault error code is set.

In access_error(), we check if a shadow stack page fault
is within a shadow stack memory area.

Signed-off-by: Yu-cheng Yu <yu-cheng...@intel.com>
---
 arch/x86/include/asm/traps.h |  2 ++
 arch/x86/mm/fault.c          | 18 ++++++++++++++++++
 2 files changed, 20 insertions(+)

diff --git a/arch/x86/include/asm/traps.h b/arch/x86/include/asm/traps.h
index 5196050ff3d5..58ea2f5722e9 100644
--- a/arch/x86/include/asm/traps.h
+++ b/arch/x86/include/asm/traps.h
@@ -157,6 +157,7 @@ enum {
  *   bit 3 ==                          1: use of reserved bit detected
  *   bit 4 ==                          1: fault was an instruction fetch
  *   bit 5 ==                          1: protection keys block access
+ *   bit 6 ==                          1: shadow stack access fault
  */
 enum x86_pf_error_code {
        X86_PF_PROT     =               1 << 0,
@@ -165,5 +166,6 @@ enum x86_pf_error_code {
        X86_PF_RSVD     =               1 << 3,
        X86_PF_INSTR    =               1 << 4,
        X86_PF_PK       =               1 << 5,
+       X86_PF_SHSTK    =               1 << 6,
 };
 #endif /* _ASM_X86_TRAPS_H */
diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c
index 47bebfe6efa7..7c3877a982f4 100644
--- a/arch/x86/mm/fault.c
+++ b/arch/x86/mm/fault.c
@@ -1162,6 +1162,17 @@ access_error(unsigned long error_code, struct 
vm_area_struct *vma)
                                       (error_code & X86_PF_INSTR), foreign))
                return 1;
 
+       /*
+        * Verify X86_PF_SHSTK is within a shadow stack VMA.
+        * It is always an error if there is a shadow stack
+        * fault outside a shadow stack VMA.
+        */
+       if (error_code & X86_PF_SHSTK) {
+               if (!(vma->vm_flags & VM_SHSTK))
+                       return 1;
+               return 0;
+       }
+
        if (error_code & X86_PF_WRITE) {
                /* write, present and write, not present: */
                if (unlikely(!(vma->vm_flags & VM_WRITE)))
@@ -1300,6 +1311,13 @@ __do_page_fault(struct pt_regs *regs, unsigned long 
error_code,
 
        perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, address);
 
+       /*
+        * If the fault is caused by a shadow stack access,
+        * i.e. CALL/RET/SAVEPREVSSP/RSTORSSP, then set
+        * FAULT_FLAG_WRITE to effect copy-on-write.
+        */
+       if (error_code & X86_PF_SHSTK)
+               flags |= FAULT_FLAG_WRITE;
        if (error_code & X86_PF_WRITE)
                flags |= FAULT_FLAG_WRITE;
        if (error_code & X86_PF_INSTR)
-- 
2.17.1

Reply via email to