From 97140827bb0382e36e8076da1e89509f9d6c7423 Mon Sep 17 00:00:00 2001 From: Konstantin Belousov Date: Thu, 15 Oct 2015 17:40:39 +0000 Subject: [PATCH] ARM userspace accessors, e.g. {s,f}uword(9), copy{in,out}(9), casuword(9) and others, use LDRT and STRT instructions to access memory with the privileges of userspace. If the *RT instruction faults on the kernel address, then additional checks must be done to not confuse the VM system with invalid kernel-mode faults. Put ARM on line with other FreeBSD architectures and disallow usermode buffers which intersect with the kernel address space in advance, before any accesses are performed. In other words, vm_fault(9) is no longer called when e.g. suword(9) stores to invalid (i.e. not userspace) address. Also, switch ARM to use fueword(9) and casueword(9). Note: there is a pending patch in D3617, which adds the special processing for faults from LDRT and STRT. The addition of the processing is useful for potential other uses of the instructions and for completeness, but standard userspace accessors are better served by not allowing such faults beforehand. Reviewed by: andrew Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D3816 MFC after: 2 weeks --- sys/arm/arm/bcopyinout.S | 18 +++++ sys/arm/arm/bcopyinout_xscale.S | 18 +++++ sys/arm/arm/copystr.S | 16 ++++- sys/arm/arm/fusu.S | 124 +++++++++++++++++++++----------- sys/arm/arm/genassym.c | 1 + sys/arm/include/param.h | 4 -- 6 files changed, 133 insertions(+), 48 deletions(-) diff --git a/sys/arm/arm/bcopyinout.S b/sys/arm/arm/bcopyinout.S index df0484e685c6..1c7e0fd6341a 100644 --- a/sys/arm/arm/bcopyinout.S +++ b/sys/arm/arm/bcopyinout.S @@ -94,6 +94,15 @@ ENTRY(copyin) moveq r0, #0 RETeq + adds r3, r0, r2 + movcs r0, #EFAULT + RETc(cs) + + ldr r12, =(VM_MAXUSER_ADDRESS + 1) + cmp r3, r12 + movcs r0, #EFAULT + RETc(cs) + ldr r3, .L_arm_memcpy ldr r3, [r3] cmp r3, #0 @@ -332,6 +341,15 @@ ENTRY(copyout) moveq r0, #0 RETeq + adds r3, r1, r2 + movcs r0, #EFAULT + RETc(cs) + + ldr r12, =(VM_MAXUSER_ADDRESS + 1) + cmp r3, r12 + movcs r0, #EFAULT + RETc(cs) + ldr r3, .L_arm_memcpy ldr r3, [r3] cmp r3, #0 diff --git a/sys/arm/arm/bcopyinout_xscale.S b/sys/arm/arm/bcopyinout_xscale.S index 7a5abb588d63..79a5027356c0 100644 --- a/sys/arm/arm/bcopyinout_xscale.S +++ b/sys/arm/arm/bcopyinout_xscale.S @@ -67,6 +67,15 @@ ENTRY(copyin) movle r0, #0x00 movle pc, lr /* Bail early if length is <= 0 */ + adds r3, r0, r2 + movcs r0, #EFAULT + RETc(cs) + + ldr r12, =(VM_MAXUSER_ADDRESS + 1) + cmp r3, r12 + movcs r0, #EFAULT + RETc(cs) + ldr r3, .L_arm_memcpy ldr r3, [r3] cmp r3, #0 @@ -509,6 +518,15 @@ ENTRY(copyout) movle r0, #0x00 movle pc, lr /* Bail early if length is <= 0 */ + adds r3, r1, r2 + movcs r0, #EFAULT + RETc(cs) + + ldr r12, =(VM_MAXUSER_ADDRESS + 1) + cmp r3, r12 + movcs r0, #EFAULT + RETc(cs) + ldr r3, .L_arm_memcpy ldr r3, [r3] cmp r3, #0 diff --git a/sys/arm/arm/copystr.S b/sys/arm/arm/copystr.S index 48c296b09292..4cb8469903d8 100644 --- a/sys/arm/arm/copystr.S +++ b/sys/arm/arm/copystr.S @@ -113,6 +113,8 @@ ENTRY(copyinstr) moveq r0, #ENAMETOOLONG beq 2f + ldr r12, =VM_MAXUSER_ADDRESS + GET_PCB(r4) ldr r4, [r4] @@ -124,7 +126,10 @@ ENTRY(copyinstr) adr r5, .Lcopystrfault str r5, [r4, #PCB_ONFAULT] -1: ldrbt r5, [r0], #0x0001 +1: + cmp r0, r12 + bcs .Lcopystrfault + ldrbt r5, [r0], #0x0001 add r6, r6, #0x00000001 teq r5, #0x00000000 strb r5, [r1], #0x0001 @@ -161,6 +166,8 @@ ENTRY(copyoutstr) moveq r0, #ENAMETOOLONG beq 2f + ldr r12, =VM_MAXUSER_ADDRESS + GET_PCB(r4) ldr r4, [r4] @@ -172,7 +179,10 @@ ENTRY(copyoutstr) adr r5, .Lcopystrfault str r5, [r4, #PCB_ONFAULT] -1: ldrb r5, [r0], #0x0001 +1: + cmp r0, r12 + bcs .Lcopystrfault + ldrb r5, [r0], #0x0001 add r6, r6, #0x00000001 teq r5, #0x00000000 strbt r5, [r1], #0x0001 @@ -195,9 +205,9 @@ END(copyoutstr) /* A fault occurred during the copy */ .Lcopystrfault: - mov r0, #EFAULT mov r1, #0x00000000 str r1, [r4, #PCB_ONFAULT] + mov r0, #EFAULT RESTORE_REGS RET diff --git a/sys/arm/arm/fusu.S b/sys/arm/arm/fusu.S index 06853c456948..dee2455a0d34 100644 --- a/sys/arm/arm/fusu.S +++ b/sys/arm/arm/fusu.S @@ -53,49 +53,51 @@ __FBSDID("$FreeBSD$"); #endif /* - * fuword(caddr_t uaddr); - * Fetch an int from the user's address space. + * casueword32(volatile uint32_t *base, uint32_t oldval, uint32_t *oldvalp, + * uint32_t newval); */ -ENTRY(casuword) -EENTRY_NP(casuword32) - GET_PCB(r3) - ldr r3, [r3] +ENTRY(casueword) +EENTRY_NP(casueword32) + stmfd sp!, {r4, r5, r6} + + ldr r4, =(VM_MAXUSER_ADDRESS-3) + cmp r0, r4 + mvncs r0, #0 + bcs 2f + + GET_PCB(r6) + ldr r6, [r6] #ifdef DIAGNOSTIC - teq r3, #0x00000000 + teq r6, #0x00000000 + ldmfdeq sp!, {r4, r5, r6} beq .Lfusupcbfault #endif - stmfd sp!, {r4, r5} + adr r4, .Lcasuwordfault - str r4, [r3, #PCB_ONFAULT] + str r4, [r6, #PCB_ONFAULT] + #if __ARM_ARCH >= 6 1: - cmp r0, #KERNBASE - mvnhs r0, #0 - bhs 2f - - ldrex r5, [r0] - cmp r5, r1 - movne r0, r5 - bne 2f - strex r5, r2, [r0] - cmp r5, #0 - bne 1b + ldrex r4, [r0] + cmp r4, r1 + strexeq r5, r3, [r0] + cmpeq r5, #1 + beq 1b #else - ldrt r5, [r0] - cmp r5, r1 - movne r0, r5 - strteq r2, [r0] + ldrt r4, [r0] + cmp r4, r1 + strteq r3, [r0] #endif - moveq r0, r1 + str r4, [r2] + mov r0, #0 + str r0, [r6, #PCB_ONFAULT] 2: - ldmfd sp!, {r4, r5} - mov r1, #0x00000000 - str r1, [r3, #PCB_ONFAULT] + ldmfd sp!, {r4, r5, r6} RET -EEND(casuword32) -END(casuword) +EEND(casueword32) +END(casueword) /* * Handle faults from casuword. Clean up and return -1. @@ -103,18 +105,23 @@ END(casuword) .Lcasuwordfault: mov r0, #0x00000000 - str r0, [r3, #PCB_ONFAULT] - mvn r0, #0x00000000 - ldmfd sp!, {r4, r5} + str r0, [r6, #PCB_ONFAULT] + mvn r0, #0 + ldmfd sp!, {r4, r5, r6} RET /* - * fuword(caddr_t uaddr); + * fueword(caddr_t uaddr, long *val); * Fetch an int from the user's address space. */ -ENTRY(fuword) -EENTRY_NP(fuword32) +ENTRY(fueword) +EENTRY_NP(fueword32) + ldr r3, =(VM_MAXUSER_ADDRESS-3) + cmp r0, r3 + mvncs r0, #0 + RETc(cs) + GET_PCB(r2) ldr r2, [r2] @@ -123,14 +130,14 @@ EENTRY_NP(fuword32) beq .Lfusupcbfault #endif - adr r1, .Lfusufault - str r1, [r2, #PCB_ONFAULT] + adr r3, .Lfusufault + str r3, [r2, #PCB_ONFAULT] ldrt r3, [r0] + str r3, [r1] - mov r1, #0x00000000 - str r1, [r2, #PCB_ONFAULT] - mov r0, r3 + mov r0, #0x00000000 + str r0, [r2, #PCB_ONFAULT] RET EEND(fuword32) END(fuword) @@ -141,6 +148,11 @@ END(fuword) */ ENTRY(fusword) + ldr r3, =(VM_MAXUSER_ADDRESS-1) + cmp r0, r3 + mvncs r0, #0 + RETc(cs) + GET_PCB(r2) ldr r2, [r2] @@ -171,6 +183,11 @@ END(fusword) */ ENTRY(fuswintr) + ldr r3, =(VM_MAXUSER_ADDRESS-1) + cmp r0, r3 + mvncs r0, #0 + RETc(cs) + ldr r2, Lblock_userspace_access ldr r2, [r2] teq r2, #0 @@ -217,6 +234,11 @@ _C_LABEL(block_userspace_access): */ ENTRY(fubyte) + ldr r3, =VM_MAXUSER_ADDRESS + cmp r0, r3 + mvncs r0, #0 + RETc(cs) + GET_PCB(r2) ldr r2, [r2] @@ -282,6 +304,11 @@ fusupcbfaulttext: ENTRY(suword) EENTRY_NP(suword32) + ldr r3, =(VM_MAXUSER_ADDRESS-3) + cmp r0, r3 + mvncs r0, #0 + RETc(cs) + GET_PCB(r2) ldr r2, [r2] @@ -308,6 +335,11 @@ END(suword) */ ENTRY(suswintr) + ldr r3, =(VM_MAXUSER_ADDRESS-1) + cmp r0, r3 + mvncs r0, #0 + RETc(cs) + ldr r2, Lblock_userspace_access ldr r2, [r2] teq r2, #0 @@ -345,6 +377,11 @@ END(suswintr) */ ENTRY(susword) + ldr r3, =(VM_MAXUSER_ADDRESS-1) + cmp r0, r3 + mvncs r0, #0 + RETc(cs) + GET_PCB(r2) ldr r2, [r2] @@ -376,6 +413,11 @@ END(susword) */ ENTRY(subyte) + ldr r3, =VM_MAXUSER_ADDRESS + cmp r0, r3 + mvncs r0, #0 + RETc(cs) + GET_PCB(r2) ldr r2, [r2] diff --git a/sys/arm/arm/genassym.c b/sys/arm/arm/genassym.c index 900fc4183942..4e2b7e91f235 100644 --- a/sys/arm/arm/genassym.c +++ b/sys/arm/arm/genassym.c @@ -161,6 +161,7 @@ ASSYM(P_VMSPACE, offsetof(struct proc, p_vmspace)); ASSYM(VM_PMAP, offsetof(struct vmspace, vm_pmap)); ASSYM(PM_ACTIVE, offsetof(struct pmap, pm_active)); ASSYM(PC_CPUID, offsetof(struct pcpu, pc_cpuid)); +ASSYM(VM_MAXUSER_ADDRESS, VM_MAXUSER_ADDRESS); ASSYM(DCACHE_LINE_SIZE, offsetof(struct cpuinfo, dcache_line_size)); ASSYM(DCACHE_LINE_MASK, offsetof(struct cpuinfo, dcache_line_mask)); diff --git a/sys/arm/include/param.h b/sys/arm/include/param.h index d3aa01b7ce1c..bbe9bcb08325 100644 --- a/sys/arm/include/param.h +++ b/sys/arm/include/param.h @@ -149,8 +149,4 @@ #define pgtok(x) ((x) * (PAGE_SIZE / 1024)) -#ifdef _KERNEL -#define NO_FUEWORD 1 -#endif - #endif /* !_ARM_INCLUDE_PARAM_H_ */