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 Pointer Authentication (PAC).



details:   https://anonhg.NetBSD.org/src/rev/0d5498395752
branches:  trunk
changeset: 1009084:0d5498395752
user:      maxv <maxv%NetBSD.org@localhost>
date:      Sun Apr 12 07:49:58 2020 +0000

description:
Add support for Pointer Authentication (PAC).

We use the "pac-ret" option, to sign the return instruction pointer on
function entry, and authenticate it on function exit. This acts as a
mitigation against ROP.

The authentication uses a per-lwp (secret) I-A key stored in the 128bit
APIAKey register and part of the lwp context. During lwp creation, the
kernel generates a random key, and during context switches, it installs
the key of the target lwp on the CPU.

Userland cannot read the APIAKey register directly. However, it can sign
its pointers with it, because the register is architecturally shared
between userland and the kernel. Although part of the CPU design, it is
a bit of an undesired behavior, because it allows to forge valid kernel
pointers from userland. To avoid that, we don't share the key with
userland, and rather switch it in EL0<->EL1 transitions. This means that
when userland executes, a different key is loaded in APIAKey than the one
the kernel uses. For now the userland key is a fixed 128bit zero value.

The DDB stack unwinder is changed to strip the authentication code from
the pointers in lr.

Two problems are known:

 * Currently the idlelwps' keys are not really secret. This is because
   the RNG is not yet available when we spawn these lwps. Not overly
   important, but would be nice to fix with UEFI RNG.
 * The key switching in EL0<->EL1 transitions is not the most optimized
   code on the planet. Instead of checking aarch64_pac_enabled, it would
   be better to hot-patch the code at boot time, but there currently is
   no hot-patch support on aarch64.

Tested on Qemu.

diffstat:

 sys/arch/aarch64/aarch64/aarch64_machdep.c |  12 ++++-
 sys/arch/aarch64/aarch64/cpufunc.c         |  48 +++++++++++++++++++-
 sys/arch/aarch64/aarch64/cpuswitch.S       |  72 +++++++++++++++++++++++++++++-
 sys/arch/aarch64/aarch64/db_trace.c        |   7 ++-
 sys/arch/aarch64/aarch64/genassym.cf       |   6 ++-
 sys/arch/aarch64/aarch64/locore.S          |  12 ++++-
 sys/arch/aarch64/aarch64/vectors.S         |  17 ++++++-
 sys/arch/aarch64/aarch64/vm_machdep.c      |  15 +++++-
 sys/arch/aarch64/conf/Makefile.aarch64     |   6 ++-
 sys/arch/aarch64/include/armreg.h          |  27 ++++++++++-
 sys/arch/aarch64/include/asm.h             |  20 +++++++-
 sys/arch/aarch64/include/cpufunc.h         |   6 ++-
 sys/arch/aarch64/include/proc.h            |   8 ++-
 sys/arch/arm/conf/files.arm                |   5 +-
 sys/arch/evbarm/conf/GENERIC64             |   6 ++-
 15 files changed, 246 insertions(+), 21 deletions(-)

diffs (truncated from 592 to 300 lines):

