git: d94ff663b6a6 - stable/14 - arm: Fix VFP state corruption during signal delivery

From: Michal Meloun <mmel_at_FreeBSD.org>
Date: Sun, 08 Dec 2024 13:37:47 UTC
The branch stable/14 has been updated by mmel:

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

commit d94ff663b6a6e208af2bc27474e00d96659fcb41
Author:     Michal Meloun <mmel@FreeBSD.org>
AuthorDate: 2024-11-26 11:08:21 +0000
Commit:     Michal Meloun <mmel@FreeBSD.org>
CommitDate: 2024-12-08 10:36:38 +0000

    arm: Fix VFP state corruption during signal delivery
    
    D37419 corrupts VFP context store on signal delivery and D38696 corrupts PCB
    because it performs a binary copy between structures with different layouts.
    Revert the problematic parts of these commits to have signals delivery
    working. Unfortunately, there are more problems with these revisions and
    more fixes need to be developed.
    
    Fixes: 6926e2699ae55080f860488895a2a9aa6e6d9b4d
    Fixes: 4d2427f2c4451babe1bad600ae02c8a7c66031fe
    MFC after:      4 weeks
    
    (cherry picked from commit 3abef90c325dc9badc51cc0e195db3fd5548ff53)
---
 sys/arm/arm/exec_machdep.c | 42 ++++++++++++++++++++++++------------------
 1 file changed, 24 insertions(+), 18 deletions(-)

diff --git a/sys/arm/arm/exec_machdep.c b/sys/arm/arm/exec_machdep.c
index 6f52e1724a5c..258526d03ff5 100644
--- a/sys/arm/arm/exec_machdep.c
+++ b/sys/arm/arm/exec_machdep.c
@@ -102,14 +102,19 @@ get_vfpcontext(struct thread *td, mcontext_vfp_t *vfp)
 	    P_SHOULDSTOP(td->td_proc));
 
 	pcb = td->td_pcb;
-	if ((pcb->pcb_fpflags & PCB_FP_STARTED) != 0 && td == curthread) {
+	if (td == curthread) {
 		critical_enter();
 		vfp_store(&pcb->pcb_vfpstate, false);
 		critical_exit();
 	}
 	KASSERT(pcb->pcb_vfpsaved == &pcb->pcb_vfpstate,
 		("Called get_vfpcontext while the kernel is using the VFP"));
-	memcpy(vfp, &pcb->pcb_vfpstate, sizeof(*vfp));
+
+	memset(vfp, 0, sizeof(*vfp));
+	memcpy(vfp->mcv_reg, pcb->pcb_vfpstate.reg,
+	    sizeof(vfp->mcv_reg));
+	vfp->mcv_fpscr = pcb->pcb_vfpstate.fpscr;
+
 }
 
 /*
@@ -128,7 +133,10 @@ set_vfpcontext(struct thread *td, mcontext_vfp_t *vfp)
 	}
 	KASSERT(pcb->pcb_vfpsaved == &pcb->pcb_vfpstate,
 		("Called set_vfpcontext while the kernel is using the VFP"));
-	memcpy(&pcb->pcb_vfpstate, vfp, sizeof(*vfp));
+	memcpy(pcb->pcb_vfpstate.reg, vfp->mcv_reg,
+	    sizeof(pcb->pcb_vfpstate.reg));
+	pcb->pcb_vfpstate.fpscr = vfp->mcv_fpscr;
+
 }
 #endif
 
@@ -164,8 +172,6 @@ get_mcontext(struct thread *td, mcontext_t *mcp, int clear_ret)
 {
 	struct trapframe *tf = td->td_frame;
 	__greg_t *gr = mcp->__gregs;
-	mcontext_vfp_t	mcontext_vfp;
-	int rv;
 
 	if (clear_ret & GET_MC_CLEAR_RET) {
 		gr[_REG_R0] = 0;
@@ -190,19 +196,9 @@ get_mcontext(struct thread *td, mcontext_t *mcp, int clear_ret)
 	gr[_REG_LR]   = tf->tf_usr_lr;
 	gr[_REG_PC]   = tf->tf_pc;
 
-#ifdef VFP
-	if (mcp->mc_vfp_size != sizeof(mcontext_vfp_t))
-		return (EINVAL);
-	get_vfpcontext(td, &mcontext_vfp);
-#else
-	bzero(&mcontext_vfp, sizeof(mcontext_vfp));
-#endif
-
-	if (mcp->mc_vfp_ptr != NULL) {
-		rv = copyout(&mcontext_vfp, mcp->mc_vfp_ptr,  sizeof(mcontext_vfp));
-		if (rv != 0)
-			return (rv);
-	}
+	mcp->mc_vfp_size = 0;
+	mcp->mc_vfp_ptr = NULL;
+	memset(&mcp->mc_spare, 0, sizeof(mcp->mc_spare));
 
 	return (0);
 }
@@ -316,6 +312,16 @@ sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
 	/* Populate the siginfo frame. */
 	bzero(&frame, sizeof(frame));
 	get_mcontext(td, &frame.sf_uc.uc_mcontext, 0);
+
+#ifdef VFP
+	get_vfpcontext(td, &frame.sf_vfp);
+	frame.sf_uc.uc_mcontext.mc_vfp_size = sizeof(fp->sf_vfp);
+	frame.sf_uc.uc_mcontext.mc_vfp_ptr = &fp->sf_vfp;
+#else
+	frame.sf_uc.uc_mcontext.mc_vfp_size = 0;
+	frame.sf_uc.uc_mcontext.mc_vfp_ptr = NULL;
+#endif
+
 	frame.sf_si = ksi->ksi_info;
 	frame.sf_uc.uc_sigmask = *mask;
 	frame.sf_uc.uc_stack = td->td_sigstk;