git: 8babb5582eed - main - riscv: fix VM_MAXUSER_ADDRESS checks in asm routines

From: Mitchell Horne <mhorne_at_FreeBSD.org>
Date: Thu, 07 Oct 2021 21:18:09 UTC
The branch main has been updated by mhorne:

URL: https://cgit.FreeBSD.org/src/commit/?id=8babb5582eed2250309084d76898798409a2aae0

commit 8babb5582eed2250309084d76898798409a2aae0
Author:     Mitchell Horne <mhorne@FreeBSD.org>
AuthorDate: 2021-10-07 21:12:30 +0000
Commit:     Mitchell Horne <mhorne@FreeBSD.org>
CommitDate: 2021-10-07 21:12:30 +0000

    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
---
 sys/riscv/riscv/copyinout.S  |  6 +++---
 sys/riscv/riscv/support.S    | 20 ++++++++++----------
 tests/sys/kern/kern_copyin.c | 24 ++++++++++++++++++++++++
 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)