Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/arch Add support for Privileged Access Never (ARMv8.1-PAN).



details:   https://anonhg.NetBSD.org/src/rev/a9ff7dfc3d34
branches:  trunk
changeset: 936702:a9ff7dfc3d34
user:      maxv <maxv%NetBSD.org@localhost>
date:      Sun Aug 02 06:58:16 2020 +0000

description:
Add support for Privileged Access Never (ARMv8.1-PAN).

PAN provides the same functionality as SMAP on x86: it forbids kernel
access to userland pages when PSTATE.PAN=1, and allows such accesses when
PSTATE.PAN=0.

We clear SCTLR_SPAN, to guarantee that PAN=1 each time the kernel is
entered. We catch PAN faults and panic right away without further
processing. In copyin, copyout, etc, we temporarily authorize access to
userland pages.

PAN is a very useful exploit mitigation. Reviewed by ryo@, thanks. Tested
on Qemu. Enabled by default.

diffstat:

 sys/arch/aarch64/aarch64/aarch64_machdep.c |  12 ++++++++-
 sys/arch/aarch64/aarch64/copyinout.S       |  26 ++++++++++++++++++++-
 sys/arch/aarch64/aarch64/cpufunc.c         |  35 ++++++++++++++++++++++++++++-
 sys/arch/aarch64/aarch64/db_interface.c    |  10 ++++++-
 sys/arch/aarch64/aarch64/fault.c           |  20 +++++++++++++++-
 sys/arch/aarch64/aarch64/fusu.S            |  27 +++++++++++++++++++++-
 sys/arch/aarch64/aarch64/locore.S          |  12 ++++++++-
 sys/arch/aarch64/aarch64/trap.c            |   9 ++++++-
 sys/arch/aarch64/include/armreg.h          |   6 ++++-
 sys/arch/aarch64/include/asm.h             |  10 ++++++--
 sys/arch/aarch64/include/cpufunc.h         |   4 ++-
 sys/arch/arm/conf/files.arm                |   3 +-
 sys/arch/evbarm/conf/GENERIC64             |   5 +++-
 13 files changed, 156 insertions(+), 23 deletions(-)

diffs (truncated from 501 to 300 lines):

