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
This commit is contained in:
Konstantin Belousov 2015-10-15 17:40:39 +00:00
parent 4d45a6738a
commit 97140827bb
6 changed files with 133 additions and 48 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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]

View File

@ -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));

View File

@ -149,8 +149,4 @@
#define pgtok(x) ((x) * (PAGE_SIZE / 1024))
#ifdef _KERNEL
#define NO_FUEWORD 1
#endif
#endif /* !_ARM_INCLUDE_PARAM_H_ */