powerpc/signal: Convert to scoped user access
Christophe Leroy (CS GROUP)
reviewerv2 cover powerpc/signal: Convert to scoped user access
This series converts powerpc architecture signal handling to scoped user access and enlarges some of the block accesses to minimise the number of times user access has to be opened and closed.
As mentioned in individual patches, some bring real performance improvement.
This series is built from previous series [1] which predates implementation of scoped user access.
Changes in v2:
- Add a stub setup_tm_sigcontexts() for when CONFIG_PPC_TRANSACTIONAL_MEM is not set in patch 2
Christophe Leroy (CS GROUP) (8):
powerpc/signal32: Convert to scoped user access powerpc/signal64: Untangle setup_tm_sigcontexts() and
user_access_begin()
powerpc/signal64: Convert to scoped user access powerpc/signal64: Access function descriptor with scoped user access powerpc/signal: Include the new stack frame inside the user access
block
signal: Add unsafe_copy_siginfo_to_user() powerpc/uaccess: Add unsafe_clear_user()
powerpc/signal: Use unsafe_copy_siginfo_to_user()
arch/powerpc/include/asm/uaccess.h | 20 ++ arch/powerpc/kernel/signal_32.c | 498 ++++++++++++++--------------- arch/powerpc/kernel/signal_64.c | 138 ++++---- include/linux/signal.h | 15 + include/linux/uaccess.h | 1 + kernel/signal.c | 5 - 6 files changed, 334 insertions(+), 343 deletions(-)
Signature · 1 line
2.54.0
Christophe Leroy (CS GROUP)
reviewerPATCH v2 1/8 powerpc/signal32: Convert to scoped user access
Commit 861574d51bbd ("powerpc/uaccess: Implement masked user access") provides optimised user access by avoiding the cost of access_ok().
Convert signal32 functions to scoped user access.
Scoped user access also make the code simpler.
--- arch/powerpc/kernel/signal_32.c | 456 +++++++++++++++----------------- 1 file changed, 217 insertions(+), 239 deletions(-)
arch/powerpc/kernel/signal_32.c +217 -239
@@ -468,98 +468,98 @@ static long restore_user_regs(struct pt_regs *regs, {unsigned int save_r2 =0 ;unsigned long msr; -#ifdef CONFIG_VSX -int i; -#endif -if (!user_read_access_begin (sr,sizeof (*sr))) -return 1 ; -/* -* restore general registers but not including MSR or SOFTE. Also -* take care of keeping r2 (TLS) intact if not a signal -*/ -if (!sig) - save_r2 = (unsigned int )regs->gpr[2 ]; -unsafe_restore_general_regs (regs, sr, failed); -set_trap_norestart (regs); -unsafe_get_user (msr, &sr->mc_gregs[PT_MSR ], failed); -if (!sig) - regs->gpr[2 ] = (unsigned long ) save_r2; - -/* if doing signal return, restore the previous little-endian mode */ -if (sig) -regs_set_return_msr (regs, (regs->msr & ~MSR_LE ) | (msr &MSR_LE )); + scoped_user_read_access(sr, failed) { +/* +* restore general registers but not including MSR or SOFTE. Also +* take care of keeping r2 (TLS) intact if not a signal +*/ +if (!sig) + save_r2 = (unsigned int )regs->gpr[2 ]; +unsafe_restore_general_regs (regs, sr, failed); +set_trap_norestart (regs); +unsafe_get_user (msr, &sr->mc_gregs[PT_MSR ], failed); +if (!sig) + regs->gpr[2 ] = (unsigned long )save_r2; + +/* if doing signal return, restore the previous little-endian mode */ +if (sig) +regs_set_return_msr (regs, (regs->msr & ~MSR_LE ) | (msr &MSR_LE ));#ifdef CONFIG_ALTIVEC -/* -* Force the process to reload the altivec registers from -* current->thread when it next does altivec instructions -*/ -regs_set_return_msr (regs, regs->msr & ~MSR_VEC ); -if (msr &MSR_VEC ) { -/* restore altivec registers from the stack */ -unsafe_copy_from_user (¤t->thread.vr_state, &sr->mc_vregs, -sizeof (sr->mc_vregs), failed); - current->thread.used_vr = true; - }else if (current->thread.used_vr) -memset (¤t->thread.vr_state,0 , -ELF_NVRREG *sizeof (vector128)); - -/* Always get VRSAVE back */ -unsafe_get_user (current->thread.vrsave, (u32 __user *)&sr->mc_vregs[32 ], failed); -if (cpu_has_feature (CPU_FTR_ALTIVEC )) -mtspr (SPRN_VRSAVE , current->thread.vrsave); +/* +* Force the process to reload the altivec registers from +* current->thread when it next does altivec instructions +*/ +regs_set_return_msr (regs, regs->msr & ~MSR_VEC ); +if (msr &MSR_VEC ) { +/* restore altivec registers from the stack */ +unsafe_copy_from_user (¤t->thread.vr_state, &sr->mc_vregs, +sizeof (sr->mc_vregs), failed); + current->thread.used_vr = true; + }else if (current->thread.used_vr) { +memset (¤t->thread.vr_state,0 , +ELF_NVRREG *sizeof (vector128)); + } + +/* Always get VRSAVE back */ +unsafe_get_user (current->thread.vrsave, (u32 __user *)&sr->mc_vregs[32 ], failed); +if (cpu_has_feature (CPU_FTR_ALTIVEC )) +mtspr (SPRN_VRSAVE , current->thread.vrsave);#endif /* CONFIG_ALTIVEC */ -unsafe_copy_fpr_from_user (current, &sr->mc_fregs, failed); +unsafe_copy_fpr_from_user (current, &sr->mc_fregs, failed);#ifdef CONFIG_VSX -/* -* Force the process to reload the VSX registers from -* current->thread when it next does VSX instruction. -*/ -regs_set_return_msr (regs, regs->msr & ~MSR_VSX ); -if (msr &MSR_VSX ) {/* -* Restore altivec registers from the stack to a local -* buffer, then write this out to the thread_struct +* Force the process to reload the VSX registers from +* current->thread when it next does VSX instruction. */ -unsafe_copy_vsx_from_user (current, &sr->mc_vsregs, failed); - current->thread.used_vsr = true; - }else if (current->thread.used_vsr) -for (i =0 ; i <32 ; i++) - current->thread.fp_state.fpr[i][TS_VSRLOWOFFSET ] =0 ; +regs_set_return_msr (regs, regs->msr & ~MSR_VSX ); +if (msr &MSR_VSX ) { +/* +* Restore altivec registers from the stack to a local +* buffer, then write this out to the thread_struct +*/ +unsafe_copy_vsx_from_user (current, &sr->mc_vsregs, failed); + current->thread.used_vsr = true; + }else if (current->thread.used_vsr) { +int i; + +for (i =0 ; i <32 ; i++) + current->thread.fp_state.fpr[i][TS_VSRLOWOFFSET ] =0 ; + }#endif /* CONFIG_VSX */ -/* -* force the process to reload the FP registers from -* current->thread when it next does FP instructions -*/ -regs_set_return_msr (regs, regs->msr & ~(MSR_FP |MSR_FE0 |MSR_FE1 )); +/* +* force the process to reload the FP registers from +* current->thread when it next does FP instructions +*/ +regs_set_return_msr (regs, regs->msr & ~(MSR_FP |MSR_FE0 |MSR_FE1 ));#ifdef CONFIG_SPE -/* -* Force the process to reload the spe registers from -* current->thread when it next does spe instructions. -* Since this is user ABI, we must enforce the sizing. -*/ -BUILD_BUG_ON (sizeof (current->thread.spe) !=ELF_NEVRREG *sizeof (u32)); -regs_set_return_msr (regs, regs->msr & ~MSR_SPE ); -if (msr &MSR_SPE ) { -/* restore spe registers from the stack */ -unsafe_copy_from_user (¤t->thread.spe, &sr->mc_vregs, -sizeof (current->thread.spe), failed); - current->thread.used_spe = true; - }else if (current->thread.used_spe) -memset (¤t->thread.spe,0 ,sizeof (current->thread.spe)); - -/* Always get SPEFSCR back */ -unsafe_get_user (current->thread.spefscr, (u32 __user *)&sr->mc_vregs +ELF_NEVRREG , failed); -#endif /* CONFIG_SPE */ +/* +* Force the process to reload the spe registers from +* current->thread when it next does spe instructions. +* Since this is user ABI, we must enforce the sizing. +*/ +BUILD_BUG_ON (sizeof (current->thread.spe) !=ELF_NEVRREG *sizeof (u32)); +regs_set_return_msr (regs, regs->msr & ~MSR_SPE ); +if (msr &MSR_SPE ) { +/* restore spe registers from the stack */ +unsafe_copy_from_user (¤t->thread.spe, &sr->mc_vregs, +sizeof (current->thread.spe), failed); + current->thread.used_spe = true; + }else if (current->thread.used_spe) { +memset (¤t->thread.spe,0 ,sizeof (current->thread.spe)); + } -user_read_access_end (); +/* Always get SPEFSCR back */ +unsafe_get_user (current->thread.spefscr, + (u32 __user *)&sr->mc_vregs +ELF_NEVRREG , failed); +#endif /* CONFIG_SPE */ + }return 0 ; failed: -user_read_access_end ();return 1 ; }
@@ -574,7 +574,6 @@ static long restore_tm_user_regs(struct pt_regs *regs, struct mcontext __user *tm_sr) {unsigned long msr, msr_hi; -int i;if (tm_suspend_disabled)return 1 ;
@@ -585,86 +584,81 @@ static long restore_tm_user_regs(struct pt_regs *regs,* TFHAR is restored from the checkpointed NIP; TEXASR and TFIAR * were set by the signal delivery. */ -if (!user_read_access_begin (sr,sizeof (*sr))) -return 1 ; - -unsafe_restore_general_regs (¤t->thread.ckpt_regs, sr, failed); -unsafe_get_user (current->thread.tm_tfhar, &sr->mc_gregs[PT_NIP ], failed); -unsafe_get_user (msr, &sr->mc_gregs[PT_MSR ], failed); + scoped_user_read_access(sr, failed) { +unsafe_restore_general_regs (¤t->thread.ckpt_regs, sr, failed); +unsafe_get_user (current->thread.tm_tfhar, &sr->mc_gregs[PT_NIP ], failed); +unsafe_get_user (msr, &sr->mc_gregs[PT_MSR ], failed); -/* Restore the previous little-endian mode */ -regs_set_return_msr (regs, (regs->msr & ~MSR_LE ) | (msr &MSR_LE )); +/* Restore the previous little-endian mode */ +regs_set_return_msr (regs, (regs->msr & ~MSR_LE ) | (msr &MSR_LE )); -regs_set_return_msr (regs, regs->msr & ~MSR_VEC ); -if (msr &MSR_VEC ) { -/* restore altivec registers from the stack */ -unsafe_copy_from_user (¤t->thread.ckvr_state, &sr->mc_vregs, -sizeof (sr->mc_vregs), failed); - current->thread.used_vr = true; - }else if (current->thread.used_vr) { -memset (¤t->thread.vr_state,0 , -ELF_NVRREG *sizeof (vector128)); -memset (¤t->thread.ckvr_state,0 , -ELF_NVRREG *sizeof (vector128)); - } +regs_set_return_msr (regs, regs->msr & ~MSR_VEC ); +if (msr &MSR_VEC ) { +/* restore altivec registers from the stack */ +unsafe_copy_from_user (¤t->thread.ckvr_state, &sr->mc_vregs, +sizeof (sr->mc_vregs), failed); + current->thread.used_vr = true; + }else if (current->thread.used_vr) { +memset (¤t->thread.vr_state,0 ,ELF_NVRREG *sizeof (vector128)); +memset (¤t->thread.ckvr_state,0 ,ELF_NVRREG *sizeof (vector128)); + } -/* Always get VRSAVE back */ -unsafe_get_user (current->thread.ckvrsave, - (u32 __user *)&sr->mc_vregs[32 ], failed); -if (cpu_has_feature (CPU_FTR_ALTIVEC )) -mtspr (SPRN_VRSAVE , current->thread.ckvrsave); +/* Always get VRSAVE back */ +unsafe_get_user (current->thread.ckvrsave, + (u32 __user *)&sr->mc_vregs[32 ], failed); +if (cpu_has_feature (CPU_FTR_ALTIVEC )) +mtspr (SPRN_VRSAVE , current->thread.ckvrsave); -regs_set_return_msr (regs, regs->msr & ~(MSR_FP |MSR_FE0 |MSR_FE1 )); +regs_set_return_msr (regs, regs->msr & ~(MSR_FP |MSR_FE0 |MSR_FE1 )); -unsafe_copy_fpr_from_user (current, &sr->mc_fregs, failed); +unsafe_copy_fpr_from_user (current, &sr->mc_fregs, failed); -regs_set_return_msr (regs, regs->msr & ~MSR_VSX ); -if (msr &MSR_VSX ) { -/* -* Restore altivec registers from the stack to a local -* buffer, then write this out to the thread_struct -*/ -unsafe_copy_ckvsx_from_user (current, &sr->mc_vsregs, failed); - current->thread.used_vsr = true; - }else if (current->thread.used_vsr) -for (i =0 ; i <32 ; i++) { - current->thread.fp_state.fpr[i][TS_VSRLOWOFFSET ] =0 ; - current->thread.ckfp_state.fpr[i][TS_VSRLOWOFFSET ] =0 ; +regs_set_return_msr (regs, regs->msr & ~MSR_VSX ); +if (msr &MSR_VSX ) { +/* +* Restore altivec registers from the stack to a local +* buffer, then write this out to the thread_struct +*/ +unsafe_copy_ckvsx_from_user (current, &sr->mc_vsregs, failed); + current->thread.used_vsr = true; + }else if (current->thread.used_vsr) { +int i; + +for (i =0 ; i <32 ; i++) { + current->thread.fp_state.fpr[i][TS_VSRLOWOFFSET ] =0 ; + current->thread.ckfp_state.fpr[i][TS_VSRLOWOFFSET ] =0 ; + } } + } -user_read_access_end (); - -if (!user_read_access_begin (tm_sr,sizeof (*tm_sr))) -return 1 ; + scoped_user_read_access(tm_sr, failed) { +unsafe_restore_general_regs (regs, tm_sr, failed); -unsafe_restore_general_regs (regs, tm_sr, failed); +/* restore altivec registers from the stack */ +if (msr &MSR_VEC ) +unsafe_copy_from_user (¤t->thread.vr_state, &tm_sr->mc_vregs, +sizeof (sr->mc_vregs), failed); -/* restore altivec registers from the stack */ -if (msr &MSR_VEC ) -unsafe_copy_from_user (¤t->thread.vr_state, &tm_sr->mc_vregs, -sizeof (sr->mc_vregs), failed); +/* Always get VRSAVE back */ +unsafe_get_user (current->thread.vrsave, + (u32 __user *)&tm_sr->mc_vregs[32 ], failed); -/* Always get VRSAVE back */ -unsafe_get_user (current->thread.vrsave, - (u32 __user *)&tm_sr->mc_vregs[32 ], failed); +unsafe_copy_ckfpr_from_user (current, &tm_sr->mc_fregs, failed); -unsafe_copy_ckfpr_from_user (current, &tm_sr->mc_fregs, failed); +if (msr &MSR_VSX ) { +/* +* Restore altivec registers from the stack to a local +* buffer, then write this out to the thread_struct +*/ +unsafe_copy_vsx_from_user (current, &tm_sr->mc_vsregs, failed); + current->thread.used_vsr = true; + } -if (msr &MSR_VSX ) { -/* -* Restore altivec registers from the stack to a local -* buffer, then write this out to the thread_struct -*/ -unsafe_copy_vsx_from_user (current, &tm_sr->mc_vsregs, failed); - current->thread.used_vsr = true; +/* 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 ; } -/* 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 ; - -user_read_access_end (); -/* If TM bits are set to the reserved value, it's an invalid context */ if (MSR_TM_RESV (msr_hi))return 1 ;
@@ -712,7 +706,6 @@ static long restore_tm_user_regs(struct pt_regs *regs,return 0 ; failed: -user_read_access_end (); return 1; }#else
@@ -737,8 +730,6 @@ int handle_rt_signal32(struct ksignal *ksig, sigset_t *oldset, struct task_struct *tsk) {struct rt_sigframe __user *frame; -struct mcontext __user *mctx; -struct mcontext __user *tm_mctx =NULL ;unsigned long newsp =0 ;unsigned long tramp;struct pt_regs *regs = tsk->thread.regs;
@@ -747,52 +738,53 @@ int handle_rt_signal32(struct ksignal *ksig, sigset_t *oldset,/* Set up Signal Frame */ frame =get_sigframe (ksig, tsk,sizeof (*frame),1 ); - mctx = &frame->uc.uc_mcontext; -#ifdef CONFIG_PPC_TRANSACTIONAL_MEM - tm_mctx = &frame->uc_transact.uc_mcontext; -#endif if (MSR_TM_ACTIVE (msr))prepare_save_tm_user_regs ();else prepare_save_user_regs (1 ); -if (!user_access_begin (frame,sizeof (*frame))) - goto badframe; + scoped_user_rw_access(frame, badframe) { +struct mcontext __user *mctx; +struct mcontext __user *tm_mctx =NULL ; -/* Put the siginfo & fill in most of the ucontext */ -unsafe_put_user (0 , &frame->uc.uc_flags, failed); + mctx = &frame->uc.uc_mcontext; +#ifdef CONFIG_PPC_TRANSACTIONAL_MEM + tm_mctx = &frame->uc_transact.uc_mcontext; +#endif +/* Put the siginfo & fill in most of the ucontext */ +unsafe_put_user (0 , &frame->uc.uc_flags, badframe);#ifdef CONFIG_PPC64 -unsafe_compat_save_altstack (&frame->uc.uc_stack, regs->gpr[1 ], failed); +unsafe_compat_save_altstack (&frame->uc.uc_stack, regs->gpr[1 ], badframe);#else -unsafe_save_altstack (&frame->uc.uc_stack, regs->gpr[1 ], failed); +unsafe_save_altstack (&frame->uc.uc_stack, regs->gpr[1 ], badframe);#endif -unsafe_put_user (to_user_ptr (&frame->uc.uc_mcontext), &frame->uc.uc_regs, failed); +unsafe_put_user (to_user_ptr (&frame->uc.uc_mcontext), &frame->uc.uc_regs, badframe); -if (MSR_TM_ACTIVE (msr)) { +if (MSR_TM_ACTIVE (msr)) {#ifdef CONFIG_PPC_TRANSACTIONAL_MEM -unsafe_put_user ((unsigned long )&frame->uc_transact, - &frame->uc.uc_link, failed); -unsafe_put_user ((unsigned long )tm_mctx, - &frame->uc_transact.uc_regs, failed); +unsafe_put_user ((unsigned long )&frame->uc_transact, + &frame->uc.uc_link, badframe); +unsafe_put_user ((unsigned long )tm_mctx, + &frame->uc_transact.uc_regs, badframe);#endif -unsafe_save_tm_user_regs (regs, mctx, tm_mctx, msr, failed); - }else { -unsafe_put_user (0 , &frame->uc.uc_link, failed); -unsafe_save_user_regs (regs, mctx, tm_mctx,1 , failed); - } +unsafe_save_tm_user_regs (regs, mctx, tm_mctx, msr, badframe); + }else { +unsafe_put_user (0 , &frame->uc.uc_link, badframe); +unsafe_save_user_regs (regs, mctx, tm_mctx,1 , badframe); + } -/* Save user registers on the stack */ -if (tsk->mm->context.vdso) { - tramp =VDSO32_SYMBOL (tsk->mm->context.vdso, sigtramp_rt32); - }else { - tramp = (unsigned long )mctx->mc_pad; -unsafe_put_user (PPC_RAW_LI (_R0, __NR_rt_sigreturn), &mctx->mc_pad[0 ], failed); -unsafe_put_user (PPC_RAW_SC (), &mctx->mc_pad[1 ], failed); - asm("dcbst %y0; sync; icbi %y0; sync" ::"Z" (mctx->mc_pad[0 ])); +/* Save user registers on the stack */ +if (tsk->mm->context.vdso) { + tramp =VDSO32_SYMBOL (tsk->mm->context.vdso, sigtramp_rt32); + }else { + tramp = (unsigned long )mctx->mc_pad; +unsafe_put_user (PPC_RAW_LI (_R0, __NR_rt_sigreturn), &mctx->mc_pad[0 ], + badframe); +unsafe_put_user (PPC_RAW_SC (), &mctx->mc_pad[1 ], badframe); + asm("dcbst %y0; sync; icbi %y0; sync" ::"Z" (mctx->mc_pad[0 ])); + } +unsafe_put_sigset_t (&frame->uc.uc_sigmask, oldset, badframe); } -unsafe_put_sigset_t (&frame->uc.uc_sigmask, oldset, failed); - -user_access_end ();if (copy_siginfo_to_user (&frame->info, &ksig->info)) goto badframe;
@@ -820,9 +812,6 @@ int handle_rt_signal32(struct ksignal *ksig, sigset_t *oldset,return 0 ; -failed: -user_access_end (); - badframe:signal_fault (tsk, regs,"handle_rt_signal32" , frame);
@@ -837,8 +826,6 @@ int handle_signal32(struct ksignal *ksig, sigset_t *oldset, {struct sigcontext __user *sc;struct sigframe __user *frame; -struct mcontext __user *mctx; -struct mcontext __user *tm_mctx =NULL ;unsigned long newsp =0 ;unsigned long tramp;struct pt_regs *regs = tsk->thread.regs;
@@ -847,46 +834,49 @@ int handle_signal32(struct ksignal *ksig, sigset_t *oldset,/* Set up Signal Frame */ frame =get_sigframe (ksig, tsk,sizeof (*frame),1 ); - mctx = &frame->mctx; -#ifdef CONFIG_PPC_TRANSACTIONAL_MEM - tm_mctx = &frame->mctx_transact; -#endif if (MSR_TM_ACTIVE (msr))prepare_save_tm_user_regs ();else prepare_save_user_regs (1 ); -if (!user_access_begin (frame,sizeof (*frame))) - goto badframe; - sc = (struct sigcontext __user *) &frame->sctx; + scoped_user_rw_access(frame, badframe) { +struct mcontext __user *mctx; +struct mcontext __user *tm_mctx =NULL ; + + mctx = &frame->mctx; +#ifdef CONFIG_PPC_TRANSACTIONAL_MEM + tm_mctx = &frame->mctx_transact; +#endif + sc = (struct sigcontext __user *)&frame->sctx;#if _NSIG !=64 #error "Please adjust handle_signal()"#endif -unsafe_put_user (to_user_ptr (ksig->ka.sa.sa_handler), &sc->handler, failed); -unsafe_put_user (oldset->sig[0 ], &sc->oldmask, failed); +unsafe_put_user (to_user_ptr (ksig->ka.sa.sa_handler), &sc->handler, badframe); +unsafe_put_user (oldset->sig[0 ], &sc->oldmask, badframe);#ifdef CONFIG_PPC64 -unsafe_put_user ((oldset->sig[0 ] >>32 ), &sc->_unused[3 ], failed); +unsafe_put_user ((oldset->sig[0 ] >>32 ), &sc->_unused[3 ], badframe);#else -unsafe_put_user (oldset->sig[1 ], &sc->_unused[3 ], failed); +unsafe_put_user (oldset->sig[1 ], &sc->_unused[3 ], badframe);#endif -unsafe_put_user (to_user_ptr (mctx), &sc->regs, failed); -unsafe_put_user (ksig->sig, &sc->signal, failed); +unsafe_put_user (to_user_ptr (mctx), &sc->regs, badframe); +unsafe_put_user (ksig->sig, &sc->signal, badframe); -if (MSR_TM_ACTIVE (msr)) -unsafe_save_tm_user_regs (regs, mctx, tm_mctx, msr, failed); -else -unsafe_save_user_regs (regs, mctx, tm_mctx,1 , failed); - -if (tsk->mm->context.vdso) { - tramp =VDSO32_SYMBOL (tsk->mm->context.vdso, sigtramp32); - }else { - tramp = (unsigned long )mctx->mc_pad; -unsafe_put_user (PPC_RAW_LI (_R0, __NR_sigreturn), &mctx->mc_pad[0 ], failed); -unsafe_put_user (PPC_RAW_SC (), &mctx->mc_pad[1 ], failed); - asm("dcbst %y0; sync; icbi %y0; sync" ::"Z" (mctx->mc_pad[0 ])); +if (MSR_TM_ACTIVE (msr)) +unsafe_save_tm_user_regs (regs, mctx, tm_mctx, msr, badframe); +else +unsafe_save_user_regs (regs, mctx, tm_mctx,1 , badframe); + +if (tsk->mm->context.vdso) { + tramp =VDSO32_SYMBOL (tsk->mm->context.vdso, sigtramp32); + }else { + tramp = (unsigned long )mctx->mc_pad; +unsafe_put_user (PPC_RAW_LI (_R0, __NR_sigreturn), &mctx->mc_pad[0 ], + badframe); +unsafe_put_user (PPC_RAW_SC (), &mctx->mc_pad[1 ], badframe); + asm("dcbst %y0; sync; icbi %y0; sync" ::"Z" (mctx->mc_pad[0 ])); + } } -user_access_end (); regs->link = tramp;
@@ -908,9 +898,6 @@ int handle_signal32(struct ksignal *ksig, sigset_t *oldset,return 0 ; -failed: -user_access_end (); - badframe:signal_fault (tsk, regs,"handle_signal32" , frame);
@@ -922,21 +909,19 @@ static int do_setcontext(struct ucontext __user *ucp, struct pt_regs *regs, intsigset_t set;struct mcontext __user *mcp; -if (!user_read_access_begin (ucp,sizeof (*ucp))) -return -EFAULT ; - -unsafe_get_sigset_t (&set, &ucp->uc_sigmask, failed); + scoped_user_read_access(ucp, failed) { +unsafe_get_sigset_t (&set, &ucp->uc_sigmask, failed);#ifdef CONFIG_PPC64 - { -u32 cmcp; + { +u32 cmcp; -unsafe_get_user (cmcp, &ucp->uc_regs, failed); - mcp = (struct mcontext __user *)(u64 )cmcp; - } +unsafe_get_user (cmcp, &ucp->uc_regs, failed); + mcp = (struct mcontext __user *)(u64 )cmcp; + }#else -unsafe_get_user (mcp, &ucp->uc_regs, failed); +unsafe_get_user (mcp, &ucp->uc_regs, failed);#endif -user_read_access_end (); + }set_current_blocked (&set);if (restore_user_regs (regs, mcp, sig))
@@ -945,7 +930,6 @@ static int do_setcontext(struct ucontext __user *ucp, struct pt_regs *regs, intreturn 0 ; failed: -user_read_access_end ();return -EFAULT ; }
@@ -960,13 +944,10 @@ static int do_setcontext_tm(struct ucontext __user *ucp,u32 cmcp;u32 tm_cmcp; -if (!user_read_access_begin (ucp,sizeof (*ucp))) -return -EFAULT ; - -unsafe_get_sigset_t (&set, &ucp->uc_sigmask, failed); -unsafe_get_user (cmcp, &ucp->uc_regs, failed); - -user_read_access_end (); + scoped_user_read_access(ucp, failed) { +unsafe_get_sigset_t (&set, &ucp->uc_sigmask, failed); +unsafe_get_user (cmcp, &ucp->uc_regs, failed); + }if (__get_user (tm_cmcp, &tm_ucp->uc_regs))return -EFAULT ;
@@ -981,7 +962,6 @@ static int do_setcontext_tm(struct ucontext __user *ucp,return 0 ; failed: -user_read_access_end (); return -EFAULT; }#endif
@@ -1051,12 +1031,11 @@ SYSCALL_DEFINE3(swapcontext, struct ucontext __user *, old_ctx, mctx = (struct mcontext __user *) ((unsigned long ) &old_ctx->uc_mcontext & ~0xfUL );prepare_save_user_regs (ctx_has_vsx_region); -if (!user_write_access_begin (old_ctx, ctx_size)) -return -EFAULT ; -unsafe_save_user_regs (regs, mctx,NULL , ctx_has_vsx_region, failed); -unsafe_put_sigset_t (&old_ctx->uc_sigmask, ¤t->blocked, failed); -unsafe_put_user (to_user_ptr (mctx), &old_ctx->uc_regs, failed); -user_write_access_end (); + scoped_user_write_access_size(old_ctx, ctx_size, failed) { +unsafe_save_user_regs (regs, mctx,NULL , ctx_has_vsx_region, failed); +unsafe_put_sigset_t (&old_ctx->uc_sigmask, ¤t->blocked, failed); +unsafe_put_user (to_user_ptr (mctx), &old_ctx->uc_regs, failed); + } }if (new_ctx ==NULL )return 0 ;
@@ -1084,7 +1063,6 @@ SYSCALL_DEFINE3(swapcontext, struct ucontext __user *, old_ctx,return 0 ; failed: -user_write_access_end ();return -EFAULT ; }
Signature · 1 line
2.54.0
Christophe Leroy (CS GROUP)
reviewerPATCH v2 2/8 powerpc/signal64: Untangle setup_tm_sigcontexts() and user_access_begin()
In reply to Christophe Leroy (CS GROUP)Call setup_tm_sigcontexts() before opening user access to avoid having to close and open again.
---
v2: Add a stub setup_tm_sigcontexts() for when CONFIG_PPC_TRANSACTIONAL_MEM is not set
--- arch/powerpc/kernel/signal_64.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-)
arch/powerpc/kernel/signal_64.c +15 -15
@@ -203,8 +203,7 @@ static long notrace __unsafe_setup_sigcontext(struct sigcontext __user *sc,* examine the transactional registers in the 2nd sigcontext to determine the * real origin of the signal. */ -static long setup_tm_sigcontexts (struct sigcontext __user *sc, -struct sigcontext __user *tm_sc, +static long setup_tm_sigcontexts (struct rt_sigframe __user *frame,struct task_struct *tsk,int signr,sigset_t *set,unsigned long handler,unsigned long msr)
@@ -217,6 +216,8 @@ static long setup_tm_sigcontexts(struct sigcontext __user *sc,* Userland shall check AT_HWCAP to know wether it can rely on the * v_regs pointer or not. */ +struct sigcontext __user *sc = &frame->uc.uc_mcontext; +struct sigcontext __user *tm_sc = &frame->uc_transact.uc_mcontext;#ifdef CONFIG_ALTIVEC elf_vrreg_t __user *v_regs =sigcontext_vmx_regs (sc);elf_vrreg_t __user *tm_v_regs =sigcontext_vmx_regs (tm_sc);
@@ -325,6 +326,15 @@ static long setup_tm_sigcontexts(struct sigcontext __user *sc, return err; } +#else +static long setup_tm_sigcontexts (struct rt_sigframe __user *frame, +struct task_struct *tsk, +int signr,sigset_t *set,unsigned long handler, +unsigned long msr) +{ +BUILD_BUG (); +return -EINVAL ; +}#endif /*
@@ -872,6 +882,9 @@ int handle_rt_signal64(struct ksignal *ksig, sigset_t *set,*/ if (!MSR_TM_ACTIVE (msr))prepare_setup_sigcontext (tsk); +else + err |=setup_tm_sigcontexts (frame, tsk, ksig->sig,NULL , + (unsigned long )ksig->ka.sa.sa_handler, msr);if (!user_write_access_begin (frame,sizeof (*frame))) goto badframe;
@@ -889,19 +902,6 @@ int handle_rt_signal64(struct ksignal *ksig, sigset_t *set,* ucontext_t (for transactional state) with its uc_link ptr. */ unsafe_put_user (&frame->uc_transact, &frame->uc.uc_link, badframe_block); - -user_write_access_end (); - - err |=setup_tm_sigcontexts (&frame->uc.uc_mcontext, - &frame->uc_transact.uc_mcontext, - tsk, ksig->sig,NULL , - (unsigned long )ksig->ka.sa.sa_handler, - msr); - -if (!user_write_access_begin (&frame->uc.uc_sigmask, -sizeof (frame->uc.uc_sigmask))) - goto badframe; -#endif }else {unsafe_put_user (0 , &frame->uc.uc_link, badframe_block);
Signature · 1 line
2.54.0
Christophe Leroy (CS GROUP)
reviewerPATCH v2 3/8 powerpc/signal64: Convert to scoped user access
In reply to Christophe Leroy (CS GROUP)Commit 861574d51bbd ("powerpc/uaccess: Implement masked user access") provides optimised user access by avoiding the cost of access_ok().
Convert signal64 functions to scoped user access.
Scoped user access also make the code simpler.
--- arch/powerpc/kernel/signal_64.c | 81 +++++++++++++-------------------- 1 file changed, 32 insertions(+), 49 deletions(-)
arch/powerpc/kernel/signal_64.c +32 -49
@@ -693,15 +693,12 @@ SYSCALL_DEFINE3(swapcontext, struct ucontext __user *, old_ctx,if (old_ctx !=NULL ) {prepare_setup_sigcontext (current); -if (!user_write_access_begin (old_ctx, ctx_size)) -return -EFAULT ; - -unsafe_setup_sigcontext (&old_ctx->uc_mcontext, current,0 ,NULL , -0 , ctx_has_vsx_region, efault_out); -unsafe_copy_to_user (&old_ctx->uc_sigmask, ¤t->blocked, -sizeof (sigset_t), efault_out); - -user_write_access_end (); + scoped_user_write_access_size(old_ctx, ctx_size, efault_out) { +unsafe_setup_sigcontext (&old_ctx->uc_mcontext, current,0 ,NULL , +0 , ctx_has_vsx_region, efault_out); +unsafe_copy_to_user (&old_ctx->uc_sigmask, ¤t->blocked, +sizeof (sigset_t), efault_out); + } }if (new_ctx ==NULL )return 0 ;
@@ -727,14 +724,12 @@ SYSCALL_DEFINE3(swapcontext, struct ucontext __user *, old_ctx, }set_current_blocked (&set); -if (!user_read_access_begin (new_ctx, ctx_size)) -return -EFAULT ; -if (__unsafe_restore_sigcontext (current,NULL ,0 , &new_ctx->uc_mcontext)) { -user_read_access_end (); -force_exit_sig (SIGSEGV ); -return -EFAULT ; + scoped_user_read_access_size(new_ctx, ctx_size, efault_out) { +if (__unsafe_restore_sigcontext (current,NULL ,0 , &new_ctx->uc_mcontext)) { +force_exit_sig (SIGSEGV ); +return -EFAULT ; + } } -user_read_access_end ();/* This returns like rt_sigreturn */ set_thread_flag (TIF_RESTOREALL );
@@ -742,7 +737,6 @@ SYSCALL_DEFINE3(swapcontext, struct ucontext __user *, old_ctx,return 0 ; efault_out: -user_write_access_end ();return -EFAULT ; }
@@ -825,6 +819,7 @@ SYSCALL_DEFINE0(rt_sigreturn) &uc_transact->uc_mcontext)) goto badframe; }else { +struct sigcontext __user *uc_mcontext = &uc->uc_mcontext;/* * Fall through, for non-TM restore *
@@ -839,13 +834,8 @@ SYSCALL_DEFINE0(rt_sigreturn)*/ regs_set_return_msr (current->thread.regs, current->thread.regs->msr & ~MSR_TS_MASK ); -if (!user_read_access_begin (&uc->uc_mcontext,sizeof (uc->uc_mcontext))) - goto badframe; - -unsafe_restore_sigcontext (current,NULL ,1 , &uc->uc_mcontext, - badframe_block); - -user_read_access_end (); + scoped_user_read_access(uc_mcontext, badframe) +unsafe_restore_sigcontext (current,NULL ,1 , uc_mcontext, badframe); }if (restore_altstack (&uc->uc_stack))
@@ -855,8 +845,6 @@ SYSCALL_DEFINE0(rt_sigreturn)return 0 ; -badframe_block: -user_read_access_end (); badframe:signal_fault (current, regs,"rt_sigreturn" , uc);
@@ -886,32 +874,29 @@ int handle_rt_signal64(struct ksignal *ksig, sigset_t *set, err |=setup_tm_sigcontexts (frame, tsk, ksig->sig,NULL , (unsigned long )ksig->ka.sa.sa_handler, msr); -if (!user_write_access_begin (frame,sizeof (*frame))) - goto badframe; + scoped_user_write_access(frame, badframe) { +unsafe_put_user (&frame->info, &frame->pinfo, badframe); +unsafe_put_user (&frame->uc, &frame->puc, badframe); -unsafe_put_user (&frame->info, &frame->pinfo, badframe_block); -unsafe_put_user (&frame->uc, &frame->puc, badframe_block); +/* Create the ucontext. */ +unsafe_put_user (0 , &frame->uc.uc_flags, badframe); +unsafe_save_altstack (&frame->uc.uc_stack, regs->gpr[1 ], badframe); -/* Create the ucontext. */ -unsafe_put_user (0 , &frame->uc.uc_flags, badframe_block); -unsafe_save_altstack (&frame->uc.uc_stack, regs->gpr[1 ], badframe_block); - -if (MSR_TM_ACTIVE (msr)) { +if (MSR_TM_ACTIVE (msr)) {#ifdef CONFIG_PPC_TRANSACTIONAL_MEM -/* The ucontext_t passed to userland points to the second -* ucontext_t (for transactional state) with its uc_link ptr. -*/ -unsafe_put_user (&frame->uc_transact, &frame->uc.uc_link, badframe_block); +/* The ucontext_t passed to userland points to the second +* ucontext_t (for transactional state) with its uc_link ptr. +*/ +unsafe_put_user (&frame->uc_transact, &frame->uc.uc_link, badframe);#endif - }else { -unsafe_put_user (0 , &frame->uc.uc_link, badframe_block); -unsafe_setup_sigcontext (&frame->uc.uc_mcontext, tsk, ksig->sig, -NULL , (unsigned long )ksig->ka.sa.sa_handler, -1 , badframe_block); - } + }else { +unsafe_put_user (0 , &frame->uc.uc_link, badframe); +unsafe_setup_sigcontext (&frame->uc.uc_mcontext, tsk, ksig->sig,NULL , + (unsigned long )ksig->ka.sa.sa_handler,1 , badframe); + } -unsafe_copy_to_user (&frame->uc.uc_sigmask, set,sizeof (*set), badframe_block); -user_write_access_end (); +unsafe_copy_to_user (&frame->uc.uc_sigmask, set,sizeof (*set), badframe); + }/* Save the siginfo outside of the unsafe block. */ if (copy_siginfo_to_user (&frame->info, &ksig->info))
@@ -968,8 +953,6 @@ int handle_rt_signal64(struct ksignal *ksig, sigset_t *set,return 0 ; -badframe_block: -user_write_access_end (); badframe:signal_fault (current, regs,"handle_rt_signal64" , frame);
Signature · 1 line
2.54.0
Christophe Leroy (CS GROUP)
reviewerPATCH v2 4/8 powerpc/signal64: Access function descriptor with scoped user access
In reply to Christophe Leroy (CS GROUP)Access the function descriptor of the handler within a scoped user access block.
--- arch/powerpc/kernel/signal_64.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-)
arch/powerpc/kernel/signal_64.c +9 -2
@@ -932,8 +932,10 @@ int handle_rt_signal64(struct ksignal *ksig, sigset_t *set,struct func_desc __user *ptr = (struct func_desc __user *)ksig->ka.sa.sa_handler; - err |=get_user (regs->ctr, &ptr->addr); - err |=get_user (regs->gpr[2 ], &ptr->toc); + scoped_user_read_access(ptr, badfunc) { +unsafe_get_user (regs->ctr, &ptr->addr, badfunc); +unsafe_get_user (regs->gpr[2 ], &ptr->toc, badfunc); + } }/* enter the signal handler in native-endian mode */
@@ -956,5 +958,10 @@ int handle_rt_signal64(struct ksignal *ksig, sigset_t *set, badframe:signal_fault (current, regs,"handle_rt_signal64" , frame); +return 1 ; + +badfunc: +signal_fault (current, regs, __func__, (void __user *)ksig->ka.sa.sa_handler); +return 1 ; }
Signature · 1 line
2.54.0
Christophe Leroy (CS GROUP)
reviewerPATCH v2 5/8 powerpc/signal: Include the new stack frame inside the user access block
In reply to Christophe Leroy (CS GROUP)Include the new stack frame inside the user access block and set it up using unsafe_put_user().
On an mpc 8321 (book3s/32) the improvment is about 4% on a process sending a signal to itself.
--- arch/powerpc/kernel/signal_32.c | 28 ++++++++++++---------------- arch/powerpc/kernel/signal_64.c | 13 ++++++------- 2 files changed, 18 insertions(+), 23 deletions(-)
arch/powerpc/kernel/signal_32.c +12 -16
@@ -730,7 +730,7 @@ int handle_rt_signal32(struct ksignal *ksig, sigset_t *oldset, struct task_struct *tsk) {struct rt_sigframe __user *frame; -unsigned long newsp =0 ; +unsigned long __user *newsp;unsigned long tramp;struct pt_regs *regs = tsk->thread.regs;/* Save the thread's msr before get_tm_stackpointer() changes it */
@@ -738,12 +738,13 @@ int handle_rt_signal32(struct ksignal *ksig, sigset_t *oldset,/* Set up Signal Frame */ frame =get_sigframe (ksig, tsk,sizeof (*frame),1 ); + newsp = (unsigned long __user *)((unsigned long )frame - (__SIGNAL_FRAMESIZE +16 ));if (MSR_TM_ACTIVE (msr))prepare_save_tm_user_regs ();else prepare_save_user_regs (1 ); - scoped_user_rw_access(frame, badframe) { + scoped_user_rw_access_size(newsp, __SIGNAL_FRAMESIZE + 16 + sizeof(*frame), badframe) {struct mcontext __user *mctx;struct mcontext __user *tm_mctx =NULL ;
@@ -784,6 +785,9 @@ int handle_rt_signal32(struct ksignal *ksig, sigset_t *oldset, asm("dcbst %y0; sync; icbi %y0; sync" ::"Z" (mctx->mc_pad[0 ])); }unsafe_put_sigset_t (&frame->uc.uc_sigmask, oldset, badframe); + +/* create a stack frame for the caller of the handler */ +unsafe_put_user (regs->gpr[1 ], newsp, badframe); }if (copy_siginfo_to_user (&frame->info, &ksig->info))
@@ -795,13 +799,8 @@ int handle_rt_signal32(struct ksignal *ksig, sigset_t *oldset, tsk->thread.fp_state.fpscr =0 ;/* turn off all fp exceptions */ #endif -/* create a stack frame for the caller of the handler */ - newsp = ((unsigned long )frame) - (__SIGNAL_FRAMESIZE +16 ); -if (put_user (regs->gpr[1 ], (u32 __user *)newsp)) - goto badframe; -/* Fill registers for signal handler */ - regs->gpr[1 ] = newsp; + regs->gpr[1 ] = (unsigned long )newsp; regs->gpr[3 ] = ksig->sig; regs->gpr[4 ] = (unsigned long )&frame->info; regs->gpr[5 ] = (unsigned long )&frame->uc;
@@ -826,7 +825,7 @@ int handle_signal32(struct ksignal *ksig, sigset_t *oldset, {struct sigcontext __user *sc;struct sigframe __user *frame; -unsigned long newsp =0 ; +unsigned long __user *newsp;unsigned long tramp;struct pt_regs *regs = tsk->thread.regs;/* Save the thread's msr before get_tm_stackpointer() changes it */
@@ -834,12 +833,13 @@ int handle_signal32(struct ksignal *ksig, sigset_t *oldset,/* Set up Signal Frame */ frame =get_sigframe (ksig, tsk,sizeof (*frame),1 ); + newsp = (unsigned long __user *)((unsigned long )frame - __SIGNAL_FRAMESIZE);if (MSR_TM_ACTIVE (msr))prepare_save_tm_user_regs ();else prepare_save_user_regs (1 ); - scoped_user_rw_access(frame, badframe) { + scoped_user_rw_access_size(newsp, __SIGNAL_FRAMESIZE + sizeof(*frame), badframe) {struct mcontext __user *mctx;struct mcontext __user *tm_mctx =NULL ;
@@ -876,6 +876,7 @@ int handle_signal32(struct ksignal *ksig, sigset_t *oldset,unsafe_put_user (PPC_RAW_SC (), &mctx->mc_pad[1 ], badframe); asm("dcbst %y0; sync; icbi %y0; sync" ::"Z" (mctx->mc_pad[0 ])); } +unsafe_put_user (regs->gpr[1 ], newsp, badframe); } regs->link = tramp;
@@ -884,12 +885,7 @@ int handle_signal32(struct ksignal *ksig, sigset_t *oldset, tsk->thread.fp_state.fpscr =0 ;/* turn off all fp exceptions */ #endif -/* create a stack frame for the caller of the handler */ - newsp = ((unsigned long )frame) - __SIGNAL_FRAMESIZE; -if (put_user (regs->gpr[1 ], (u32 __user *)newsp)) - goto badframe; - - regs->gpr[1 ] = newsp; + regs->gpr[1 ] = (unsigned long )newsp; regs->gpr[3 ] = ksig->sig; regs->gpr[4 ] = (unsigned long ) sc;regs_set_return_ip (regs, (unsigned long ) ksig->ka.sa.sa_handler);
arch/powerpc/kernel/signal_64.c +6 -7
@@ -856,13 +856,14 @@ int handle_rt_signal64(struct ksignal *ksig, sigset_t *set, struct task_struct *tsk) {struct rt_sigframe __user *frame; -unsigned long newsp =0 ; +unsigned long __user *newsp;long err =0 ;struct pt_regs *regs = tsk->thread.regs;/* Save the thread's msr before get_tm_stackpointer() changes it */ unsigned long msr = regs->msr; frame =get_sigframe (ksig, tsk,sizeof (*frame),0 ); + newsp = (unsigned long __user *)((unsigned long )frame - __SIGNAL_FRAMESIZE);/* * This only applies when calling unsafe_setup_sigcontext() and must be
@@ -874,7 +875,7 @@ int handle_rt_signal64(struct ksignal *ksig, sigset_t *set, err |=setup_tm_sigcontexts (frame, tsk, ksig->sig,NULL , (unsigned long )ksig->ka.sa.sa_handler, msr); - scoped_user_write_access(frame, badframe) { + scoped_user_write_access_size(newsp, __SIGNAL_FRAMESIZE + sizeof(*frame), badframe) {unsafe_put_user (&frame->info, &frame->pinfo, badframe);unsafe_put_user (&frame->uc, &frame->puc, badframe);
@@ -896,6 +897,8 @@ int handle_rt_signal64(struct ksignal *ksig, sigset_t *set, }unsafe_copy_to_user (&frame->uc.uc_sigmask, set,sizeof (*set), badframe); +/* Allocate a dummy caller frame for the signal handler. */ +unsafe_put_user (regs->gpr[1 ], newsp, badframe); }/* Save the siginfo outside of the unsafe block. */
@@ -915,10 +918,6 @@ int handle_rt_signal64(struct ksignal *ksig, sigset_t *set,regs_set_return_ip (regs, (unsigned long ) &frame->tramp[0 ]); } -/* Allocate a dummy caller frame for the signal handler. */ - newsp = ((unsigned long )frame) - __SIGNAL_FRAMESIZE; - err |=put_user (regs->gpr[1 ], (unsigned long __user *)newsp); -/* Set up "regs" so we "return" to the signal handler. */ if (is_elf2_task ()) { regs->ctr = (unsigned long ) ksig->ka.sa.sa_handler;
@@ -940,7 +939,7 @@ int handle_rt_signal64(struct ksignal *ksig, sigset_t *set,/* enter the signal handler in native-endian mode */ regs_set_return_msr (regs, (regs->msr & ~MSR_LE ) | (MSR_KERNEL &MSR_LE )); - regs->gpr[1 ] = newsp; + regs->gpr[1 ] = (unsigned long )newsp; regs->gpr[3 ] = ksig->sig; regs->result =0 ;if (ksig->ka.sa.sa_flags &SA_SIGINFO ) {
Signature · 1 line
2.54.0
Christophe Leroy (CS GROUP)
reviewerPATCH v2 6/8 signal: Add unsafe_copy_siginfo_to_user()
In reply to Christophe Leroy (CS GROUP)In the same spirit as commit fb05121fd6a2 ("signal: Add unsafe_get_compat_sigset()"), implement an 'unsafe' version of copy_siginfo_to_user() in order to use it within user access blocks.
For that, also add an 'unsafe' version of clear_user().
This commit adds the generic fallback for unsafe_clear_user(). Architectures wanting to use unsafe_copy_siginfo_to_user() within a user_access_begin() section have to make sure they have their own unsafe_clear_user().
--- include/linux/signal.h | 15 +++++++++++++++ include/linux/uaccess.h | 1 + kernel/signal.c | 5 ----- 3 files changed, 16 insertions(+), 5 deletions(-)
include/linux/signal.h +15 -0
@@ -36,6 +36,21 @@ static inline void copy_siginfo_to_external(siginfo_t *to,int copy_siginfo_to_user (siginfo_t __user *to,const kernel_siginfo_t *from);int copy_siginfo_from_user (kernel_siginfo_t *to,const siginfo_t __user *from); +static __always_inline char __user *si_expansion(const siginfo_t __user *info) +{ +return ((char __user *)info) +sizeof (struct kernel_siginfo ); +} + +#define unsafe_copy_siginfo_to_user (to, from, label) do { \ + siginfo_t __user *__ucs_to = to; \ + const kernel_siginfo_t *__ucs_from = from; \ + char __user *__ucs_expansion = si_expansion(__ucs_to); \ + \ + unsafe_copy_to_user(__ucs_to, __ucs_from, \ + sizeof(struct kernel_siginfo), label); \ + unsafe_clear_user(__ucs_expansion, SI_EXPANSION_SIZE, label); \ +} while (0) +enum siginfo_layout {SIL_KILL ,SIL_TIMER ,
include/linux/uaccess.h +1 -0
@@ -636,6 +636,7 @@ do { \#define unsafe_put_user (x,p,e) unsafe_op_wrap(__put_user(x,p),e)#define unsafe_copy_to_user (d,s,l,e) unsafe_op_wrap(__copy_to_user(d,s,l),e)#define unsafe_copy_from_user (d,s,l,e) unsafe_op_wrap(__copy_from_user(d,s,l),e) +#define unsafe_clear_user (d, l, e) unsafe_op_wrap(__clear_user(d, l), e)static inline unsigned long user_access_save (void ) {return 0UL ; }static inline void user_access_restore (unsigned long flags) { }#endif /* !user_access_begin */
kernel/signal.c +0 -5
@@ -3493,11 +3493,6 @@ enum siginfo_layout siginfo_layout(unsigned sig, int si_code)return layout; } -static inline char __user *si_expansion (const siginfo_t __user *info) -{ -return ((char __user *)info) +sizeof (struct kernel_siginfo ); -} -int copy_siginfo_to_user (siginfo_t __user *to,const kernel_siginfo_t *from) {char __user *expansion =si_expansion (to);
Signature · 1 line
2.54.0
Christophe Leroy (CS GROUP)
reviewerPATCH v2 7/8 powerpc/uaccess: Add unsafe_clear_user()
In reply to Christophe Leroy (CS GROUP)Implement unsafe_clear_user() for powerpc.
It's a copy/paste of unsafe_copy_to_user() with value 0 as source.
It may be improved in a later patch by using 'dcbz' instruction to zeroize full cache lines at once.
--- arch/powerpc/include/asm/uaccess.h | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+)
arch/powerpc/include/asm/uaccess.h +20 -0
@@ -588,6 +588,26 @@ do { \ unsafe_put_user(*(u8*)(_src + _i), (u8 __user *)(_dst + _i), e); \ } while (0) +#define unsafe_clear_user (d, l, e) \ +do { \ + u8 __user *_dst = (u8 __user *)(d); \ + size_t _len = (l); \ + int _i; \ + \ + for (_i = 0; _i < (_len & ~(sizeof(u64) - 1)); _i += sizeof(u64)) \ + unsafe_put_user(0, (u64 __user *)(_dst + _i), e); \ + if (_len & 4) { \ + unsafe_put_user(0, (u32 __user *)(_dst + _i), e); \ + _i += 4; \ + } \ + if (_len & 2) { \ + unsafe_put_user(0, (u16 __user *)(_dst + _i), e); \ + _i += 2; \ + } \ + if (_len & 1) \ + unsafe_put_user(0, (u8 __user *)(_dst + _i), e); \ +} while (0) +#define arch_get_kernel_nofault (dst, src, type, err_label) \ __get_user_size_goto(*((type *)(dst)), \ (__force type __user *)(src), sizeof(type), err_label)
Signature · 1 line
2.54.0
Christophe Leroy (CS GROUP)
reviewerPATCH v2 8/8 powerpc/signal: Use unsafe_copy_siginfo_to_user()
In reply to Christophe Leroy (CS GROUP)Use unsafe_copy_siginfo_to_user() in order to do the copy within the user access block.
On an mpc 8321 (book3s/32) the improvment is about 5% on a process sending a signal to itself.
--- arch/powerpc/kernel/signal_32.c | 18 +++++++++--------- arch/powerpc/kernel/signal_64.c | 5 +---- 2 files changed, 10 insertions(+), 13 deletions(-)
arch/powerpc/kernel/signal_32.c +9 -9
@@ -716,12 +716,6 @@ static long restore_tm_user_regs(struct pt_regs *regs, struct mcontext __user *s }#endif -#ifdef CONFIG_PPC64 - -#define copy_siginfo_to_user copy_siginfo_to_user32 - -#endif /* CONFIG_PPC64 */ -/* * Set up a signal frame for a "real-time" signal handler * (one which gets siginfo).
@@ -735,6 +729,7 @@ int handle_rt_signal32(struct ksignal *ksig, sigset_t *oldset,struct pt_regs *regs = tsk->thread.regs;/* Save the thread's msr before get_tm_stackpointer() changes it */ unsigned long msr = regs->msr; +compat_siginfo_t uinfo;/* Set up Signal Frame */ frame =get_sigframe (ksig, tsk,sizeof (*frame),1 );
@@ -744,6 +739,9 @@ int handle_rt_signal32(struct ksignal *ksig, sigset_t *oldset,else prepare_save_user_regs (1 ); +if (IS_ENABLED (CONFIG_COMPAT )) +copy_siginfo_to_external32 (&uinfo, &ksig->info); + scoped_user_rw_access_size(newsp, __SIGNAL_FRAMESIZE + 16 + sizeof(*frame), badframe) {struct mcontext __user *mctx;struct mcontext __user *tm_mctx =NULL ;
@@ -785,14 +783,16 @@ int handle_rt_signal32(struct ksignal *ksig, sigset_t *oldset, asm("dcbst %y0; sync; icbi %y0; sync" ::"Z" (mctx->mc_pad[0 ])); }unsafe_put_sigset_t (&frame->uc.uc_sigmask, oldset, badframe); +if (IS_ENABLED (CONFIG_COMPAT )) +unsafe_copy_to_user (&frame->info, &uinfo,sizeof (frame->info), badframe); +else +unsafe_copy_siginfo_to_user ((void __user *)&frame->info, &ksig->info, + badframe);/* create a stack frame for the caller of the handler */ unsafe_put_user (regs->gpr[1 ], newsp, badframe); } -if (copy_siginfo_to_user (&frame->info, &ksig->info)) - goto badframe; - regs->link = tramp;#ifdef CONFIG_PPC_FPU_REGS
arch/powerpc/kernel/signal_64.c +1 -4
@@ -897,14 +897,11 @@ int handle_rt_signal64(struct ksignal *ksig, sigset_t *set, }unsafe_copy_to_user (&frame->uc.uc_sigmask, set,sizeof (*set), badframe); +unsafe_copy_siginfo_to_user (&frame->info, &ksig->info, badframe);/* Allocate a dummy caller frame for the signal handler. */ unsafe_put_user (regs->gpr[1 ], newsp, badframe); } -/* Save the siginfo outside of the unsafe block. */ -if (copy_siginfo_to_user (&frame->info, &ksig->info)) - goto badframe; -/* Make sure signal handler doesn't get spurious FP exceptions */ tsk->thread.fp_state.fpscr =0 ;
Signature · 1 line
2.54.0
Christophe Leroy (CS GROUP)
reviewerLe 02/06/2026 à 10:46, Christophe Leroy (CS GROUP) a écrit :
Quoted 11 lines
This series converts powerpc architecture signal handling to scoped user access and enlarges some of the block accesses to minimise the number of times user access has to be opened and closed.
As mentioned in individual patches, some bring real performance improvement.
This series is built from previous series [1] which predates implementation of scoped user access.
Sashiko made relevant comments, I need to rework this series.
Quoted 16 lines
Changes in v2:
- Add a stubsetup_tm_sigcontexts()for whenCONFIG_PPC_TRANSACTIONAL_MEMis not set in patch 2Christophe Leroy (CS GROUP) (8):
powerpc/signal32: Convert to scoped user access powerpc/signal64: Untanglesetup_tm_sigcontexts()and
user_access_begin()
powerpc/signal64: Convert to scoped user access powerpc/signal64: Access function descriptor with scoped user access powerpc/signal: Include the new stack frame inside the user access
block
signal: Addunsafe_copy_siginfo_to_user()powerpc/uaccess: Addunsafe_clear_user()
powerpc/signal: Useunsafe_copy_siginfo_to_user()
Quoted 8 lines
arch/powerpc/include/asm/uaccess.h | 20 ++ arch/powerpc/kernel/signal_32.c | 498 ++++++++++++++--------------- arch/powerpc/kernel/signal_64.c | 138 ++++---- include/linux/signal.h | 15 + include/linux/uaccess.h | 1 + kernel/signal.c | 5 - 6 files changed, 334 insertions(+), 343 deletions(-)
--
pw-bot: cr