diff -r a497a50cacf9 -r a9ff7dfc3d34 sys/arch/aarch64/aarch64/aarch64_machdep.c
--- a/sys/arch/aarch64/aarch64/aarch64_machdep.c        Sun Aug 02 06:51:47 2020 +0000
+++ b/sys/arch/aarch64/aarch64/aarch64_machdep.c        Sun Aug 02 06:58:16 2020 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: aarch64_machdep.c,v 1.45 2020/07/16 11:36:35 skrll Exp $ */
+/* $NetBSD: aarch64_machdep.c,v 1.46 2020/08/02 06:58:16 maxv Exp $ */
 
 /*-
  * Copyright (c) 2014 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(1, "$NetBSD: aarch64_machdep.c,v 1.45 2020/07/16 11:36:35 skrll Exp $");
+__KERNEL_RCSID(1, "$NetBSD: aarch64_machdep.c,v 1.46 2020/08/02 06:58:16 maxv Exp $");
 
 #include "opt_arm_debug.h"
 #include "opt_cpuoptions.h"
@@ -480,6 +480,14 @@
 
        sysctl_createv(clog, 0, NULL, NULL,
            CTLFLAG_PERMANENT,
+           CTLTYPE_INT, "pan",
+           SYSCTL_DESCR("Whether Privileged Access Never is enabled"),
+           NULL, 0,
+           &aarch64_pan_enabled, 0,
+           CTL_MACHDEP, CTL_CREATE, CTL_EOL);
+
+       sysctl_createv(clog, 0, NULL, NULL,
+           CTLFLAG_PERMANENT,
            CTLTYPE_INT, "pac",
            SYSCTL_DESCR("Whether Pointer Authentication is enabled"),
            NULL, 0,
diff -r a497a50cacf9 -r a9ff7dfc3d34 sys/arch/aarch64/aarch64/copyinout.S
--- a/sys/arch/aarch64/aarch64/copyinout.S      Sun Aug 02 06:51:47 2020 +0000
+++ b/sys/arch/aarch64/aarch64/copyinout.S      Sun Aug 02 06:58:16 2020 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: copyinout.S,v 1.10 2020/06/30 16:20:00 maxv Exp $ */
+/* $NetBSD: copyinout.S,v 1.11 2020/08/02 06:58:16 maxv Exp $ */
 
 /*-
  * Copyright (c) 2014 The NetBSD Foundation, Inc.
@@ -33,7 +33,27 @@
 #include <aarch64/asm.h>
 #include "assym.h"
 
-RCSID("$NetBSD: copyinout.S,v 1.10 2020/06/30 16:20:00 maxv Exp $");
+RCSID("$NetBSD: copyinout.S,v 1.11 2020/08/02 06:58:16 maxv Exp $");
+
+#ifdef ARMV81_PAN
+#define PAN_ENABLE     \
+       adrl    x9, _C_LABEL(aarch64_pan_enabled)       ; \
+       ldr     w9, [x9]                                ; \
+       cbz     w9, 666f                                ; \
+       msr     pan, #1                                 ; \
+666:
+#define PAN_DISABLE    \
+       adrl    x9, _C_LABEL(aarch64_pan_enabled)       ; \
+       ldr     w9, [x9]                                ; \
+       cbz     w9, 666f                                ; \
+       msr     pan, #0                                 ; \
+666:
+#else
+#define PAN_ENABLE     /* nothing */
+#define PAN_DISABLE    /* nothing */
+#endif
+
+       ARMV8_DEFINE_OPTIONS
 
        .macro enter_cpu_onfault
        stp     fp, lr, [sp, #-16]!     /* save fp, lr */
@@ -55,6 +75,7 @@
        mov     x0, x19                 /* x0 = x19 = arg0 */
        mov     x1, x20                 /* x1 = x20 = arg1 */
 
+       PAN_DISABLE                     /* disable PAN */
        .endm
 
        .macro exit_cpu_onfault
@@ -63,6 +84,7 @@
        ldr     x0, [x0, #CI_CURLWP]            /* x0 = curlwp */
        str     xzr, [x0, #L_MD_ONFAULT]        /* lwp->l_md_onfault = NULL */
 9:
+       PAN_ENABLE                              /* enable PAN */
        add     sp, sp, #FB_T_SIZE              /* pop stack */
        ldp     x19, x20, [sp], #16             /* restore x19, x20 */
        ldp     fp, lr, [sp], #16               /* restore fp, lr */
diff -r a497a50cacf9 -r a9ff7dfc3d34 sys/arch/aarch64/aarch64/cpufunc.c
--- a/sys/arch/aarch64/aarch64/cpufunc.c        Sun Aug 02 06:51:47 2020 +0000
+++ b/sys/arch/aarch64/aarch64/cpufunc.c        Sun Aug 02 06:58:16 2020 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: cpufunc.c,v 1.23 2020/07/04 04:59:36 rin Exp $ */
+/*     $NetBSD: cpufunc.c,v 1.24 2020/08/02 06:58:16 maxv Exp $        */
 
 /*
  * Copyright (c) 2017 Ryo Shimizu <ryo%nerv.org@localhost>
@@ -30,7 +30,7 @@
 #include "opt_multiprocessor.h"
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: cpufunc.c,v 1.23 2020/07/04 04:59:36 rin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: cpufunc.c,v 1.24 2020/08/02 06:58:16 maxv Exp $");
 
 #include <sys/param.h>
 #include <sys/types.h>
@@ -50,6 +50,7 @@
 u_int aarch64_cache_vindexsize;
 u_int aarch64_cache_prefer_mask;
 
+int aarch64_pan_enabled __read_mostly;
 int aarch64_pac_enabled __read_mostly;
 
 /* cache info per cluster. the same cluster has the same cache configuration? */
@@ -474,6 +475,36 @@
        return 0;
 }
 
+void
+aarch64_pan_init(int primary)
+{
+#ifdef ARMV81_PAN
+       uint64_t reg, sctlr;
+
+       /* CPU0 does the detection. */
+       if (primary) {
+               reg = reg_id_aa64mmfr1_el1_read();
+               if (__SHIFTOUT(reg, ID_AA64MMFR1_EL1_PAN) !=
+                   ID_AA64MMFR1_EL1_PAN_NONE)
+                       aarch64_pan_enabled = 1;
+       }
+
+       if (!aarch64_pan_enabled)
+               return;
+
+       /*
+        * On an exception to EL1, have the CPU set the PAN bit automatically.
+        * This ensures PAN is enabled each time the kernel is entered.
+        */
+       sctlr = reg_sctlr_el1_read();
+       sctlr &= ~SCTLR_SPAN;
+       reg_sctlr_el1_write(sctlr);
+
+       /* Set the PAN bit right now. */
+       reg_pan_write(1);
+#endif
+}
+
 /*
  * In order to avoid inconsistencies with pointer authentication
  * in this function itself, the caller must enable PAC according
diff -r a497a50cacf9 -r a9ff7dfc3d34 sys/arch/aarch64/aarch64/db_interface.c
--- a/sys/arch/aarch64/aarch64/db_interface.c   Sun Aug 02 06:51:47 2020 +0000
+++ b/sys/arch/aarch64/aarch64/db_interface.c   Sun Aug 02 06:58:16 2020 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: db_interface.c,v 1.7 2019/01/27 02:08:36 pgoyette Exp $ */
+/* $NetBSD: db_interface.c,v 1.8 2020/08/02 06:58:16 maxv Exp $ */
 
 /*
  * Copyright (c) 2017 Ryo Shimizu <ryo%nerv.org@localhost>
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: db_interface.c,v 1.7 2019/01/27 02:08:36 pgoyette Exp $");
+__KERNEL_RCSID(0, "$NetBSD: db_interface.c,v 1.8 2020/08/02 06:58:16 maxv Exp $");
 
 #include <sys/param.h>
 #include <sys/types.h>
@@ -67,6 +67,9 @@
                }
                lastpage = atop((vaddr_t)src);
 
+               if (aarch64_pan_enabled)
+                       reg_pan_write(0); /* disable PAN */
+
                tmp = (uintptr_t)src | (uintptr_t)data;
                if ((size >= 8) && ((tmp & 7) == 0)) {
                        *(uint64_t *)data = *(const uint64_t *)src;
@@ -87,6 +90,9 @@
                        *data++ = *src++;
                        size--;
                }
+
+               if (aarch64_pan_enabled)
+                       reg_pan_write(1); /* enable PAN */
        }
 }
 
