git: c272720e2a96 - stable/13 - linux(4): Properly build argument list for the signal handler

From: Dmitry Chagin <dchagin_at_FreeBSD.org>
Date: Fri, 17 Jun 2022 19:41:27 UTC
The branch stable/13 has been updated by dchagin:

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

commit c272720e2a96c3648ef37ee139d99d56bccb7fbd
Author:     Dmitry Chagin <dchagin@FreeBSD.org>
AuthorDate: 2022-05-30 16:53:12 +0000
Commit:     Dmitry Chagin <dchagin@FreeBSD.org>
CommitDate: 2022-06-17 19:35:38 +0000

    linux(4): Properly build argument list for the signal handler
    
    Provide arguments 2 and 3 if signal handler installed with SA_SIGINFO.
    
    MFC after:              2 weeks
    
    (cherry picked from commit 109fd18ad96957c25cfaa78da2f825c729e33fef)
---
 sys/amd64/linux/linux_sysvec.c | 28 ++++++++++++++++------------
 sys/arm64/linux/linux_sysvec.c | 12 +++++++++---
 2 files changed, 25 insertions(+), 15 deletions(-)

diff --git a/sys/amd64/linux/linux_sysvec.c b/sys/amd64/linux/linux_sysvec.c
index 8d9557a5aebc..dbf702d51bb1 100644
--- a/sys/amd64/linux/linux_sysvec.c
+++ b/sys/amd64/linux/linux_sysvec.c
@@ -557,13 +557,14 @@ linux_rt_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
 	caddr_t sp;
 	struct trapframe *regs;
 	int sig, code;
-	int oonstack;
+	int oonstack, issiginfo;
 
 	td = curthread;
 	p = td->td_proc;
 	PROC_LOCK_ASSERT(p, MA_OWNED);
 	sig = linux_translate_traps(ksi->ksi_signo, ksi->ksi_trapno);
 	psp = p->p_sigacts;
+	issiginfo = SIGISMEMBER(psp->ps_siginfo, sig);
 	code = ksi->ksi_code;
 	mtx_assert(&psp->ps_mtx, MA_OWNED);
 	regs = td->td_frame;
@@ -615,22 +616,14 @@ linux_rt_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
 	/* Align to 16 bytes. */
 	sfp = (struct l_rt_sigframe *)((unsigned long)sp & ~0xFul);
 
+	mtx_unlock(&psp->ps_mtx);
+	PROC_UNLOCK(p);
+
 	/* Translate the signal. */
 	sig = bsd_to_linux_signal(sig);
-
-	/* Build the argument list for the signal handler. */
-	regs->tf_rdi = sig;			/* arg 1 in %rdi */
-	regs->tf_rax = 0;
-	regs->tf_rsi = (register_t)&sfp->sf_si;	/* arg 2 in %rsi */
-	regs->tf_rdx = (register_t)&sfp->sf_uc;	/* arg 3 in %rdx */
-	regs->tf_rcx = (register_t)catcher;
-
 	/* Fill in POSIX parts. */
 	siginfo_to_lsiginfo(&ksi->ksi_info, &sf.sf_si, sig);
 
-	mtx_unlock(&psp->ps_mtx);
-	PROC_UNLOCK(p);
-
 	/* Copy the sigframe out to the user's stack. */
 	if (copyout(&sf, sfp, sizeof(*sfp)) != 0) {
 		uprintf("pid %d comm %s has trashed its stack, killing\n",
@@ -639,6 +632,17 @@ linux_rt_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
 		sigexit(td, SIGILL);
 	}
 
+	/* Build the argument list for the signal handler. */
+	regs->tf_rdi = sig;			/* arg 1 in %rdi */
+	regs->tf_rax = 0;
+	if (issiginfo) {
+		regs->tf_rsi = (register_t)&sfp->sf_si;	/* arg 2 in %rsi */
+		regs->tf_rdx = (register_t)&sfp->sf_uc;	/* arg 3 in %rdx */
+	} else {
+		regs->tf_rsi = 0;
+		regs->tf_rdx = 0;
+	}
+	regs->tf_rcx = (register_t)catcher;
 	regs->tf_rsp = (long)sfp;
 	regs->tf_rip = linux_rt_sigcode;
 	regs->tf_rflags &= ~(PSL_T | PSL_D);
diff --git a/sys/arm64/linux/linux_sysvec.c b/sys/arm64/linux/linux_sysvec.c
index 85b5ce992ff1..b8361584c31a 100644
--- a/sys/arm64/linux/linux_sysvec.c
+++ b/sys/arm64/linux/linux_sysvec.c
@@ -428,7 +428,7 @@ linux_rt_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
 	ucontext_t uc;
 	uint8_t *scr;
 	struct sigacts *psp;
-	int onstack, sig;
+	int onstack, sig, issiginfo;
 
 	td = curthread;
 	p = td->td_proc;
@@ -440,6 +440,7 @@ linux_rt_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
 
 	tf = td->td_frame;
 	onstack = sigonstack(tf->tf_sp);
+	issiginfo = SIGISMEMBER(psp->ps_siginfo, sig);
 
 	CTR4(KTR_SIG, "sendsig: td=%p (%s) catcher=%p sig=%d", td, p->p_comm,
 	    catcher, sig);
@@ -526,8 +527,13 @@ linux_rt_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
 	free(frame, M_LINUX);
 
 	tf->tf_x[0]= sig;
-	tf->tf_x[1] = (register_t)&fp->sf.sf_si;
-	tf->tf_x[2] = (register_t)&fp->sf.sf_uc;
+	if (issiginfo) {
+		tf->tf_x[1] = (register_t)&fp->sf.sf_si;
+		tf->tf_x[2] = (register_t)&fp->sf.sf_uc;
+	} else {
+		tf->tf_x[1] = 0;
+		tf->tf_x[2] = 0;
+	}
 	tf->tf_x[8] = (register_t)catcher;
 	tf->tf_sp = (register_t)fp;
 	tf->tf_elr = (register_t)linux_vdso_sigcode;