> Date: Fri, 14 Aug 2020 14:40:23 +0200 (CEST) > From: Mark Kettenis <mark.kette...@xs4all.nl> > > I suppose a way to test this properly is to pick a system call and > replace a copyin() with a direct access? That will succeed without > PAN but should fail with PAN enabled right?
So that does indeed work. However, the result is a hard hang. So here as an additional diff that makes sure we panic instead. The idea is that all user-space access from the kernel should be done by the special unprivileged load/store instructions. Index: arch/arm64/arm64/trap.c =================================================================== RCS file: /cvs/src/sys/arch/arm64/arm64/trap.c,v retrieving revision 1.27 diff -u -p -r1.27 trap.c --- arch/arm64/arm64/trap.c 6 Jan 2020 12:37:30 -0000 1.27 +++ arch/arm64/arm64/trap.c 14 Aug 2020 21:05:54 -0000 @@ -65,6 +65,14 @@ void do_el0_error(struct trapframe *); void dumpregs(struct trapframe*); +/* Check whether we're executing an unprivileged load/store instruction. */ +static inline int +is_unpriv_ldst(uint64_t elr) +{ + uint32_t insn = *(uint32_t *)elr; + return ((insn & 0x3f200c00) == 0x38000800); +} + static void data_abort(struct trapframe *frame, uint64_t esr, uint64_t far, int lower, int exe) @@ -104,8 +112,18 @@ data_abort(struct trapframe *frame, uint /* The top bit tells us which range to use */ if ((far >> 63) == 1) map = kernel_map; - else + else { + /* + * Only allow user-space access using + * unprivileged load/store instructions. + */ + if (!is_unpriv_ldst(frame->tf_elr)) { + panic("attempt to access user address" + " 0x%llx from EL1", far); + } + map = &p->p_vmspace->vm_map; + } } if (exe)