git: 7b68fb5ab2a2 - main - thread: Add a return value to cpu_set_upcall()

From: Mark Johnston <markj_at_FreeBSD.org>
Date: Tue, 26 Dec 2023 02:04:19 UTC
The branch main has been updated by markj:

URL: https://cgit.FreeBSD.org/src/commit/?id=7b68fb5ab2a276ccd081cc1a43cebf0fb315e952

commit 7b68fb5ab2a276ccd081cc1a43cebf0fb315e952
Author:     Mark Johnston <markj@FreeBSD.org>
AuthorDate: 2023-12-26 01:39:39 +0000
Commit:     Mark Johnston <markj@FreeBSD.org>
CommitDate: 2023-12-26 02:04:00 +0000

    thread: Add a return value to cpu_set_upcall()
    
    Some implementations copy data to userspace, an operation which can in
    principle fail.  In preparation for adding a __result_use_check
    annotation to copyin() and related functions, let implementations of
    cpu_set_upcall() return an error, and check for errors when copying data
    to user memory.
    
    Reviewed by:    kib, jhb
    MFC after:      1 week
    Differential Revision:  https://reviews.freebsd.org/D43100
---
 sys/amd64/amd64/vm_machdep.c       | 19 ++++++++++++-------
 sys/arm/arm/vm_machdep.c           |  3 ++-
 sys/arm64/arm64/vm_machdep.c       |  3 ++-
 sys/i386/i386/vm_machdep.c         | 11 +++++++----
 sys/kern/kern_thr.c                |  5 ++++-
 sys/powerpc/powerpc/exec_machdep.c |  3 ++-
 sys/riscv/riscv/vm_machdep.c       |  3 ++-
 sys/sys/proc.h                     |  2 +-
 8 files changed, 32 insertions(+), 17 deletions(-)

diff --git a/sys/amd64/amd64/vm_machdep.c b/sys/amd64/amd64/vm_machdep.c
index 6173aabd97f5..c6b78824d730 100644
--- a/sys/amd64/amd64/vm_machdep.c
+++ b/sys/amd64/amd64/vm_machdep.c
@@ -611,7 +611,7 @@ cpu_copy_thread(struct thread *td, struct thread *td0)
  * Set that machine state for performing an upcall that starts
  * the entry function with the given argument.
  */