diff -r a497a50cacf9 -r a9ff7dfc3d34 sys/arch/aarch64/aarch64/fault.c
--- a/sys/arch/aarch64/aarch64/fault.c  Sun Aug 02 06:51:47 2020 +0000
+++ b/sys/arch/aarch64/aarch64/fault.c  Sun Aug 02 06:58:16 2020 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: fault.c,v 1.14 2020/07/08 03:45:13 ryo Exp $   */
+/*     $NetBSD: fault.c,v 1.15 2020/08/02 06:58:16 maxv Exp $  */
 
 /*
  * Copyright (c) 2017 Ryo Shimizu <ryo%nerv.org@localhost>
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: fault.c,v 1.14 2020/07/08 03:45:13 ryo Exp $");
+__KERNEL_RCSID(0, "$NetBSD: fault.c,v 1.15 2020/08/02 06:58:16 maxv Exp $");
 
 #include "opt_compat_netbsd32.h"
 #include "opt_ddb.h"
@@ -136,6 +136,7 @@
        vm_prot_t ftype;
        int error = 0, len;
        const bool user = IS_SPSR_USER(tf->tf_spsr) ? true : false;
+       bool is_pan_trap = false;
 
        bool fatalabort;
        const char *faultstr;
@@ -191,6 +192,16 @@
        }
 #endif
 
+       if (__predict_false(!user && (map != kernel_map) &&
+           (tf->tf_spsr & SPSR_PAN))) {
+               /*
+                * We were in kernel mode, faulted on a user address,
+                * and had PAN enabled. This is a fatal fault.
+                */
+               is_pan_trap = true;
+               goto handle_fault;
+       }
+
        /* reference/modified emulation */
        if (pmap_fault_fixup(map->pmap, va, ftype, user)) {
                UVMHIST_LOG(pmaphist, "fixed: va=%016llx", tf->tf_far, 0, 0, 0);
@@ -218,6 +229,7 @@
                return;
        }
 
