kernel - Implement support for SMAP and SMEP security
authorMatthew Dillon <dillon@apollo.backplane.com>
Fri, 17 May 2019 00:14:58 +0000 (17:14 -0700)
committerMatthew Dillon <dillon@apollo.backplane.com>
Fri, 17 May 2019 00:14:58 +0000 (17:14 -0700)
* Implement support for SMAP security.  This prevents accidental
  accesses to user address space from the kernel.  When available,
  we wrap intentional user-space accesses from the kernel with
  the 'stac' and 'clac' instructions.

  We use a NOP replacement policy to implement the feature.  The wrapper
  is initially a 'nop %eax' (3-byte NOP), and is replaced by 'stac' and
  'clac' via a .section iteration when the feature is supported.

* Implement support for SMEP security.  This prevents accidental
  execution of user code from the kernel and simply requires
  turning the bit on in CR4.

* Reports support in dmesg via the 'CPU Special Features Installed:'
  line.

sys/cpu/x86_64/include/asmacros.h
sys/cpu/x86_64/include/specialreg.h
sys/platform/pc64/x86_64/identcpu.c
sys/platform/pc64/x86_64/initcpu.c
sys/platform/pc64/x86_64/machdep.c
sys/platform/pc64/x86_64/pmap.c
sys/platform/pc64/x86_64/support.s

index 00c65f5..c1c0cee 100644 (file)
        movq %gs:PC_PRVSPACE, reg ;                             \
        addq $PC_ ## member, reg
 
+/*
+ * This adds a code placemarker (the 3-byte NOP) and references
+ * it from a section, allowing it to be replaced with a STAC or CLAC
+ * instruction (also 3-byte instructions) when the system supports
+ * SMAP.
+ */
+#define SMAP_OPEN                                              \
+       .globl  __start_set_smap_open ;                         \
+       .globl  __stop_set_smap_open ;                          \
+60:    nop     %eax ;                                          \
+       .section set_smap_open,"aw" ;                           \
+       .quad   60b ;                                           \
+       .previous                                               \
+
+#define SMAP_CLOSE                                             \
+       .globl  __start_set_smap_close ;                        \
+       .globl  __stop_set_smap_close ;                         \
+60:    nop     %eax ;                                          \
+       .section set_smap_close,"aw" ;                          \
+       .quad   60b ;                                           \
+       .previous                                               \
+
 #endif /* LOCORE */
 
 #endif /* !_CPU_ASMACROS_H_ */
index 5f03bbf..656c2ce 100644 (file)
 #define        CR4_XMM         0x00000400      /* Enable SIMD/MMX2 to use except 16 */
 #define        CR4_VMXE        0x00002000      /* Enables VMX - Intel specific */
 #define        CR4_XSAVE       0x00040000      /* Enable XSave (for AVX Instructions)*/
