aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMitchell Horne <mhorne@FreeBSD.org>2021-10-07 21:12:30 +0000
committerMitchell Horne <mhorne@FreeBSD.org>2021-10-15 15:22:13 +0000
commitd925085dcdbd9dd3953dc1a1c726df8d359705b2 (patch)
tree345d3a7957173aead948fd4b00d7730f4bbbac7f
parent43f5da70cc96161c6f738b4e3a91fbdc44679760 (diff)
downloadsrc-d925085dcdbd9dd3953dc1a1c726df8d359705b2.tar.gz
src-d925085dcdbd9dd3953dc1a1c726df8d359705b2.zip
riscv: fix VM_MAXUSER_ADDRESS checks in asm routines
There are two issues with the checks against VM_MAXUSER_ADDRESS. First, the comparison should consider the values as unsigned, otherwise addresses with the high bit set will fail to branch. Second, the value of VM_MAXUSER_ADDRESS is, by convention, one larger than the maximum mappable user address and invalid itself. Thus, use the bgeu instruction for these comparisons. Add a regression test case for copyin(9). PR: 257193 Reported by: Robert Morris <rtm@lcs.mit.edu> Reviewed by: markj Differential Revision: https://reviews.freebsd.org/D31209 (cherry picked from commit 8babb5582eed2250309084d76898798409a2aae0)
-rw-r--r--sys/riscv/riscv/copyinout.S6
-rw-r--r--sys/riscv/riscv/support.S20
-rw-r--r--tests/sys/kern/kern_copyin.c24
3 files changed, 37 insertions, 13 deletions
diff --git a/sys/riscv/riscv/copyinout.S b/sys/riscv/riscv/copyinout.S
index 1f2a44121ecd..5a171f5a5e17 100644
--- a/sys/riscv/riscv/copyinout.S
+++ b/sys/riscv/riscv/copyinout.S
@@ -118,7 +118,7 @@ ENTRY(copyout)
beqz a2, copyout_end /* If len == 0 then skip loop */
add a3, a1, a2
li a4, VM_MAXUSER_ADDRESS
- bgt a3, a4, copyio_fault_nopcb
+ bgeu a3, a4, copyio_fault_nopcb
copycommon
@@ -136,7 +136,7 @@ ENTRY(copyin)
beqz a2, copyin_end /* If len == 0 then skip loop */
add a3, a0, a2
li a4, VM_MAXUSER_ADDRESS
- bgt a3, a4, copyio_fault_nopcb
+ bgeu a3, a4, copyio_fault_nopcb
copycommon
@@ -159,7 +159,7 @@ ENTRY(copyinstr)
ENTER_USER_ACCESS(a7)
li a7, VM_MAXUSER_ADDRESS
-1: bgt a0, a7, copyio_fault
+1: bgeu a0, a7, copyio_fault
lb a4, 0(a0) /* Load from uaddr */
addi a0, a0, 1
sb a4, 0(a1) /* Store in kaddr */
diff --git a/sys/riscv/riscv/support.S b/sys/riscv/riscv/support.S
index 3f0ec08ac768..7fcd6af283b7 100644
--- a/sys/riscv/riscv/support.S
+++ b/sys/riscv/riscv/support.S
@@ -56,7 +56,7 @@ END(fsu_fault)
*/
ENTRY(casueword32)
li a4, (VM_MAXUSER_ADDRESS-3)
- bgt a0, a4, fsu_fault_nopcb
+ bgeu a0, a4, fsu_fault_nopcb
la a6, fsu_fault /* Load the fault handler */
SET_FAULT_HANDLER(a6, a4) /* And set it */
ENTER_USER_ACCESS(a4)
@@ -77,7 +77,7 @@ END(casueword32)
*/
ENTRY(casueword)
li a4, (VM_MAXUSER_ADDRESS-7)
- bgt a0, a4, fsu_fault_nopcb
+ bgeu a0, a4, fsu_fault_nopcb
la a6, fsu_fault /* Load the fault handler */
SET_FAULT_HANDLER(a6, a4) /* And set it */
ENTER_USER_ACCESS(a4)
@@ -98,7 +98,7 @@ END(casueword)
*/
ENTRY(fubyte)
li a1, VM_MAXUSER_ADDRESS
- bgt a0, a1, fsu_fault_nopcb
+ bgeu a0, a1, fsu_fault_nopcb
la a6, fsu_fault /* Load the fault handler */
SET_FAULT_HANDLER(a6, a1) /* And set it */
ENTER_USER_ACCESS(a1)
@@ -113,7 +113,7 @@ END(fubyte)
*/
ENTRY(fuword16)
li a1, (VM_MAXUSER_ADDRESS-1)
- bgt a0, a1, fsu_fault_nopcb
+ bgeu a0, a1, fsu_fault_nopcb
la a6, fsu_fault /* Load the fault handler */
SET_FAULT_HANDLER(a6, a1) /* And set it */
ENTER_USER_ACCESS(a1)
@@ -128,7 +128,7 @@ END(fuword16)
*/
ENTRY(fueword32)
li a2, (VM_MAXUSER_ADDRESS-3)
- bgt a0, a2, fsu_fault_nopcb
+ bgeu a0, a2, fsu_fault_nopcb
la a6, fsu_fault /* Load the fault handler */
SET_FAULT_HANDLER(a6, a2) /* And set it */
ENTER_USER_ACCESS(a2)
@@ -147,7 +147,7 @@ END(fueword32)
ENTRY(fueword)
EENTRY(fueword64)
li a2, (VM_MAXUSER_ADDRESS-7)
- bgt a0, a2, fsu_fault_nopcb
+ bgeu a0, a2, fsu_fault_nopcb
la a6, fsu_fault /* Load the fault handler */
SET_FAULT_HANDLER(a6, a2) /* And set it */
ENTER_USER_ACCESS(a2)
@@ -165,7 +165,7 @@ END(fueword)
*/
ENTRY(subyte)
li a2, VM_MAXUSER_ADDRESS
- bgt a0, a2, fsu_fault_nopcb
+ bgeu a0, a2, fsu_fault_nopcb
la a6, fsu_fault /* Load the fault handler */
SET_FAULT_HANDLER(a6, a2) /* And set it */
ENTER_USER_ACCESS(a2)
@@ -181,7 +181,7 @@ END(subyte)
*/
ENTRY(suword16)
li a2, (VM_MAXUSER_ADDRESS-1)
- bgt a0, a2, fsu_fault_nopcb
+ bgeu a0, a2, fsu_fault_nopcb
la a6, fsu_fault /* Load the fault handler */
SET_FAULT_HANDLER(a6, a2) /* And set it */
ENTER_USER_ACCESS(a2)
@@ -197,7 +197,7 @@ END(suword16)
*/
ENTRY(suword32)
li a2, (VM_MAXUSER_ADDRESS-3)
- bgt a0, a2, fsu_fault_nopcb
+ bgeu a0, a2, fsu_fault_nopcb
la a6, fsu_fault /* Load the fault handler */
SET_FAULT_HANDLER(a6, a2) /* And set it */
ENTER_USER_ACCESS(a2)
@@ -214,7 +214,7 @@ END(suword32)
ENTRY(suword)
EENTRY(suword64)
li a2, (VM_MAXUSER_ADDRESS-7)
- bgt a0, a2, fsu_fault_nopcb
+ bgeu a0, a2, fsu_fault_nopcb
la a6, fsu_fault /* Load the fault handler */
SET_FAULT_HANDLER(a6, a2) /* And set it */
ENTER_USER_ACCESS(a2)
diff --git a/tests/sys/kern/kern_copyin.c b/tests/sys/kern/kern_copyin.c
index b77360e928fd..eb1fea315b5a 100644
--- a/tests/sys/kern/kern_copyin.c
+++ b/tests/sys/kern/kern_copyin.c
@@ -34,6 +34,7 @@ __FBSDID("$FreeBSD$");
#include <sys/exec.h>
#include <sys/sysctl.h>
#include <errno.h>
+#include <fcntl.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
@@ -54,6 +55,21 @@ copyin_checker(uintptr_t uaddr, size_t len)
return (ret == -1 ? errno : 0);
}
+#if __SIZEOF_POINTER__ == 8
+/*
+ * A slightly more direct path to calling copyin(), but without the ability
+ * to specify a length.
+ */
+static int
+copyin_checker2(uintptr_t uaddr)
+{
+ int ret;
+
+ ret = fcntl(scratch_file, F_GETLK, (const void *)uaddr);
+ return (ret == -1 ? errno : 0);
+}
+#endif
+
#ifdef __amd64__
static uintptr_t
get_maxuser_address(void)
@@ -83,6 +99,10 @@ get_maxuser_address(void)
#endif
#define FMAX ULONG_MAX
+#if __SIZEOF_POINTER__ == 8
+/* PR 257193 */
+#define ADDR_SIGNED 0x800000c000000000
+#endif
ATF_TC_WITHOUT_HEAD(kern_copyin);
ATF_TC_BODY(kern_copyin, tc)
@@ -122,6 +142,10 @@ ATF_TC_BODY(kern_copyin, tc)
ATF_CHECK(copyin_checker(FMAX - 10, 9) == EFAULT);
ATF_CHECK(copyin_checker(FMAX - 10, 10) == EFAULT);
ATF_CHECK(copyin_checker(FMAX - 10, 11) == EFAULT);
+#if __SIZEOF_POINTER__ == 8
+ ATF_CHECK(copyin_checker(ADDR_SIGNED, 1) == EFAULT);
+ ATF_CHECK(copyin_checker2(ADDR_SIGNED) == EFAULT);
+#endif
}
ATF_TP_ADD_TCS(tp)