diff -r dfad46bae277 -r 0d5498395752 sys/arch/aarch64/aarch64/aarch64_machdep.c
--- a/sys/arch/aarch64/aarch64/aarch64_machdep.c        Sun Apr 12 07:41:11 2020 +0000
+++ b/sys/arch/aarch64/aarch64/aarch64_machdep.c        Sun Apr 12 07:49:58 2020 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: aarch64_machdep.c,v 1.40 2020/02/29 21:36:03 ryo Exp $ */
+/* $NetBSD: aarch64_machdep.c,v 1.41 2020/04/12 07:49:58 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.40 2020/02/29 21:36:03 ryo Exp $");
+__KERNEL_RCSID(1, "$NetBSD: aarch64_machdep.c,v 1.41 2020/04/12 07:49:58 maxv Exp $");
 
 #include "opt_arm_debug.h"
 #include "opt_ddb.h"
@@ -456,6 +456,14 @@
            SYSCTL_DESCR("top byte ignored in the address calculation"),
            sysctl_machdep_tagged_address, 0, NULL, 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,
+           &aarch64_pac_enabled, 0,
+           CTL_MACHDEP, CTL_CREATE, CTL_EOL);
 }
 
 void
diff -r dfad46bae277 -r 0d5498395752 sys/arch/aarch64/aarch64/cpufunc.c
--- a/sys/arch/aarch64/aarch64/cpufunc.c        Sun Apr 12 07:41:11 2020 +0000
+++ b/sys/arch/aarch64/aarch64/cpufunc.c        Sun Apr 12 07:49:58 2020 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: cpufunc.c,v 1.16 2020/04/05 22:54:51 jmcneill Exp $    */
+/*     $NetBSD: cpufunc.c,v 1.17 2020/04/12 07:49:58 maxv Exp $        */
 
 /*
  * Copyright (c) 2017 Ryo Shimizu <ryo%nerv.org@localhost>
@@ -26,10 +26,11 @@
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
+#include "opt_cpuoptions.h"
 #include "opt_multiprocessor.h"
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: cpufunc.c,v 1.16 2020/04/05 22:54:51 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: cpufunc.c,v 1.17 2020/04/12 07:49:58 maxv Exp $");
 
 #include <sys/param.h>
 #include <sys/types.h>
@@ -46,6 +47,8 @@
 u_int aarch64_cache_vindexsize;
 u_int aarch64_cache_prefer_mask;
 
+int aarch64_pac_enabled __read_mostly;
+
 /* cache info per cluster. the same cluster has the same cache configuration? */
 #define MAXCPUPACKAGES MAXCPUS         /* maximum of ci->ci_package_id */
 static struct aarch64_cache_info *aarch64_cacheinfo[MAXCPUPACKAGES];
@@ -438,3 +441,44 @@
 
        return 0;
 }
+
+/*
+ * TODO: this function should have a "no-pac" attribute. Right now it
+ * doesn't use PAC so that's fine.
+ */
+void
+aarch64_pac_init(int primary)
+{
+#ifdef ARMV83_PAC
+       uint64_t reg, sctlr;
+
+       /* CPU0 does the detection. */
+       if (primary) {
+               reg = reg_id_aa64isar1_el1_read();
+               if (__SHIFTOUT(reg, ID_AA64ISAR1_EL1_APA) !=
+                   ID_AA64ISAR1_EL1_APA_NONE)
+                       aarch64_pac_enabled = 1;
+               if (__SHIFTOUT(reg, ID_AA64ISAR1_EL1_API) !=
+                   ID_AA64ISAR1_EL1_API_NONE)
+                       aarch64_pac_enabled = 1;
+               if (__SHIFTOUT(reg, ID_AA64ISAR1_EL1_GPA) !=
+                   ID_AA64ISAR1_EL1_GPA_NONE)
+                       aarch64_pac_enabled = 1;
+               if (__SHIFTOUT(reg, ID_AA64ISAR1_EL1_GPI) !=
+                   ID_AA64ISAR1_EL1_GPI_NONE)
+                       aarch64_pac_enabled = 1;
+       }
+
+       if (!aarch64_pac_enabled)
+               return;
+
+       /* Enable PAC on the CPU. */
+       sctlr = reg_sctlr_el1_read();
+       sctlr |= SCTLR_EnIA;
+       reg_sctlr_el1_write(sctlr);
+
+       /* Set the key. Curlwp here is the CPU's idlelwp. */
+       reg_APIAKeyLo_EL1_write(curlwp->l_md.md_ia_kern_lo);
+       reg_APIAKeyHi_EL1_write(curlwp->l_md.md_ia_kern_hi);
+#endif
+}
diff -r dfad46bae277 -r 0d5498395752 sys/arch/aarch64/aarch64/cpuswitch.S
--- a/sys/arch/aarch64/aarch64/cpuswitch.S      Sun Apr 12 07:41:11 2020 +0000
+++ b/sys/arch/aarch64/aarch64/cpuswitch.S      Sun Apr 12 07:49:58 2020 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: cpuswitch.S,v 1.15 2020/01/08 20:59:18 skrll Exp $ */
+/* $NetBSD: cpuswitch.S,v 1.16 2020/04/12 07:49:58 maxv Exp $ */
 
 /*-
  * Copyright (c) 2014 The NetBSD Foundation, Inc.
@@ -34,10 +34,13 @@
 #include "assym.h"
 
 #include "opt_compat_netbsd32.h"
+#include "opt_cpuoptions.h"
 #include "opt_ddb.h"
 #include "opt_kasan.h"
 
-RCSID("$NetBSD: cpuswitch.S,v 1.15 2020/01/08 20:59:18 skrll Exp $")
+RCSID("$NetBSD: cpuswitch.S,v 1.16 2020/04/12 07:49:58 maxv Exp $")
+
+       ARMV8_DEFINE_OPTIONS
 
 /*
  * At IPL_SCHED:
@@ -77,6 +80,18 @@
        mov     sp, x4                  /* restore stack pointer */
        msr     cpacr_el1, x5           /* restore cpacr_el1 */
 
