2010-05-28 23:09:12 -04:00
/*
* Copyright 2010 Tilera Corporation . All Rights Reserved .
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation , version 2.
*
* This program is distributed in the hope that it will be useful , but
* WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE , GOOD TITLE or
* NON INFRINGEMENT . See the GNU General Public License for
* more details .
*/
# include <linux/sched.h>
# include <linux/mm.h>
# include <linux/smp.h>
# include <linux/kernel.h>
# include <linux/signal.h>
# include <linux/errno.h>
# include <linux/wait.h>
# include <linux/unistd.h>
# include <linux/stddef.h>
# include <linux/personality.h>
# include <linux/suspend.h>
# include <linux/ptrace.h>
# include <linux/elf.h>
# include <linux/compat.h>
# include <linux/syscalls.h>
# include <linux/uaccess.h>
# include <asm/processor.h>
# include <asm/ucontext.h>
# include <asm/sigframe.h>
2010-06-25 17:04:17 -04:00
# include <asm/syscalls.h>
2013-08-07 15:33:32 -04:00
# include <asm/vdso.h>
2010-05-28 23:09:12 -04:00
# include <arch/interrupts.h>
struct compat_ucontext {
compat_ulong_t uc_flags ;
compat_uptr_t uc_link ;
struct compat_sigaltstack uc_stack ;
struct sigcontext uc_mcontext ;
sigset_t uc_sigmask ; /* mask last for extensibility */
} ;
struct compat_rt_sigframe {
unsigned char save_area [ C_ABI_SAVE_AREA_SIZE ] ; /* caller save area */
struct compat_siginfo info ;
struct compat_ucontext uc ;
} ;
2013-10-13 17:23:53 -04:00
int copy_siginfo_to_user32 ( struct compat_siginfo __user * to , const siginfo_t * from )
2010-05-28 23:09:12 -04:00
{
int err ;
if ( ! access_ok ( VERIFY_WRITE , to , sizeof ( struct compat_siginfo ) ) )
return - EFAULT ;
/* If you change siginfo_t structure, please make sure that
this code is fixed accordingly .
It should never copy any pad contained in the structure
to avoid security leaks , but must copy the generic
3 ints plus the relevant union member . */
err = __put_user ( from - > si_signo , & to - > si_signo ) ;
err | = __put_user ( from - > si_errno , & to - > si_errno ) ;
err | = __put_user ( ( short ) from - > si_code , & to - > si_code ) ;
if ( from - > si_code < 0 ) {
err | = __put_user ( from - > si_pid , & to - > si_pid ) ;
err | = __put_user ( from - > si_uid , & to - > si_uid ) ;
2015-03-16 15:04:05 -04:00
err | = __put_user ( from - > si_int , & to - > si_int ) ;
2010-05-28 23:09:12 -04:00
} else {
/*
* First 32 bits of unions are always present :
* si_pid = = = si_band = = = si_tid = = = si_addr ( LS half )
*/
err | = __put_user ( from - > _sifields . _pad [ 0 ] ,
& to - > _sifields . _pad [ 0 ] ) ;
switch ( from - > si_code > > 16 ) {
case __SI_FAULT > > 16 :
break ;
case __SI_CHLD > > 16 :
err | = __put_user ( from - > si_utime , & to - > si_utime ) ;
err | = __put_user ( from - > si_stime , & to - > si_stime ) ;
err | = __put_user ( from - > si_status , & to - > si_status ) ;
/* FALL THROUGH */
default :
case __SI_KILL > > 16 :
err | = __put_user ( from - > si_uid , & to - > si_uid ) ;
break ;
case __SI_POLL > > 16 :
err | = __put_user ( from - > si_fd , & to - > si_fd ) ;
break ;
case __SI_TIMER > > 16 :
err | = __put_user ( from - > si_overrun , & to - > si_overrun ) ;
2015-03-16 15:04:05 -04:00
err | = __put_user ( from - > si_int , & to - > si_int ) ;
2010-05-28 23:09:12 -04:00
break ;
/* This is not generated by the kernel as of now. */
case __SI_RT > > 16 :
case __SI_MESGQ > > 16 :
err | = __put_user ( from - > si_uid , & to - > si_uid ) ;
err | = __put_user ( from - > si_int , & to - > si_int ) ;
break ;
}
}
return err ;
}
int copy_siginfo_from_user32 ( siginfo_t * to , struct compat_siginfo __user * from )
{
int err ;
if ( ! access_ok ( VERIFY_READ , from , sizeof ( struct compat_siginfo ) ) )
return - EFAULT ;
err = __get_user ( to - > si_signo , & from - > si_signo ) ;
err | = __get_user ( to - > si_errno , & from - > si_errno ) ;
err | = __get_user ( to - > si_code , & from - > si_code ) ;
err | = __get_user ( to - > si_pid , & from - > si_pid ) ;
err | = __get_user ( to - > si_uid , & from - > si_uid ) ;
2015-03-16 15:04:05 -04:00
err | = __get_user ( to - > si_int , & from - > si_int ) ;
2010-05-28 23:09:12 -04:00
return err ;
}
2010-12-14 16:07:25 -05:00
/* The assembly shim for this function arranges to ignore the return value. */
2012-10-23 13:30:54 -04:00
long compat_sys_rt_sigreturn ( void )
2010-05-28 23:09:12 -04:00
{
2012-10-23 13:30:54 -04:00
struct pt_regs * regs = current_pt_regs ( ) ;
2010-05-28 23:09:12 -04:00
struct compat_rt_sigframe __user * frame =
( struct compat_rt_sigframe __user * ) compat_ptr ( regs - > sp ) ;
sigset_t set ;
if ( ! access_ok ( VERIFY_READ , frame , sizeof ( * frame ) ) )
goto badframe ;
if ( __copy_from_user ( & set , & frame - > uc . uc_sigmask , sizeof ( set ) ) )
goto badframe ;
2012-02-14 11:41:06 +00:00
set_current_blocked ( & set ) ;
2010-05-28 23:09:12 -04:00
2010-12-14 16:07:25 -05:00
if ( restore_sigcontext ( regs , & frame - > uc . uc_mcontext ) )
2010-05-28 23:09:12 -04:00
goto badframe ;
2012-12-23 03:50:34 -05:00
if ( compat_restore_altstack ( & frame - > uc . uc_stack ) )
2010-05-28 23:09:12 -04:00
goto badframe ;
2010-12-14 16:07:25 -05:00
return 0 ;
2010-05-28 23:09:12 -04:00
badframe :
2011-05-16 14:23:44 -04:00
signal_fault ( " bad sigreturn frame " , regs , frame , 0 ) ;
2010-05-28 23:09:12 -04:00
return 0 ;
}
/*
* Determine which stack to use . .
*/
static inline void __user * compat_get_sigframe ( struct k_sigaction * ka ,
struct pt_regs * regs ,
size_t frame_size )
{
unsigned long sp ;
/* Default to using normal stack */
sp = ( unsigned long ) compat_ptr ( regs - > sp ) ;
/*
* If we are on the alternate signal stack and would overflow
* it , don ' t . Return an always - bogus address instead so we
* will die with SIGSEGV .
*/
if ( on_sig_stack ( sp ) & & ! likely ( on_sig_stack ( sp - frame_size ) ) )
2010-06-25 17:04:17 -04:00
return ( void __user __force * ) - 1UL ;
2010-05-28 23:09:12 -04:00
/* This is the X/Open sanctioned signal stack switching. */
if ( ka - > sa . sa_flags & SA_ONSTACK ) {
if ( sas_ss_flags ( sp ) = = 0 )
sp = current - > sas_ss_sp + current - > sas_ss_size ;
}
sp - = frame_size ;
/*
* Align the stack pointer according to the TILE ABI ,
* i . e . so that on function entry ( sp & 15 ) = = 0.
*/
sp & = - 16UL ;
return ( void __user * ) sp ;
}
2013-10-07 15:01:08 +02:00
int compat_setup_rt_frame ( struct ksignal * ksig , sigset_t * set ,
struct pt_regs * regs )
2010-05-28 23:09:12 -04:00
{
unsigned long restorer ;
struct compat_rt_sigframe __user * frame ;
2013-10-07 15:01:08 +02:00
int err = 0 , sig = ksig - > sig ;
2010-05-28 23:09:12 -04:00
2013-10-07 15:01:08 +02:00
frame = compat_get_sigframe ( & ksig - > ka , regs , sizeof ( * frame ) ) ;
2010-05-28 23:09:12 -04:00
if ( ! access_ok ( VERIFY_WRITE , frame , sizeof ( * frame ) ) )
2013-10-07 15:01:08 +02:00
goto err ;
2010-05-28 23:09:12 -04:00
/* Always write at least the signal number for the stack backtracer. */
2013-10-07 15:01:08 +02:00
if ( ksig - > ka . sa . sa_flags & SA_SIGINFO ) {
2010-05-28 23:09:12 -04:00
/* At sigreturn time, restore the callee-save registers too. */
2013-10-07 15:01:08 +02:00
err | = copy_siginfo_to_user32 ( & frame - > info , & ksig - > info ) ;
2010-05-28 23:09:12 -04:00
regs - > flags | = PT_FLAGS_RESTORE_REGS ;
} else {
2013-10-07 15:01:08 +02:00
err | = __put_user ( ksig - > info . si_signo , & frame - > info . si_signo ) ;
2010-05-28 23:09:12 -04:00
}
/* Create the ucontext. */
err | = __clear_user ( & frame - > save_area , sizeof ( frame - > save_area ) ) ;
err | = __put_user ( 0 , & frame - > uc . uc_flags ) ;
err | = __put_user ( 0 , & frame - > uc . uc_link ) ;
2012-12-23 03:50:34 -05:00
err | = __compat_save_altstack ( & frame - > uc . uc_stack , regs - > sp ) ;
2010-05-28 23:09:12 -04:00
err | = setup_sigcontext ( & frame - > uc . uc_mcontext , regs ) ;
err | = __copy_to_user ( & frame - > uc . uc_sigmask , set , sizeof ( * set ) ) ;
if ( err )
2013-10-07 15:01:08 +02:00
goto err ;
2010-05-28 23:09:12 -04:00
2013-08-07 15:33:32 -04:00
restorer = VDSO_SYM ( & __vdso_rt_sigreturn ) ;
2013-10-07 15:01:08 +02:00
if ( ksig - > ka . sa . sa_flags & SA_RESTORER )
restorer = ptr_to_compat_reg ( ksig - > ka . sa . sa_restorer ) ;
2010-05-28 23:09:12 -04:00
/*
* Set up registers for signal handler .
* Registers that we don ' t modify keep the value they had from
* user - space at the time we took the signal .
2012-05-16 14:54:20 -04:00
* We always pass siginfo and mcontext , regardless of SA_SIGINFO ,
* since some things rely on this ( e . g . glibc ' s debug / segfault . c ) .
2010-05-28 23:09:12 -04:00
*/
2013-10-07 15:01:08 +02:00
regs - > pc = ptr_to_compat_reg ( ksig - > ka . sa . sa_handler ) ;
2010-05-28 23:09:12 -04:00
regs - > ex1 = PL_ICS_EX1 ( USER_PL , 1 ) ; /* set crit sec in handler */
regs - > sp = ptr_to_compat_reg ( frame ) ;
regs - > lr = restorer ;
2014-07-13 17:40:49 +02:00
regs - > regs [ 0 ] = ( unsigned long ) sig ;
2012-05-16 14:54:20 -04:00
regs - > regs [ 1 ] = ptr_to_compat_reg ( & frame - > info ) ;
regs - > regs [ 2 ] = ptr_to_compat_reg ( & frame - > uc ) ;
regs - > flags | = PT_FLAGS_CALLER_SAVES ;
2010-05-28 23:09:12 -04:00
return 0 ;
2013-10-07 15:01:08 +02:00
err :
trace_unhandled_signal ( " bad sigreturn frame " , regs ,
( unsigned long ) frame , SIGSEGV ) ;
2010-05-28 23:09:12 -04:00
return - EFAULT ;
}