[5.16.0-rc2] Kernel warning while running sigfuz w/PPC_IRQ_SOFT_MASK_DEBUG

Nicholas Piggin npiggin at gmail.com
Thu Nov 25 23:22:31 AEDT 2021


Excerpts from Sachin Sant's message of November 25, 2021 9:37 pm:
> While running sigfuz powerpc self test following warning is seen on a Power 10 LPAR. 
> This warning is seen only with CONFIG_PPC_IRQ_SOFT_MASK_DEBUG=y
> The kernel eventually panics.
> 
> [ 1032.912973] sigfuz[2061671]: bad frame in rt_sigreturn: 0000000097830b2d nip 00007fff9d9a0470 lr 00007fff9d9a0464
> [ 1032.913430] ------------[ cut here ]------------
> [ 1032.913455] WARNING: CPU: 6 PID: 2061674 at arch/powerpc/kernel/interrupt_64.S:34 system_call_common+0x150/0x268
> [ 1032.913482] Modules linked in: bonding tls nft_fib_inet nft_fib_ipv4 nft_fib_ipv6 nft_fib nft_reject_inet nf_reject_ipv4 nf_reject_ipv6 nft_reject nft_ct nft_chain_nat nf_nat nf_conntrack nf_defrag_ipv6 nf_defrag_ipv4 ip_set nf_tables rfkill libcrc32c nfnetlink sunrpc xts vmx_crypto pseries_rng ip_tables ext4 mbcache jbd2 dm_service_time sd_mod t10_pi sg ibmvfc scsi_transport_fc ibmveth dm_multipath dm_mirror dm_region_hash dm_log dm_mod fuse
> [ 1032.913587] CPU: 6 PID: 2061674 Comm: sigfuz Not tainted 5.16.0-rc2-g95c6ab13ec7e #1
> [ 1032.913612] NIP:  c00000000000c730 LR: 0000000045faa436 CTR: 0000000000000000
> [ 1032.913636] REGS: c00000000c7e7b70 TRAP: 0700   Not tainted  (5.16.0-rc2-g95c6ab13ec7e)
> [ 1032.913652] MSR:  800000000282b033 <SF,VEC,VSX,EE,FP,ME,IR,DR,RI,LE>  CR: 28004474  XER: 20040000
> [ 1032.913679] CFAR: c00000000003a2d4 IRQMASK: 0 
> [ 1032.913679] GPR00: c00000000000c6d8 c00000000c7e7e10 000000002fcdac67 0000000000000800 
> [ 1032.913679] GPR04: 0000000060d67006 800000000280f032 0000000045faa436 c0000001eb3d4c00 
> [ 1032.913679] GPR08: 800000000280f032 0000000000000001 0000000000000001 0000000060d67004 
> [ 1032.913679] GPR12: 0000000060d67006 c00000077fdf2300 0000000000000000 00007fff9da00000 

SRR0 == r11, regs->nip == r12

I wonder if this is just that SRR0 does not implement the bottom 2 bits 
so the check fails when the signal context sets them. Hopefully the 
panic is just due to this warning 0x700 program check hitting at a bad
time.

We could always adjust the debug check but maybe something like this 
would keep those bits clear which might be cleaner.

Thanks,
Nick

diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c
index 3e053e2fd6b6..92a3a6982813 100644
--- a/arch/powerpc/kernel/signal_32.c
+++ b/arch/powerpc/kernel/signal_32.c
@@ -116,7 +116,7 @@ __unsafe_restore_general_regs(struct pt_regs *regs, struct mcontext __user *sr)
 	int i;
 
 	for (i = 0; i <= PT_RESULT; i++) {
-		if ((i == PT_MSR) || (i == PT_SOFTE))
+		if ((i == PT_NIP) || (i == PT_MSR) || (i == PT_SOFTE))
 			continue;
 		unsafe_get_user(gregs[i], &sr->mc_gregs[i], failed);
 	}