+#ifdef ARMV83_PAC
+       /* Switch the PAC key. */
+       adrl    x4, _C_LABEL(aarch64_pac_enabled)
+       ldr     w4, [x4]
+       cbz     w4, 1f
+       ldr     x5, [x1, #L_MD_IA_KERN_LO]
+       ldr     x6, [x1, #L_MD_IA_KERN_HI]
+       msr     APIAKeyLo_EL1, x5
+       msr     APIAKeyHi_EL1, x6
+1:
+#endif
+
        mrs     x3, tpidr_el1
        str     x1, [x3, #CI_CURLWP]    /* switch curlwp to new lwp */
        ENABLE_INTERRUPT
@@ -132,6 +147,18 @@
        str     x5, [x19, #L_MD_CPACR]
        str     x0, [x3, #CI_CURLWP]    /* curcpu()->ci_curlwp = softlwp; */
 
+#ifdef ARMV83_PAC
+       /* Switch the PAC key. */
+       adrl    x4, _C_LABEL(aarch64_pac_enabled)
+       ldr     w4, [x4]
+       cbz     w4, 1f
+       ldr     x5, [x0, #L_MD_IA_KERN_LO]
+       ldr     x6, [x0, #L_MD_IA_KERN_HI]
+       msr     APIAKeyLo_EL1, x5
+       msr     APIAKeyHi_EL1, x6
+1:
+#endif
+
 #ifdef KASAN
        /* clear the new stack */
        stp     x0, x1, [sp, #-16]!
@@ -159,6 +186,18 @@
        mov     sp, x4                  /* restore pinned_lwp sp */
        msr     cpacr_el1, x5           /* restore pinned_lwp cpacr */
 
+#ifdef ARMV83_PAC
+       /* Restore the PAC key. */
+       adrl    x4, _C_LABEL(aarch64_pac_enabled)
+       ldr     w4, [x4]
+       cbz     w4, 1f
+       ldr     x5, [x19, #L_MD_IA_KERN_LO]
+       ldr     x6, [x19, #L_MD_IA_KERN_HI]
+       msr     APIAKeyLo_EL1, x5
+       msr     APIAKeyHi_EL1, x6
+1:
+#endif
+
        ldp     x19, x20, [sp, #TF_X19]
        msr     daif, x19               /* restore interrupt mask */
        mov     lr, x20                 /* restore pinned_lwp lr */
@@ -199,7 +238,24 @@
  *     x28 = arg
  */
 ENTRY_NP(lwp_trampoline)
+       stp     x0, x1, [sp, #-16]!     /* save x0, x1 */
        bl      _C_LABEL(lwp_startup)
+       ldp     x0, x1, [sp], #16       /* restore x0, x1 */
+
+#ifdef ARMV83_PAC
+       /* Generate a new PAC key. */
+       adrl    x4, _C_LABEL(aarch64_pac_enabled)
+       ldr     w4, [x4]
+       cbz     w4, 1f
+       mov     x26, x1
+       bl      _C_LABEL(cprng_strong64)
+       ldr     x0, [x26, #L_MD_IA_KERN_LO]
+       msr     APIAKeyLo_EL1, x0
+       bl      _C_LABEL(cprng_strong64)
+       ldr     x0, [x26, #L_MD_IA_KERN_HI]
+       msr     APIAKeyHi_EL1, x0
+1:
+#endif
 
        /*
         * When the x27 function returns, it will jump to el0_trap_exit.
@@ -311,6 +367,18 @@
        msr     tpidrro_el0, x0
 #endif
 
+#ifdef ARMV83_PAC
+       /* Switch to the user PAC key. */
+       adrl    x4, _C_LABEL(aarch64_pac_enabled)
+       ldr     w4, [x4]
+       cbz     w4, 1f
+       ldr     x5, [x9, #L_MD_IA_USER_LO]
+       ldr     x6, [x9, #L_MD_IA_USER_HI]
+       msr     APIAKeyLo_EL1, x5
+       msr     APIAKeyHi_EL1, x6
+1:
+#endif
+
        unwind_x3_x30
 
 #if TF_PC + 8 == TF_SPSR
diff -r dfad46bae277 -r 0d5498395752 sys/arch/aarch64/aarch64/db_trace.c
--- a/sys/arch/aarch64/aarch64/db_trace.c       Sun Apr 12 07:41:11 2020 +0000
+++ b/sys/arch/aarch64/aarch64/db_trace.c       Sun Apr 12 07:49:58 2020 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: db_trace.c,v 1.8 2019/01/27 02:08:36 pgoyette Exp $ */
+/* $NetBSD: db_trace.c,v 1.9 2020/04/12 07:49:58 maxv Exp $ */
 
 /*
  * Copyright (c) 2017 Ryo Shimizu <ryo%nerv.org@localhost>
@@ -28,7 +28,7 @@
 
 #include <sys/cdefs.h>
 
-__KERNEL_RCSID(0, "$NetBSD: db_trace.c,v 1.8 2019/01/27 02:08:36 pgoyette Exp $");
+__KERNEL_RCSID(0, "$NetBSD: db_trace.c,v 1.9 2020/04/12 07:49:58 maxv Exp $");
 
 #include <sys/param.h>
 #include <sys/proc.h>
@@ -236,6 +236,7 @@
                lastfp = lastlr = lr = fp = 0;
                db_read_bytes((db_addr_t)&tf->tf_pc, sizeof(lr), (char *)&lr);
                db_read_bytes((db_addr_t)&tf->tf_reg[29], sizeof(fp), (char *)&fp);
+               lr = ptr_strip_pac(lr);
 
                pr_traceaddr("fp", fp, lr - 4, flags, pr);
        }
@@ -251,6 +252,7 @@
                 */
                db_read_bytes(lastfp + 0, sizeof(fp), (char *)&fp);
                db_read_bytes(lastfp + 8, sizeof(lr), (char *)&lr);
+               lr = ptr_strip_pac(lr);
 
                if (!trace_user && IN_USER_VM_ADDRESS(lr))
                        break;
@@ -268,6 +270,7 @@
                        lr = fp = 0;
                        db_read_bytes((db_addr_t)&tf->tf_pc, sizeof(lr), (char *)&lr);
                        db_read_bytes((db_addr_t)&tf->tf_reg[29], sizeof(fp), (char *)&fp);
+                       lr = ptr_strip_pac(lr);
 
                        /*
                         * no need to display the frame of el0_trap
diff -r dfad46bae277 -r 0d5498395752 sys/arch/aarch64/aarch64/genassym.cf
--- a/sys/arch/aarch64/aarch64/genassym.cf      Sun Apr 12 07:41:11 2020 +0000
+++ b/sys/arch/aarch64/aarch64/genassym.cf      Sun Apr 12 07:49:58 2020 +0000
@@ -1,4 +1,4 @@
-# $NetBSD: genassym.cf,v 1.22 2020/02/20 08:27:38 skrll Exp $
+# $NetBSD: genassym.cf,v 1.23 2020/04/12 07:49:58 maxv Exp $
 #-
 # Copyright (c) 2014 The NetBSD Foundation, Inc.
 # All rights reserved.
@@ -150,6 +150,10 @@
 define L_MD_UTF                offsetof(struct lwp, l_md.md_utf)
 define L_MD_CPACR              offsetof(struct lwp, l_md.md_cpacr)
 define L_MD_ONFAULT            offsetof(struct lwp, l_md.md_onfault)
+define L_MD_IA_KERN_LO         offsetof(struct lwp, l_md.md_ia_kern_lo)
+define L_MD_IA_KERN_HI         offsetof(struct lwp, l_md.md_ia_kern_hi)
+define L_MD_IA_USER_LO         offsetof(struct lwp, l_md.md_ia_user_lo)
+define L_MD_IA_USER_HI         offsetof(struct lwp, l_md.md_ia_user_hi)
 
 define FB_X19                  FB_X19
 define FB_X20                  FB_X20
diff -r dfad46bae277 -r 0d5498395752 sys/arch/aarch64/aarch64/locore.S
--- a/sys/arch/aarch64/aarch64/locore.S Sun Apr 12 07:41:11 2020 +0000
+++ b/sys/arch/aarch64/aarch64/locore.S Sun Apr 12 07:49:58 2020 +0000
@@ -1,4 +1,4 @@



Home | Main Index | Thread Index | Old Index