Theo de Raadt <[email protected]> wrote:
> Theo de Raadt <[email protected]> wrote:
>
> > kettenis, mortimer, and I have had long discussions about the
> > uvm_map_inentry() checks in MD trap.c being excessively broad. We can
> > this check-function less often.
> >
> > I don't want to explain the full picture about how SP and PC checks
> > in syscall() and trap() hinder ROP, ROP stack pivoting, gadgets with
> > unfortunate memory access side-effects, etc. But...
> >
> > When a ROP chain pivots onto a non-MAP_STACK chunk of data, to use a
> > data/heap loaded secondary chain, it will eventually want to do a system
> > call.
> >
> > (a) Thus, we force the chain to pivot back to MAP_STACK memory before doing
> > the first syscall, otherwise the SP check in syscall() will kill it.
> > This pivot-back is additional labour not neccessary for attack on other
> > operating systems.
> >
> > (b) We also do sp checking at trap time. On most architectures it is
> > currently done for MANY types of userland traps. (Additionally, it can
> > tsleep, which exposed a bunch of old bugs on many architecturs we fixed
> > at k2k20). We now propose only performing uvm_map_inentry() for the
> > standard userland "page fault" case which goes to uvm_fault()
> >
> > It is pointless (and costly) to use interrupts, or other strange and
> > rare traps, hoping to catch a rop chain which is just chewing through
> > properly mapped memory. Those other traps tend to also get us into
> > issues like tsleep. Without a performance cost, and negligable security
> > benefit.
> >
> > However, unmapped memory is the achilles heel.
> >
> > A poorly written chain will eventually accesseses unmapped memory because
> > it is using a gadget which has a memory-access side effect (and
> > references to a not-yet-mapped page (either cow fault, or zfod, or
> > demand-from-vnode), or because it is trying to use memory-scanning or
> > sled methods). Additionally, such unmapped memory accesses maybe done as
> > ptr derefs against uncontrolled registers, and libc randomization plays
> > a powerful role (but the margin way too narrow)
> >
> > So for an attacker, this reduces gadget selection to ONLY THE BEST
> > GADGETS -- meaning, minimal or no side effects. We've reduced gadget
> > count by a lot, placed code in very random places, so this becomes a
> > further hinderance in selection.
> >
> > By narrowing the check, it will bring back a bit of performance from
> > before the addition of trap.c uvm_map_inentry()
>
> Repeating diffs from i386, amd64, sh. Improve alpha diff to handle an
> additional fault case. Adding diffs for powerpc, powerc64, and m88k.
>
> armv7, sparc64, hppa, mips64 still missing. arm64 is already doing it
> mostly right.
Plus hppa.
armv7, sparc64, mips64 missing.
Index: alpha/alpha/trap.c
===================================================================
RCS file: /cvs/src/sys/arch/alpha/alpha/trap.c,v
retrieving revision 1.89
diff -u -p -u -r1.89 trap.c
--- alpha/alpha/trap.c 19 Aug 2020 10:10:57 -0000 1.89
+++ alpha/alpha/trap.c 23 Sep 2020 13:11:48 -0000
@@ -244,10 +244,6 @@ trap(a0, a1, a2, entry, framep)
if (user) {
p->p_md.md_tf = framep;
refreshcreds(p);
- if (!uvm_map_inentry(p, &p->p_spinentry, PROC_STACK(p),
- "[%s]%d/%d sp=%lx inside %lx-%lx: not MAP_STACK\n",
- uvm_map_inentry_sp, p->p_vmspace->vm_map.sserial))
- goto out;
}
switch (entry) {
@@ -370,6 +366,12 @@ trap(a0, a1, a2, entry, framep)
break;
case ALPHA_KENTRY_MM:
+ if (user &&
+ !uvm_map_inentry(p, &p->p_spinentry, PROC_STACK(p),
+ "[%s]%d/%d sp=%lx inside %lx-%lx: not MAP_STACK\n",
+ uvm_map_inentry_sp, p->p_vmspace->vm_map.sserial))
+ goto out;
+
switch (a1) {
case ALPHA_MMCSR_FOR:
case ALPHA_MMCSR_FOE:
Index: amd64/amd64/trap.c
===================================================================
RCS file: /cvs/src/sys/arch/amd64/amd64/trap.c,v
retrieving revision 1.81
diff -u -p -u -r1.81 trap.c
--- amd64/amd64/trap.c 14 Sep 2020 12:51:28 -0000 1.81
+++ amd64/amd64/trap.c 23 Sep 2020 12:17:10 -0000
@@ -343,11 +343,6 @@ usertrap(struct trapframe *frame)
p->p_md.md_regs = frame;
refreshcreds(p);
- if (!uvm_map_inentry(p, &p->p_spinentry, PROC_STACK(p),
- "[%s]%d/%d sp=%lx inside %lx-%lx: not MAP_STACK\n",
- uvm_map_inentry_sp, p->p_vmspace->vm_map.sserial))
- goto out;
-
switch (type) {
case T_PROTFLT: /* protection fault */
case T_TSSFLT:
@@ -381,6 +376,10 @@ usertrap(struct trapframe *frame)
break;
case T_PAGEFLT: /* page fault */
+ if (!uvm_map_inentry(p, &p->p_spinentry, PROC_STACK(p),
+ "[%s]%d/%d sp=%lx inside %lx-%lx: not MAP_STACK\n",
+ uvm_map_inentry_sp, p->p_vmspace->vm_map.sserial))
+ goto out;
if (pageflttrap(frame, cr2, 1))
goto out;
/* FALLTHROUGH */
Index: hppa/hppa/trap.c
===================================================================
RCS file: /cvs/src/sys/arch/hppa/hppa/trap.c,v
retrieving revision 1.148
diff -u -p -u -r1.148 trap.c
--- hppa/hppa/trap.c 14 Sep 2020 19:04:30 -0000 1.148
+++ hppa/hppa/trap.c 23 Sep 2020 14:12:17 -0000
@@ -213,13 +213,8 @@ trap(int type, struct trapframe *frame)
mtctl(frame->tf_eiem, CR_EIEM);
}
- if (type & T_USER) {
+ if (type & T_USER)
refreshcreds(p);
- if (!uvm_map_inentry(p, &p->p_spinentry, PROC_STACK(p),
- "[%s]%d/%d sp=%lx inside %lx-%lx: not MAP_STACK\n",
- uvm_map_inentry_sp, p->p_vmspace->vm_map.sserial))
- goto out;
- }
switch (type) {
case T_NONEXIST:
@@ -462,6 +457,13 @@ datacc:
case T_ITLBMISS | T_USER:
case T_DTLBMISS:
case T_DTLBMISS | T_USER:
+ if (type & T_USER) {
+ if (!uvm_map_inentry(p, &p->p_spinentry, PROC_STACK(p),
+ "[%s]%d/%d sp=%lx inside %lx-%lx: not MAP_STACK\n",
+ uvm_map_inentry_sp, p->p_vmspace->vm_map.sserial))
+ goto out;
+ }
+
/*
* it could be a kernel map for exec_map faults
*/
Index: i386/i386/trap.c
===================================================================
RCS file: /cvs/src/sys/arch/i386/i386/trap.c,v
retrieving revision 1.145
diff -u -p -u -r1.145 trap.c
--- i386/i386/trap.c 15 Sep 2020 09:30:31 -0000 1.145
+++ i386/i386/trap.c 23 Sep 2020 12:16:23 -0000
@@ -153,10 +153,6 @@ trap(struct trapframe *frame)
type |= T_USER;
p->p_md.md_regs = frame;
refreshcreds(p);
- if (!uvm_map_inentry(p, &p->p_spinentry, PROC_STACK(p),
- "[%s]%d/%d sp=%lx inside %lx-%lx: not MAP_STACK\n",
- uvm_map_inentry_sp, p->p_vmspace->vm_map.sserial))
- goto out;
}
switch (type) {
@@ -352,6 +348,10 @@ trap(struct trapframe *frame)
int error;
int signal, sicode;
+ if (!uvm_map_inentry(p, &p->p_spinentry, PROC_STACK(p),
+ "[%s]%d/%d sp=%lx inside %lx-%lx: not MAP_STACK\n",
+ uvm_map_inentry_sp, p->p_vmspace->vm_map.sserial))
+ goto out;
KERNEL_LOCK();
faultcommon:
vm = p->p_vmspace;
Index: m88k/m88k/trap.c
===================================================================
RCS file: /cvs/src/sys/arch/m88k/m88k/trap.c,v
retrieving revision 1.112
diff -u -p -u -r1.112 trap.c
--- m88k/m88k/trap.c 19 Aug 2020 10:10:58 -0000 1.112
+++ m88k/m88k/trap.c 23 Sep 2020 13:53:22 -0000
@@ -239,10 +239,6 @@ m88100_trap(u_int type, struct trapframe
type += T_USER;
p->p_md.md_tf = frame; /* for ptrace/signals */
refreshcreds(p);
- if (!uvm_map_inentry(p, &p->p_spinentry, PROC_STACK(p),
- "[%s]%d/%d sp=%lx inside %lx-%lx: not MAP_STACK\n",
- uvm_map_inentry_sp, p->p_vmspace->vm_map.sserial))
- goto userexit;
}
fault_type = SI_NOINFO;
fault_code = 0;
@@ -862,6 +858,11 @@ lose:
/* User mode instruction access fault */
/* FALLTHROUGH */
case T_DATAFLT+T_USER:
+ if (!uvm_map_inentry(p, &p->p_spinentry, PROC_STACK(p),
+ "[%s]%d/%d sp=%lx inside %lx-%lx: not MAP_STACK\n",
+ uvm_map_inentry_sp, p->p_vmspace->vm_map.sserial))
+ goto userexit;
+
KERNEL_LOCK();
m88110_user_fault:
if (type == T_INSTFLT+T_USER) {
Index: powerpc/powerpc/trap.c
===================================================================
RCS file: /cvs/src/sys/arch/powerpc/powerpc/trap.c,v
retrieving revision 1.115
diff -u -p -u -r1.115 trap.c
--- powerpc/powerpc/trap.c 19 Aug 2020 10:10:58 -0000 1.115
+++ powerpc/powerpc/trap.c 23 Sep 2020 13:10:14 -0000
@@ -245,10 +245,6 @@ trap(struct trapframe *frame)
if (frame->srr1 & PSL_PR) {
type |= EXC_USER;
refreshcreds(p);
- if (!uvm_map_inentry(p, &p->p_spinentry, PROC_STACK(p),
- "[%s]%d/%d sp=%lx inside %lx-%lx: not MAP_STACK\n",
- uvm_map_inentry_sp, p->p_vmspace->vm_map.sserial))
- goto out;
}
switch (type) {
@@ -309,6 +305,11 @@ trap(struct trapframe *frame)
if (pte_spill_v(p->p_vmspace->vm_map.pmap,
frame->dar, frame->dsisr, 0))
break;
+
+ if (!uvm_map_inentry(p, &p->p_spinentry, PROC_STACK(p),
+ "[%s]%d/%d sp=%lx inside %lx-%lx: not MAP_STACK\n",
+ uvm_map_inentry_sp, p->p_vmspace->vm_map.sserial))
+ goto out;
KERNEL_LOCK();
if (frame->dsisr & DSISR_STORE) {
Index: powerpc64/powerpc64/trap.c
===================================================================
RCS file: /cvs/src/sys/arch/powerpc64/powerpc64/trap.c,v
retrieving revision 1.37
diff -u -p -u -r1.37 trap.c
--- powerpc64/powerpc64/trap.c 15 Sep 2020 07:47:24 -0000 1.37
+++ powerpc64/powerpc64/trap.c 23 Sep 2020 13:14:55 -0000
@@ -92,10 +92,6 @@ trap(struct trapframe *frame)
type |= EXC_USER;
p->p_md.md_regs = frame;
refreshcreds(p);
- if (!uvm_map_inentry(p, &p->p_spinentry, PROC_STACK(p),
- "[%s]%d/%d sp=%lx inside %lx-%lx: not MAP_STACK\n",
- uvm_map_inentry_sp, p->p_vmspace->vm_map.sserial))
- goto out;
}
switch (type) {
@@ -172,6 +168,11 @@ trap(struct trapframe *frame)
/* FALLTHROUGH */
case EXC_DSI|EXC_USER:
+ if (!uvm_map_inentry(p, &p->p_spinentry, PROC_STACK(p),
+ "[%s]%d/%d sp=%lx inside %lx-%lx: not MAP_STACK\n",
+ uvm_map_inentry_sp, p->p_vmspace->vm_map.sserial))
+ goto out;
+
map = &p->p_vmspace->vm_map;
va = frame->dar;
if (frame->dsisr & DSISR_STORE)
@@ -214,6 +215,11 @@ trap(struct trapframe *frame)
/* FALLTHROUGH */
case EXC_ISI|EXC_USER:
+ if (!uvm_map_inentry(p, &p->p_spinentry, PROC_STACK(p),
+ "[%s]%d/%d sp=%lx inside %lx-%lx: not MAP_STACK\n",
+ uvm_map_inentry_sp, p->p_vmspace->vm_map.sserial))
+ goto out;
+
map = &p->p_vmspace->vm_map;
va = frame->srr0;
ftype = PROT_READ | PROT_EXEC;
Index: sh/sh/trap.c
===================================================================
RCS file: /cvs/src/sys/arch/sh/sh/trap.c,v
retrieving revision 1.42
diff -u -p -u -r1.42 trap.c
--- sh/sh/trap.c 22 Sep 2020 15:50:20 -0000 1.42
+++ sh/sh/trap.c 23 Sep 2020 12:19:30 -0000
@@ -173,12 +173,6 @@ general_exception(struct proc *p, struct
KDASSERT(p->p_md.md_regs == tf); /* check exception depth */
expevt |= EXP_USER;
refreshcreds(p);
- if (tra != _SH_TRA_SYSCALL << 2) {
- if (!uvm_map_inentry(p, &p->p_spinentry, PROC_STACK(p),
- "[%s]%d/%d sp=%lx inside %lx-%lx: not MAP_STACK\n",
- uvm_map_inentry_sp, p->p_vmspace->vm_map.sserial))
- goto out;
- }
}
switch (expevt) {
@@ -389,6 +383,11 @@ tlb_exception(struct proc *p, struct tra
/* Select address space */
if (usermode) {
+ if (!uvm_map_inentry(p, &p->p_spinentry, PROC_STACK(p),
+ "[%s]%d/%d sp=%lx inside %lx-%lx: not MAP_STACK\n",
+ uvm_map_inentry_sp, p->p_vmspace->vm_map.sserial))
+ goto out;
+
TLB_ASSERT(p != NULL, "no curproc");
map = &p->p_vmspace->vm_map;
pmap = map->pmap;