+ handle_fault:
        fsc = __SHIFTOUT(esr, ESR_ISS_DATAABORT_DFSC); /* also IFSC */
        if (user) {
                if (!fatalabort) {
@@ -326,6 +338,10 @@
                len += snprintf(panicinfo + len, sizeof(panicinfo) - len,
                    ", State 2 Fault");
 
+       if (is_pan_trap)
+               len += snprintf(panicinfo + len, sizeof(panicinfo) - len,
+                   ", PAN Set");
+
        len += snprintf(panicinfo + len, sizeof(panicinfo) - len,
            ": pc %016"PRIxREGISTER, tf->tf_pc);
 
diff -r a497a50cacf9 -r a9ff7dfc3d34 sys/arch/aarch64/aarch64/fusu.S
--- a/sys/arch/aarch64/aarch64/fusu.S   Sun Aug 02 06:51:47 2020 +0000
+++ b/sys/arch/aarch64/aarch64/fusu.S   Sun Aug 02 06:58:16 2020 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: fusu.S,v 1.6 2019/04/06 03:06:24 thorpej Exp $ */
+/*     $NetBSD: fusu.S,v 1.7 2020/08/02 06:58:16 maxv Exp $    */
 
 /*-
  * Copyright (c) 2014, 2019 The NetBSD Foundation, Inc.
@@ -32,7 +32,27 @@
 #include <aarch64/asm.h>
 #include "assym.h"
 
-RCSID("$NetBSD: fusu.S,v 1.6 2019/04/06 03:06:24 thorpej Exp $");
+RCSID("$NetBSD: fusu.S,v 1.7 2020/08/02 06:58:16 maxv Exp $");
+
+#ifdef ARMV81_PAN
+#define PAN_ENABLE     \
+       adrl    x9, _C_LABEL(aarch64_pan_enabled)       ; \
+       ldr     w9, [x9]                                ; \
+       cbz     w9, 666f                                ; \
+       msr     pan, #1                                 ; \
+666:
+#define PAN_DISABLE    \
+       adrl    x9, _C_LABEL(aarch64_pan_enabled)       ; \
+       ldr     w9, [x9]                                ; \
+       cbz     w9, 666f                                ; \
+       msr     pan, #0                                 ; \
+666:
+#else
+#define PAN_ENABLE     /* nothing */
+#define PAN_DISABLE    /* nothing */
+#endif
+
+       ARMV8_DEFINE_OPTIONS
 
        .macro enter_cpu_onfault
        stp     fp, lr, [sp, #-16]!     /* save fp, lr */
@@ -47,6 +67,8 @@
        mov     x0, sp                  /* x0 = faultbuf */
        bl      cpu_set_onfault         /* x0 = cpu_set_onfault() */
        cbnz    x0, 9f                  /* return if error */
+
+       PAN_DISABLE                     /* disable PAN */
        .endm
 
        .macro exit_cpu_onfault
@@ -55,6 +77,7 @@
        ldr     x1, [x1, #CI_CURLWP]            /* x1 = curlwp */
        str     xzr, [x1, #L_MD_ONFAULT]        /* lwp->l_md_onfault = NULL */



Home | Main Index | Thread Index | Old Index