@@ -156,7 +156,7 @@ static __always_inline
 int __unsafe_restore_general_regs(struct pt_regs *regs, struct mcontext __user *sr)
 {
 	/* copy up to but not including MSR */
-	unsafe_copy_from_user(regs, &sr->mc_gregs, PT_MSR * sizeof(elf_greg_t), failed);
+	unsafe_copy_from_user(regs, &sr->mc_gregs, PT_NIP * sizeof(elf_greg_t), failed);
 
 	/* copy from orig_r3 (the word after the MSR) up to the end */
 	unsafe_copy_from_user(&regs->orig_gpr3, &sr->mc_gregs[PT_ORIG_R3],
@@ -458,7 +458,7 @@ static long restore_user_regs(struct pt_regs *regs,
 			      struct mcontext __user *sr, int sig)
 {
 	unsigned int save_r2 = 0;
-	unsigned long msr;
+	unsigned long nip, msr;
 #ifdef CONFIG_VSX
 	int i;
 #endif
@@ -473,6 +473,8 @@ static long restore_user_regs(struct pt_regs *regs,
 		save_r2 = (unsigned int)regs->gpr[2];
 	unsafe_restore_general_regs(regs, sr, failed);
 	set_trap_norestart(regs);
+	unsafe_get_user(nip, &sr->mc_gregs[PT_NIP], failed);
+	regs_set_return_ip(regs, nip & ~3);
 	unsafe_get_user(msr, &sr->mc_gregs[PT_MSR], failed);
 	if (!sig)
 		regs->gpr[2] = (unsigned long) save_r2;
@@ -560,7 +562,7 @@ static long restore_tm_user_regs(struct pt_regs *regs,
 				 struct mcontext __user *sr,
 				 struct mcontext __user *tm_sr)
 {
-	unsigned long msr, msr_hi;
+	unsigned long nip, msr, msr_hi;
 	int i;
 
 	if (tm_suspend_disabled)
@@ -576,7 +578,8 @@ static long restore_tm_user_regs(struct pt_regs *regs,
 		return 1;
 
 	unsafe_restore_general_regs(&current->thread.ckpt_regs, sr, failed);
-	unsafe_get_user(current->thread.tm_tfhar, &sr->mc_gregs[PT_NIP], failed);
+	unsafe_get_user(nip, &sr->mc_gregs[PT_NIP], failed);
+	current->thread.tm_tfhar = nip & ~3;
 	unsafe_get_user(msr, &sr->mc_gregs[PT_MSR], failed);
 
 	/* Restore the previous little-endian mode */
@@ -646,6 +649,9 @@ static long restore_tm_user_regs(struct pt_regs *regs,
 		current->thread.used_vsr = true;
 	}
 
+	unsafe_get_user(nip, &tm_sr->mc_gregs[PT_NIP], failed);
+	regs_set_return_ip(regs, nip & ~3);
+
 	/* Get the top half of the MSR from the user context */
 	unsafe_get_user(msr_hi, &tm_sr->mc_gregs[PT_MSR], failed);
 	msr_hi <<= 32;
@@ -801,7 +807,7 @@ int handle_rt_signal32(struct ksignal *ksig, sigset_t *oldset,
 	regs->gpr[4] = (unsigned long)&frame->info;
 	regs->gpr[5] = (unsigned long)&frame->uc;
 	regs->gpr[6] = (unsigned long)frame;
-	regs_set_return_ip(regs, (unsigned long) ksig->ka.sa.sa_handler);
+	regs_set_return_ip(regs, (unsigned long) ksig->ka.sa.sa_handler & ~3);
 	/* enter the signal handler in native-endian mode */
 	regs_set_return_msr(regs, (regs->msr & ~MSR_LE) | (MSR_KERNEL & MSR_LE));
 
@@ -889,7 +895,7 @@ int handle_signal32(struct ksignal *ksig, sigset_t *oldset,
 	regs->gpr[1] = newsp;
 	regs->gpr[3] = ksig->sig;
 	regs->gpr[4] = (unsigned long) sc;
-	regs_set_return_ip(regs, (unsigned long) ksig->ka.sa.sa_handler);
+	regs_set_return_ip(regs, (unsigned long) ksig->ka.sa.sa_handler & ~3);
 	/* enter the signal handler in native-endian mode */
 	regs_set_return_msr(regs, (regs->msr & ~MSR_LE) | (MSR_KERNEL & MSR_LE));
 
diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c
index d1e1fc0acbea..0327e5c79c36 100644
--- a/arch/powerpc/kernel/signal_64.c
+++ b/arch/powerpc/kernel/signal_64.c
@@ -336,7 +336,7 @@ static long notrace __unsafe_restore_sigcontext(struct task_struct *tsk, sigset_
 	elf_vrreg_t __user *v_regs;
 #endif
 	unsigned long save_r13 = 0;
-	unsigned long msr;
+	unsigned long nip, msr;
 	struct pt_regs *regs = tsk->thread.regs;
 #ifdef CONFIG_VSX
 	int i;
@@ -350,7 +350,8 @@ static long notrace __unsafe_restore_sigcontext(struct task_struct *tsk, sigset_
 
 	/* copy the GPRs */
 	unsafe_copy_from_user(regs->gpr, sc->gp_regs, sizeof(regs->gpr), efault_out);
-	unsafe_get_user(regs->nip, &sc->gp_regs[PT_NIP], efault_out);
+	unsafe_get_user(nip, &sc->gp_regs[PT_NIP], efault_out);
+	regs_set_return_ip(regs, nip & ~3);
 	/* get MSR separately, transfer the LE bit if doing signal return */
 	unsafe_get_user(msr, &sc->gp_regs[PT_MSR], efault_out);
 	if (sig)
@@ -434,7 +435,7 @@ static long restore_tm_sigcontexts(struct task_struct *tsk,
 	elf_vrreg_t __user *v_regs, *tm_v_regs;
 #endif
 	unsigned long err = 0;
-	unsigned long msr;
+	unsigned long nip, msr;
 	struct pt_regs *regs = tsk->thread.regs;
 #ifdef CONFIG_VSX
 	int i;
@@ -458,8 +459,10 @@ static long restore_tm_sigcontexts(struct task_struct *tsk,
 	 * For the case of getting a signal and simply returning from it,
 	 * we don't need to re-copy them here.
 	 */
-	err |= __get_user(regs->nip, &tm_sc->gp_regs[PT_NIP]);
-	err |= __get_user(tsk->thread.tm_tfhar, &sc->gp_regs[PT_NIP]);
+	err |= __get_user(nip, &tm_sc->gp_regs[PT_NIP]);
+	regs_set_return_ip(regs, nip & ~3);
+	err |= __get_user(nip, &sc->gp_regs[PT_NIP]);
+	tsk->thread.tm_tfhar = nip & ~3;
 
 	/* get MSR separately, transfer the LE bit if doing signal return */
 	err |= __get_user(msr, &sc->gp_regs[PT_MSR]);


More information about the Linuxppc-dev mailing list