-void
+int
 cpu_set_upcall(struct thread *td, void (*entry)(void *), void *arg,
     stack_t *stack)
 {
@@ -637,13 +637,15 @@ cpu_set_upcall(struct thread *td, void (*entry)(void *), void *arg,
 		td->td_frame->tf_rip = (uintptr_t)entry;
 
 		/* Return address sentinel value to stop stack unwinding. */
-		suword32((void *)td->td_frame->tf_rsp, 0);
+		if (suword32((void *)td->td_frame->tf_rsp, 0) != 0)
+			return (EFAULT);
 
 		/* Pass the argument to the entry point. */
-		suword32((void *)(td->td_frame->tf_rsp + sizeof(int32_t)),
-		    (uint32_t)(uintptr_t)arg);
-
-		return;
+		if (suword32(
+		    (void *)(td->td_frame->tf_rsp + sizeof(int32_t)),
+		    (uint32_t)(uintptr_t)arg) != 0)
+			return (EFAULT);
+		return (0);
 	}
 #endif
 
@@ -663,10 +665,13 @@ cpu_set_upcall(struct thread *td, void (*entry)(void *), void *arg,
 	td->td_frame->tf_flags = TF_HASSEGS;
 
 	/* Return address sentinel value to stop stack unwinding. */
-	suword((void *)td->td_frame->tf_rsp, 0);
+	if (suword((void *)td->td_frame->tf_rsp, 0) != 0)
+		return (EFAULT);
 
 	/* Pass the argument to the entry point. */
 	td->td_frame->tf_rdi = (register_t)arg;
+
+	return (0);
 }
 
 int
diff --git a/sys/arm/arm/vm_machdep.c b/sys/arm/arm/vm_machdep.c
index e9822c8345a5..1dd01f6700aa 100644
--- a/sys/arm/arm/vm_machdep.c
+++ b/sys/arm/arm/vm_machdep.c
@@ -224,7 +224,7 @@ cpu_copy_thread(struct thread *td, struct thread *td0)
  * Set that machine state for performing an upcall that starts
  * the entry function with the given argument.
  */
-void
+int
 cpu_set_upcall(struct thread *td, void (*entry)(void *), void *arg,
 	stack_t *stack)
 {
@@ -236,6 +236,7 @@ cpu_set_upcall(struct thread *td, void (*entry)(void *), void *arg,
 	tf->tf_spsr = PSR_USR32_MODE;
 	if ((register_t)entry & 1)
 		tf->tf_spsr |= PSR_T;
+	return (0);
 }
 
 int
diff --git a/sys/arm64/arm64/vm_machdep.c b/sys/arm64/arm64/vm_machdep.c
index 9fa5406ad828..385bec00ada5 100644
--- a/sys/arm64/arm64/vm_machdep.c
+++ b/sys/arm64/arm64/vm_machdep.c
@@ -205,7 +205,7 @@ cpu_copy_thread(struct thread *td, struct thread *td0)
  * Set that machine state for performing an upcall that starts
  * the entry function with the given argument.
  */
-void
+int
 cpu_set_upcall(struct thread *td, void (*entry)(void *), void *arg,
 	stack_t *stack)
 {
@@ -224,6 +224,7 @@ cpu_set_upcall(struct thread *td, void (*entry)(void *), void *arg,
 	tf->tf_x[0] = (register_t)arg;
 	tf->tf_x[29] = 0;
 	tf->tf_lr = 0;
+	return (0);
 }
 
 int
diff --git a/sys/i386/i386/vm_machdep.c b/sys/i386/i386/vm_machdep.c
index 778e666b9029..2c2fb9dc9821 100644
--- a/sys/i386/i386/vm_machdep.c
+++ b/sys/i386/i386/vm_machdep.c
@@ -486,7 +486,7 @@ cpu_copy_thread(struct thread *td, struct thread *td0)
  * Set that machine state for performing an upcall that starts
  * the entry function with the given argument.
  */
-void
+int
 cpu_set_upcall(struct thread *td, void (*entry)(void *), void *arg,
     stack_t *stack)
 {
@@ -510,11 +510,14 @@ cpu_set_upcall(struct thread *td, void (*entry)(void *), void *arg,
 	td->td_frame->tf_eip = (int)entry;
 
 	/* Return address sentinel value to stop stack unwinding. */
-	suword((void *)td->td_frame->tf_esp, 0);
+	if (suword((void *)td->td_frame->tf_esp, 0) != 0)
+		return (EFAULT);
 
 	/* Pass the argument to the entry point. */
-	suword((void *)(td->td_frame->tf_esp + sizeof(void *)),
-	    (int)arg);
+	if (suword((void *)(td->td_frame->tf_esp + sizeof(void *)),
+	    (int)arg) != 0)
+		return (EFAULT);
+	return (0);
 }
 
 int
diff --git a/sys/kern/kern_thr.c b/sys/kern/kern_thr.c
index d75305ea5020..544479fc9f13 100644
--- a/sys/kern/kern_thr.c
+++ b/sys/kern/kern_thr.c
@@ -146,6 +146,7 @@ thr_new_initthr(struct thread *td, void *thunk)
 {
 	stack_t stack;
 	struct thr_param *param;
+	int error;
 
 	/*
 	 * Here we copy out tid to two places, one for child and one
@@ -165,7 +166,9 @@ thr_new_initthr(struct thread *td, void *thunk)
 	stack.ss_sp = param->stack_base;
 	stack.ss_size = param->stack_size;
 	/* Set upcall address to user thread entry function. */
-	cpu_set_upcall(td, param->start_func, param->arg, &stack);
+	error = cpu_set_upcall(td, param->start_func, param->arg, &stack);
+	if (error != 0)
+		return (error);
 	/* Setup user TLS address and TLS pointer register. */
 	return (cpu_set_user_tls(td, param->tls_base));
 }
diff --git a/sys/powerpc/powerpc/exec_machdep.c b/sys/powerpc/powerpc/exec_machdep.c
index 0b1751a76454..0c10115c4e25 100644
--- a/sys/powerpc/powerpc/exec_machdep.c
+++ b/sys/powerpc/powerpc/exec_machdep.c
@@ -1149,7 +1149,7 @@ cpu_copy_thread(struct thread *td, struct thread *td0)
 	td->td_md.md_saved_msr = psl_kernset;
 }
 
-void
+int
 cpu_set_upcall(struct thread *td, void (*entry)(void *), void *arg,
     stack_t *stack)
 {
@@ -1201,6 +1201,7 @@ cpu_set_upcall(struct thread *td, void (*entry)(void *), void *arg,
 
 	td->td_retval[0] = (register_t)entry;
 	td->td_retval[1] = 0;
+	return (0);
 }
 
 static int
diff --git a/sys/riscv/riscv/vm_machdep.c b/sys/riscv/riscv/vm_machdep.c
index b4a7f1c489af..f6d6f61bdc84 100644
--- a/sys/riscv/riscv/vm_machdep.c
+++ b/sys/riscv/riscv/vm_machdep.c
@@ -178,7 +178,7 @@ cpu_copy_thread(struct thread *td, struct thread *td0)
  * Set that machine state for performing an upcall that starts
  * the entry function with the given argument.
  */
-void
+int
 cpu_set_upcall(struct thread *td, void (*entry)(void *), void *arg,
 	stack_t *stack)
 {
@@ -189,6 +189,7 @@ cpu_set_upcall(struct thread *td, void (*entry)(void *), void *arg,
 	tf->tf_sp = STACKALIGN((uintptr_t)stack->ss_sp + stack->ss_size);
 	tf->tf_sepc = (register_t)entry;
 	tf->tf_a[0] = (register_t)arg;
+	return (0);
 }
 
 int
diff --git a/sys/sys/proc.h b/sys/sys/proc.h
index 3f5f76862573..e7d2a1775603 100644
--- a/sys/sys/proc.h
+++ b/sys/sys/proc.h
@@ -1257,7 +1257,7 @@ void	cpu_fork_kthread_handler(struct thread *, void (*)(void *), void *);
 int	cpu_procctl(struct thread *td, int idtype, id_t id, int com,
 	    void *data);
 void	cpu_set_syscall_retval(struct thread *, int);
-void	cpu_set_upcall(struct thread *, void (*)(void *), void *,
+int	cpu_set_upcall(struct thread *, void (*)(void *), void *,
 	    stack_t *);
 int	cpu_set_user_tls(struct thread *, void *tls_base);
 void	cpu_thread_alloc(struct thread *);