]> xenbits.xensource.com Git - people/julieng/freebsd.git/commitdiff
ARM userspace accessors, e.g. {s,f}uword(9), copy{in,out}(9),
authorkib <kib@FreeBSD.org>
Thu, 15 Oct 2015 17:40:39 +0000 (17:40 +0000)
committerkib <kib@FreeBSD.org>
Thu, 15 Oct 2015 17:40:39 +0000 (17:40 +0000)
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
sys/arm/arm/bcopyinout_xscale.S
sys/arm/arm/copystr.S
sys/arm/arm/fusu.S
sys/arm/arm/genassym.c
sys/arm/include/param.h

index df0484e685c66eed0ab04b316a22958236155643..1c7e0fd6341a866da02474c4e743de3dbedd4e78 100644 (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
index 7a5abb588d632f95c068bde96b86295dd9f5e8b7..79a5027356c0898b40082d73b67a8c0fbeb0b173 100644 (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
index 48c296b0929228974b99e3401052167b2f12a0b4..4cb8469903d89eea95a2572ea7d27f7b053f8f31 100644 (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
 
index 06853c456948aac1e0a0fa476fc360d885d6939c..dee2455a0d34288e263a6a26a4711d3c6cd246b4 100644 (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]
 
index 900fc418394220877d1642077ab18ced6cdd16c2..4e2b7e91f235c5f64758db8a8d7c1789c243d233 100644 (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));
index d3aa01b7ce1c6e45e820b8670e07c8ed2316218a..bbe9bcb08325b76c09ccf85417a44aa728717152 100644 (file)
 
 #define        pgtok(x)                ((x) * (PAGE_SIZE / 1024))
 
-#ifdef _KERNEL
-#define        NO_FUEWORD      1
-#endif
-
 #endif /* !_ARM_INCLUDE_PARAM_H_ */