+#define        CR4_SMEP        0x00100000      /* Supervisor-Mode Execution Prevent */
+#define        CR4_SMAP        0x00200000      /* Supervisor-Mode Access Prevent */
+#define        CR4_PKE         0x00400000      /* Protection Keys Enable */
+
 
 /*
  * Bits in x86_64 special registers.  EFER is 64 bits wide.
index dae28f0..11f9dbb 100644 (file)
@@ -474,13 +474,19 @@ printcpuinfo(void)
        if (*cpu_vendor || cpu_id)
                kprintf("\n");
 
-       if (!bootverbose)
-               return;
-
-       if (cpu_vendor_id == CPU_VENDOR_AMD)
-               print_AMD_info();
+       if (cpu_stdext_feature & (CPUID_STDEXT_SMAP | CPUID_STDEXT_SMEP)) {
+               kprintf("CPU Special Features Installed:");
+               if (cpu_stdext_feature & CPUID_STDEXT_SMAP)
+                       kprintf(" SMAP");
+               if (cpu_stdext_feature & CPUID_STDEXT_SMEP)
+                       kprintf(" SMEP");
+               kprintf("\n");
+       }
 
-       kprintf("npx mask: 0x%8.8x\n", npx_mxcsr_mask);
+       if (bootverbose) {
+               if (cpu_vendor_id == CPU_VENDOR_AMD)
+                       print_AMD_info();
+       }
 }
 
 void
index 25b60bd..fd20657 100644 (file)
@@ -207,7 +207,9 @@ initializecpu(int cpu)
 {
        uint64_t msr;
 
-       /*Check for FXSR and SSE support and enable if available.*/
+       /*
+        * Check for FXSR and SSE support and enable if available
+        */
        if ((cpu_feature & CPUID_XMM) && (cpu_feature & CPUID_FXSR)) {
                load_cr4(rcr4() | CR4_FXSR | CR4_XMM);
                cpu_fxsr = hw_instruction_sse = 1;
index 7fea86a..0e62f23 100644 (file)
@@ -316,6 +316,8 @@ vm_offset_t clean_sva, clean_eva;
 static vm_offset_t pager_sva, pager_eva;
 static struct trapframe proc0_tf;
 
+static void cpu_implement_smap(void);
+
 static void
 cpu_startup(void *dummy)
 {
@@ -330,6 +332,9 @@ cpu_startup(void *dummy)
        startrtclock();
        printcpuinfo();
        panicifcpuunsupported();
+       if (cpu_stdext_feature & CPUID_STDEXT_SMAP)
+               cpu_implement_smap();
+
        kprintf("real memory  = %ju (%ju MB)\n",
                (intmax_t)Realmem,
                (intmax_t)Realmem / 1024 / 1024);
@@ -3491,3 +3496,25 @@ pcpu_timer_always(struct intrframe *frame)
 #endif
 #endif
 }
+
+SET_DECLARE(smap_open, char);
+SET_DECLARE(smap_close, char);
+
+static void
+cpu_implement_smap(void)
+{
+       char **scan;
+
+       for (scan = SET_BEGIN(smap_open);
+            scan < SET_LIMIT(smap_open); ++scan) {
+               (*scan)[0] = 0x0F;
+               (*scan)[1] = 0x01;
+               (*scan)[2] = 0xCB;
+       }
+       for (scan = SET_BEGIN(smap_close);
+            scan < SET_LIMIT(smap_close); ++scan) {
+               (*scan)[0] = 0x0F;
+               (*scan)[1] = 0x01;
+               (*scan)[2] = 0xCA;
+       }
+}
index f7e1225..12bf0c3 100644 (file)
@@ -1115,6 +1115,17 @@ pmap_bootstrap(vm_paddr_t *firstaddr)
         */
        x86_64_protection_init();
 
+       /*
+        * Check for SMAP support and enable if available.  Must be done
+        * after cr3 is loaded.
+        */
+       if (cpu_stdext_feature & CPUID_STDEXT_SMAP) {
+               load_cr4(rcr4() | CR4_SMAP);
+       }
+       if (cpu_stdext_feature & CPUID_STDEXT_SMEP) {
+               load_cr4(rcr4() | CR4_SMEP);
+       }
+
        /*
         * The kernel's pmap is statically allocated so we don't have to use
         * pmap_create, which is unlikely to work correctly at this part of
index 13958c0..6434c13 100644 (file)
@@ -299,16 +299,18 @@ END(fillw)
  * Read kernel or user memory with fault protection.
  */
 ENTRY(kreadmem64)
+       SMAP_OPEN
        movq    PCPU(curthread),%rcx
        movq    TD_PCB(%rcx), %rcx
        movq    $kreadmem64fault,PCB_ONFAULT(%rcx)
        movq    %rsp,PCB_ONFAULT_SP(%rcx)
-
        movq    (%rdi),%rax
        movq    $0,PCB_ONFAULT(%rcx)
+       SMAP_CLOSE
        ret
 
 kreadmem64fault:
+       SMAP_CLOSE
        movq    PCPU(curthread),%rcx
        xorl    %eax,%eax
        movq    TD_PCB(%rcx),%rcx
@@ -322,6 +324,7 @@ END(kreadmem64)
  *         %rdi,        %rsi,    %rdx
  */
 ENTRY(std_copyout)
+       SMAP_OPEN
        movq    PCPU(curthread),%rax
        movq    TD_PCB(%rax), %rax
        movq    $copyout_fault,PCB_ONFAULT(%rax)
@@ -367,6 +370,7 @@ ENTRY(std_copyout)
        movsb
 
 done_copyout:
+       SMAP_CLOSE
        xorl    %eax,%eax
        movq    PCPU(curthread),%rdx
        movq    TD_PCB(%rdx), %rdx
@@ -375,6 +379,7 @@ done_copyout:
 
        ALIGN_TEXT
 copyout_fault:
+       SMAP_CLOSE
        movq    PCPU(curthread),%rdx
        movq    TD_PCB(%rdx), %rdx
        movq    $0,PCB_ONFAULT(%rdx)
@@ -387,6 +392,7 @@ END(std_copyout)
  *        %rdi,      %rsi,      %rdx
  */
 ENTRY(std_copyin)
+       SMAP_OPEN
        movq    PCPU(curthread),%rax
        movq    TD_PCB(%rax), %rax
        movq    $copyin_fault,PCB_ONFAULT(%rax)
@@ -417,6 +423,7 @@ ENTRY(std_copyin)
        movsb
 
 done_copyin:
+       SMAP_CLOSE
        xorl    %eax,%eax
        movq    PCPU(curthread),%rdx
        movq    TD_PCB(%rdx), %rdx
@@ -425,6 +432,7 @@ done_copyin:
 
        ALIGN_TEXT
 copyin_fault:
+       SMAP_CLOSE
        movq    PCPU(curthread),%rdx
        movq    TD_PCB(%rdx), %rdx
        movq    $0,PCB_ONFAULT(%rdx)
@@ -437,6 +445,7 @@ END(std_copyin)
  *          dst = %rdi, old = %rsi, new = %rdx
  */
 ENTRY(casu32)
+       SMAP_OPEN
        movq    PCPU(curthread),%rcx
        movq    TD_PCB(%rcx), %rcx
        movq    $fusufault,PCB_ONFAULT(%rcx)
@@ -459,6 +468,7 @@ ENTRY(casu32)
        movq    PCPU(curthread),%rcx
        movq    TD_PCB(%rcx), %rcx
        movq    $0,PCB_ONFAULT(%rcx)
+       SMAP_CLOSE
        ret
 END(casu32)
 
@@ -466,6 +476,7 @@ END(casu32)
  * swapu32 - Swap int in user space.  ptr = %rdi, val = %rsi
  */
 ENTRY(std_swapu32)
+       SMAP_OPEN
        movq    PCPU(curthread),%rcx
        movq    TD_PCB(%rcx), %rcx
        movq    $fusufault,PCB_ONFAULT(%rcx)
@@ -487,10 +498,12 @@ ENTRY(std_swapu32)
        movq    PCPU(curthread),%rcx
        movq    TD_PCB(%rcx), %rcx
        movq    $0,PCB_ONFAULT(%rcx)
+       SMAP_CLOSE
        ret
 END(std_swapu32)
 
 ENTRY(std_fuwordadd32)
+       SMAP_OPEN
        movq    PCPU(curthread),%rcx
        movq    TD_PCB(%rcx), %rcx
        movq    $fusufault,PCB_ONFAULT(%rcx)
@@ -508,10 +521,10 @@ ENTRY(std_fuwordadd32)
         * value we expected (old) from before the store, otherwise it will
         * be the current value.
         */
-
        movq    PCPU(curthread),%rcx
        movq    TD_PCB(%rcx), %rcx
        movq    $0,PCB_ONFAULT(%rcx)
+       SMAP_CLOSE
        ret
 END(std_fuwordadd32)
 
@@ -520,6 +533,7 @@ END(std_fuwordadd32)
  *          dst = %rdi, old = %rsi, new = %rdx
  */
 ENTRY(casu64)
+       SMAP_OPEN
        movq    PCPU(curthread),%rcx
        movq    TD_PCB(%rcx), %rcx
        movq    $fusufault,PCB_ONFAULT(%rcx)
@@ -542,6 +556,7 @@ ENTRY(casu64)
        movq    PCPU(curthread),%rcx
        movq    TD_PCB(%rcx), %rcx
        movq    $0,PCB_ONFAULT(%rcx)
+       SMAP_CLOSE
        ret
 END(casu64)
 
@@ -549,6 +564,7 @@ END(casu64)
  * swapu64 - Swap long in user space.  ptr = %rdi, val = %rsi
  */
 ENTRY(std_swapu64)
+       SMAP_OPEN
        movq    PCPU(curthread),%rcx
        movq    TD_PCB(%rcx), %rcx
        movq    $fusufault,PCB_ONFAULT(%rcx)
@@ -570,10 +586,12 @@ ENTRY(std_swapu64)
        movq    PCPU(curthread),%rcx
        movq    TD_PCB(%rcx), %rcx
        movq    $0,PCB_ONFAULT(%rcx)
+       SMAP_CLOSE
        ret
 END(std_swapu64)
 
 ENTRY(std_fuwordadd64)
+       SMAP_OPEN
        movq    PCPU(curthread),%rcx
        movq    TD_PCB(%rcx), %rcx
        movq    $fusufault,PCB_ONFAULT(%rcx)
@@ -595,6 +613,7 @@ ENTRY(std_fuwordadd64)
        movq    PCPU(curthread),%rcx
        movq    TD_PCB(%rcx), %rcx
        movq    $0,PCB_ONFAULT(%rcx)
+       SMAP_CLOSE
        ret
 END(std_fuwordadd64)
 
@@ -605,6 +624,7 @@ END(std_fuwordadd64)
  */
 
 ENTRY(std_fuword64)
+       SMAP_OPEN
        movq    PCPU(curthread),%rcx
        movq    TD_PCB(%rcx), %rcx
        movq    $fusufault,PCB_ONFAULT(%rcx)
@@ -616,10 +636,12 @@ ENTRY(std_fuword64)
 
        movq    (%rdi),%rax
        movq    $0,PCB_ONFAULT(%rcx)
+       SMAP_CLOSE
        ret
 END(std_fuword64)
 
 ENTRY(std_fuword32)
+       SMAP_OPEN
        movq    PCPU(curthread),%rcx
        movq    TD_PCB(%rcx), %rcx
        movq    $fusufault,PCB_ONFAULT(%rcx)
@@ -631,10 +653,12 @@ ENTRY(std_fuword32)
 
        movl    (%rdi),%eax
        movq    $0,PCB_ONFAULT(%rcx)
+       SMAP_CLOSE
        ret
 END(std_fuword32)
 
 ENTRY(std_fubyte)
+       SMAP_OPEN
        movq    PCPU(curthread),%rcx
        movq    TD_PCB(%rcx), %rcx
        movq    $fusufault,PCB_ONFAULT(%rcx)
@@ -646,6 +670,7 @@ ENTRY(std_fubyte)
 
        movzbl  (%rdi),%eax
        movq    $0,PCB_ONFAULT(%rcx)
+       SMAP_CLOSE
        ret
 
        ALIGN_TEXT
@@ -655,6 +680,7 @@ fusufault:
        movq    TD_PCB(%rcx), %rcx
        movq    %rax,PCB_ONFAULT(%rcx)
        decq    %rax
+       SMAP_CLOSE
        ret
 END(std_fubyte)
 
@@ -667,6 +693,7 @@ END(std_fubyte)
  * Write a long
  */
 ENTRY(std_suword64)
+       SMAP_OPEN
        movq    PCPU(curthread),%rcx
        movq    TD_PCB(%rcx), %rcx
        movq    $fusufault,PCB_ONFAULT(%rcx)
@@ -681,6 +708,7 @@ ENTRY(std_suword64)
        movq    PCPU(curthread),%rcx
        movq    TD_PCB(%rcx), %rcx
        movq    %rax,PCB_ONFAULT(%rcx)
+       SMAP_CLOSE
        ret
 END(std_suword64)
 
@@ -688,6 +716,7 @@ END(std_suword64)
  * Write an int
  */
 ENTRY(std_suword32)
+       SMAP_OPEN
        movq    PCPU(curthread),%rcx
        movq    TD_PCB(%rcx), %rcx
        movq    $fusufault,PCB_ONFAULT(%rcx)
@@ -702,10 +731,12 @@ ENTRY(std_suword32)
        movq    PCPU(curthread),%rcx
        movq    TD_PCB(%rcx), %rcx
        movq    %rax,PCB_ONFAULT(%rcx)
+       SMAP_CLOSE
        ret
 END(std_suword32)
 
 ENTRY(std_subyte)
+       SMAP_OPEN
        movq    PCPU(curthread),%rcx
        movq    TD_PCB(%rcx), %rcx
        movq    $fusufault,PCB_ONFAULT(%rcx)
@@ -721,6 +752,7 @@ ENTRY(std_subyte)
        movq    PCPU(curthread),%rcx            /* restore trashed register */
        movq    TD_PCB(%rcx), %rcx
        movq    %rax,PCB_ONFAULT(%rcx)
+       SMAP_CLOSE
        ret
 END(std_subyte)
 
@@ -734,6 +766,7 @@ END(std_subyte)
  *     return the actual length in *lencopied.
  */
 ENTRY(std_copyinstr)
+       SMAP_OPEN
        movq    %rdx,%r8                        /* %r8 = maxlen */
        movq    %rcx,%r9                        /* %r9 = *len */
        movq    PCPU(curthread),%rcx
@@ -783,6 +816,7 @@ cpystrflt:
        movq    $EFAULT,%rax
 
 cpystrflt_x:
+       SMAP_CLOSE
        /* set *lencopied and return %eax */
        movq    PCPU(curthread),%rcx
        movq    TD_PCB(%rcx), %rcx
@@ -802,7 +836,6 @@ END(std_copyinstr)
  */
 ENTRY(copystr)
        movq    %rdx,%r8                        /* %r8 = maxlen */
-
        incq    %rdx
 1:
        decq    %rdx
@@ -824,7 +857,6 @@ ENTRY(copystr)
        movq    $ENAMETOOLONG,%rax
 
 6:
-
        testq   %rcx,%rcx
        jz      7f
        /* set *lencopied and return %rax */