ELF32 userspace, ELF64 kernel, and 32-bit signals on hppa. (help needed)
PATCH 1/1 ELF32 userspace, ELF64 kernel, and 32-bit signals on hppa. (help needed)
parisc,
*** Help needed, code broken ... ***
Currently our siginfo_t and ucontext_t structures delivered to an ELF32 userspace from an ELF64 kernel are not correct. The kernel thinking userspace is the same bitwidth, writes it's registers and values as 64-bits. Architectures like sparc64 and ppc64 have rolled their own solutions. I wanted to make it a little more generic.
jejb,
Thanks for the initial cleanup and poking me in the right direction! I promised this out a little while back, but as a good hacker I'm up too late to be thinking straight and get the patch out the door.
What does the patch do?
- Add siginfo_t generic compat structure and code to write it to userspace.
- Add generic compat signal structures.
- Add generic kernel code to handle this structure.
- Add lots more PARISC compat structures.
- Add code in our signal path to distinguish the process personality and learn to setup/restore a 32-bit/64-bit rt frame structure.
There is a bug hiding in the code... I can't find it yet. Userspace sorta works, but sometimes processes go splat, and I think it has to do with the following:
- In restore_context32 I have to ship the 32-bit value into a 64-bit registers. Should it be sign extended?
= I think yes.
- Is stack address 0xfffffffffaf00410 the same as 0x00000000faf00410? = No?
What to do?
- Enable debugging in singal.c and signal32.c and keep looking for the bug :)
Cheers,
Carlos.
====
arch/parisc/kernel/signal.c | 277 +++++++++++++++------------ arch/parisc/kernel/signal32.c | 156 +++++++++++++-- arch/parisc/kernel/signal32.h | 22 ++ include/asm-generic/compat_siginfo.h | 154 +++++++++++++++ include/asm-generic/compat_signal.h | 28 ++ include/asm-parisc/compat.h | 10 include/asm-parisc/compat_rt_sigframe.h | 25 ++ include/asm-parisc/compat_siginfo.h | 2 include/asm-parisc/compat_signal.h | 2 include/asm-parisc/compat_ucontext.h | 19 + include/asm-parisc/rt_sigframe.h | 13 - include/asm-parisc/siginfo.h | 2 include/asm-parisc/ucontext.h | 8 kernel/Makefile | 2 kernel/compat_signal.c | 126 ++++++++++++ kernel/signal.c | 8 16 files changed, 709 insertions(+), 145 deletions(-)
====
parisc/kernel/signal.c +163 -114
@@ -27,19 +27,25 @@#include <linux/compat.h> #include <linux/elf.h> #include <linux/personality.h> +#include <linux/compat.h> #include <asm/ucontext.h> #include <asm/rt_sigframe.h> #include <asm/uaccess.h> #include <asm/pgalloc.h> #include <asm/cacheflush.h> +#include "signal32.h" -#define DEBUG_SIG 0 +#define DEBUG_SIG 0 +#define DEBUG_SIG_LEVEL 2#if DEBUG_SIG -#define DBG (x) printk x +#define DBG (LEVEL , ...) \ + ((DEBUG_SIG_LEVEL >= LEVEL) \ + ? printk(__VA_ARGS__) : (void) 0)#else -#define DBG (x) +#define DBG (LEVEL , ...)#endif +#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
@@ -52,43 +58,6 @@int do_signal (sigset_t *oldset,struct pt_regs *regs,int in_syscall); -int copy_siginfo_to_user (siginfo_t *to,siginfo_t *from) -{ -if (from->si_code <0 ) -return __copy_to_user (to, from,sizeof (siginfo_t)); -else { -int err; - -/* -* If you change siginfo_t structure, please be sure -* 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); -switch (from->si_code >>16 ) { -case __SI_FAULT >>16 : -/* FIXME: should we put the interruption code here? */ -case __SI_POLL >>16 : - err |=__put_user ((unsigned long )from->si_addr, &to->si_addr); -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); -default : - err |=__put_user (from->si_uid, &to->si_uid); - err |=__put_user (from->si_pid, &to->si_pid); -break ; -/* case __SI_RT: This is not generated by the kernel as of now. */ - } -return err; - } -} -/* * Atomically swap in the new signal mask, and wait for a signal. */
@@ -101,26 +70,27 @@ sys_rt_sigsuspend(sigset_t *unewset, siz {sigset_t saveset, newset;#ifdef __LP64__ -/* XXX FIXME -- assumes 32-bit user app! */ compat_sigset_t newset32; -/* XXX: Don't preclude handling different sized sigset_t's. */ -if (sigsetsize !=sizeof (compat_sigset_t)) -return -EINVAL ; - -if (copy_from_user (&newset32, (compat_sigset_t *)unewset,sizeof (newset32))) -return -EFAULT ; - - newset.sig[0 ] = newset32.sig[0 ] | ((unsigned long )newset32.sig[1 ] <<32 ); -#else - -/* XXX: Don't preclude handling different sized sigset_t's. */ -if (sigsetsize !=sizeof (sigset_t)) -return -EINVAL ; - -if (copy_from_user (&newset, unewset,sizeof (newset))) -return -EFAULT ; +if (personality (current->personality) ==PER_LINUX32 ){ +/* XXX: Don't preclude handling different sized sigset_t's. */ +if (sigsetsize !=sizeof (compat_sigset_t)) +return -EINVAL ; +if (copy_from_user (&newset32, (compat_sigset_t *)unewset,sizeof (newset32))) +return -EFAULT ; +sigset_32to64 (&newset,&newset32); + + } else#endif + { +/* XXX: Don't preclude handling different sized sigset_t's. */ +if (sigsetsize !=sizeof (sigset_t)) +return -EINVAL ; + +if (copy_from_user (&newset, unewset,sizeof (newset))) +return -EFAULT ; + } +sigdelsetmask (&newset, ~_BLOCKABLE);spin_lock_irq (¤t->sighand->siglock);
@@ -161,7 +131,9 @@ restore_sigcontext(struct sigcontext *sc err |=__copy_from_user (regs->iaoq, sc->sc_iaoq,sizeof (regs->iaoq)); err |=__copy_from_user (regs->iasq, sc->sc_iasq,sizeof (regs->iasq)); err |=__get_user (regs->sar, &sc->sc_sar); -DBG (("restore_sigcontext: r28 is %ld\n" , regs->gr[28 ])); +DBG (2 ,"restore_sigcontext: iaoq is 0x%#lx / 0x%#lx\n" , + regs->iaoq[0 ],regs->iaoq[1 ]); +DBG (2 ,"restore_sigcontext: r28 is %ld\n" , regs->gr[28 ]);return err; }
@@ -174,6 +146,9 @@ sys_rt_sigreturn(struct pt_regs *regs, iunsigned long usp = (regs->gr[30 ] & ~(0x01UL ));unsigned long sigframe_size =PARISC_RT_SIGFRAME_SIZE ;#ifdef __LP64__ +compat_sigset_t compat_set; +struct compat_rt_sigframe * compat_frame; +if (personality (current->personality) ==PER_LINUX32 ) sigframe_size =PARISC_RT_SIGFRAME_SIZE32 ;#endif
@@ -182,11 +157,23 @@ sys_rt_sigreturn(struct pt_regs *regs, i/* Unwind the user stack to get the rt_sigframe structure. */ frame = (struct rt_sigframe *) (usp - sigframe_size); -DBG (("in sys_rt_sigreturn, frame is %p\n" , frame)); - -if (__copy_from_user (&set, &frame->uc.uc_sigmask,sizeof (set))) - goto give_sigsegv; +DBG (2 ,"sys_rt_sigreturn: frame is %p\n" , frame); +#ifdef __LP64__ + compat_frame = (struct compat_rt_sigframe *)frame; + +if (personality (current->personality) ==PER_LINUX32 ){ +DBG (2 ,"sys_rt_sigreturn: ELF32 process.\n" ); +if (__copy_from_user (&compat_set, &compat_frame->uc.uc_sigmask,sizeof (compat_set))) + goto give_sigsegv; +sigset_32to64 (&set,&compat_set); + } else +#endif + { +if (__copy_from_user (&set, &frame->uc.uc_sigmask,sizeof (set))) + goto give_sigsegv; + } +sigdelsetmask (&set, ~_BLOCKABLE);spin_lock_irq (¤t->sighand->siglock); current->blocked = set;
@@ -194,17 +181,30 @@ sys_rt_sigreturn(struct pt_regs *regs, ispin_unlock_irq (¤t->sighand->siglock);/* Good thing we saved the old gr[30], eh? */ -if (restore_sigcontext (&frame->uc.uc_mcontext, regs)) - goto give_sigsegv; - -DBG (("usp: %#08lx stack %p" , usp, &frame->uc.uc_stack)); +#ifdef __LP64__ +if (personality (current->personality) ==PER_LINUX32 ){ +DBG (1 ,"sys_rt_sigreturn: compat_frame->uc.uc_mcontext 0x%p\n" , + &compat_frame->uc.uc_mcontext); +if (restore_sigcontext32 (&compat_frame->uc.uc_mcontext, regs)) + goto give_sigsegv; +DBG (1 ,"sys_rt_sigreturn: usp %#08lx stack 0x%p\n" , + usp, &compat_frame->uc.uc_stack); +if (do_sigaltstack32 (&compat_frame->uc.uc_stack,NULL , usp) == -EFAULT ) + goto give_sigsegv; + } else +#endif + { +DBG (1 ,"sys_rt_sigreturn: frame->uc.uc_mcontext 0x%p\n" , + &frame->uc.uc_mcontext); +if (restore_sigcontext (&frame->uc.uc_mcontext, regs)) + goto give_sigsegv; +DBG (1 ,"sys_rt_sigreturn: usp %#08lx stack 0x%p\n" , + usp, &frame->uc.uc_stack); +if (do_sigaltstack (&frame->uc.uc_stack,NULL , usp) == -EFAULT ) + goto give_sigsegv; + } + -/* I don't know why everyone else assumes they can call this -with a pointer to a stack_t on the kernel stack. That -makes no sense. Anyway we'll do it like m68k, since we -also are using segmentation in the same way as them. */ -if (do_sigaltstack (&frame->uc.uc_stack,NULL , usp) == -EFAULT ) - goto give_sigsegv;/* If we are on the syscall path IAOQ will not be restored, and * if we are on the interrupt path we must not corrupt gr31.
@@ -212,14 +212,13 @@ sys_rt_sigreturn(struct pt_regs *regs, iif (in_syscall) regs->gr[31 ] = regs->iaoq[0 ];#if DEBUG_SIG -DBG (("returning to %#lx\n" , regs->iaoq[0 ])); -DBG (("in sys_rt_sigreturn:\n" )); +DBG (1 ,"sys_rt_sigreturn: returning to %#lx, DUMPING REGS:\n" , regs->iaoq[0 ]);show_regs (regs);#endif return ; give_sigsegv: -DBG (("sys_rt_sigreturn sending SIGSEGV\n" )); +DBG (1 ,"sys_rt_sigreturn: Sending SIGSEGV\n" ); si.si_signo =SIGSEGV ; si.si_errno =0 ; si.si_code =SI_KERNEL ;
@@ -237,9 +236,16 @@ give_sigsegv:static inline void *get_sigframe (struct k_sigaction *ka,unsigned long sp,size_t frame_size) { +/*FIXME: ELF32 vs. ELF64 has different frame_size, but since we +don't use the parameter it doesn't matter */ + +DBG (1 ,"get_sigframe: ka = %#lx, sp = %#lx, frame_size = %#lx\n" , + (unsigned long )ka, sp, frame_size); +if ((ka->sa.sa_flags &SA_ONSTACK ) !=0 && !on_sig_stack (sp)) sp = current->sas_ss_sp;/* Stacks grow up! */ +DBG (1 ,"get_sigframe: Returning sp = %#lx\n" , (unsigned long )sp);return (void *) sp;/* Stacks grow up. Fun. */ }
@@ -259,20 +265,20 @@ setup_sigcontext(struct sigcontext *sc, err |=__put_user (regs->gr[31 ]+4 , &sc->sc_iaoq[1 ]); err |=__put_user (regs->sr[3 ], &sc->sc_iasq[0 ]); err |=__put_user (regs->sr[3 ], &sc->sc_iasq[1 ]); -DBG (("setup_sigcontext: iaoq %#lx/%#lx\n" , - regs->gr[31 ], regs->gr[31 ])); +DBG (1 ,"setup_sigcontext: iaoq %#lx / %#lx (in syscall)\n" , + regs->gr[31 ], regs->gr[31 ]+4 ); }else { err |=__copy_to_user (sc->sc_iaoq, regs->iaoq,sizeof (regs->iaoq)); err |=__copy_to_user (sc->sc_iasq, regs->iasq,sizeof (regs->iasq)); -DBG (("setup_sigcontext: iaoq %#lx/%#lx\n" , - regs->iaoq[0 ], regs->iaoq[1 ])); +DBG (1 ,"setup_sigcontext: iaoq %#lx / %#lx (not in syscall)\n" , + regs->iaoq[0 ], regs->iaoq[1 ]); } err |=__put_user (flags, &sc->sc_flags); err |=__copy_to_user (sc->sc_gr, regs->gr,sizeof (regs->gr)); err |=__copy_to_user (sc->sc_fr, regs->fr,sizeof (regs->fr)); err |=__put_user (regs->sar, &sc->sc_sar); -DBG (("setup_sigcontext: r28 is %ld\n" , regs->gr[28 ])); +DBG (1 ,"setup_sigcontext: r28 is %ld\n" , regs->gr[28 ]);return err; }
@@ -286,19 +292,53 @@ setup_rt_frame(int sig, struct k_sigactiunsigned long haddr, sigframe_size;struct siginfo si;int err =0 ; - +#ifdef __LP64__ +compat_int_t compat_val; +struct compat_rt_sigframe * compat_frame; +compat_sigset_t compat_set; +#endif + usp = (regs->gr[30 ] & ~(0x01UL )); +/*FIXME: frame_size parameter is unused, remove it. */ frame =get_sigframe (ka, usp,sizeof (*frame)); -DBG (("setup_rt_frame 1: frame %p info %p\n" , frame, info)); +DBG (1 ,"setup_rt_frame: frame %p info %p\n" , frame, info); - err |=__copy_to_user (&frame->info, info,sizeof (siginfo_t)); - err |=__put_user (current->sas_ss_sp, &frame->uc.uc_stack.ss_sp); - err |=__put_user (current->sas_ss_size, &frame->uc.uc_stack.ss_size); - err |=__put_user (sas_ss_flags (regs->gr[30 ]), - &frame->uc.uc_stack.ss_flags); - err |=setup_sigcontext (&frame->uc.uc_mcontext, regs, in_syscall); - err |=__copy_to_user (&frame->uc.uc_sigmask, set,sizeof (*set)); + +#ifdef __LP64__ + + compat_frame = (struct compat_rt_sigframe *)frame; + +if (personality (current->personality) ==PER_LINUX32 ) { +DBG (1 ,"setup_rt_frame: frame->info = 0x%p\n" , &compat_frame->info); + err |=compat_copy_siginfo_to_user (&compat_frame->info, info); + compat_val = (compat_int_t )current->sas_ss_sp; + err |=__put_user (compat_val, &compat_frame->uc.uc_stack.ss_sp); + compat_val = (compat_int_t )current->sas_ss_size; + err |=__put_user (compat_val, &compat_frame->uc.uc_stack.ss_size); + compat_val =sas_ss_flags (regs->gr[30 ]); + err |=__put_user (compat_val, &compat_frame->uc.uc_stack.ss_flags); +DBG (1 ,"setup_rt_frame: frame->uc = 0x%p\n" , &compat_frame->uc); +DBG (1 ,"setup_rt_frame: frame->uc.uc_mcontext = 0x%p\n" , &compat_frame->uc.uc_mcontext); + err |=setup_sigcontext32 (&compat_frame->uc.uc_mcontext, regs, in_syscall); +sigset_64to32 (&compat_set,set); + err |=__copy_to_user (&compat_frame->uc.uc_sigmask, &compat_set,sizeof (compat_set)); + } else +#endif + { +DBG (1 ,"setup_rt_frame: frame->info = 0x%p\n" , &frame->info); + err |=copy_siginfo_to_user (&frame->info, info); + err |=__put_user (current->sas_ss_sp, &frame->uc.uc_stack.ss_sp); + err |=__put_user (current->sas_ss_size, &frame->uc.uc_stack.ss_size); + err |=__put_user (sas_ss_flags (regs->gr[30 ]), + &frame->uc.uc_stack.ss_flags); +DBG (1 ,"setup_rt_frame: frame->uc = 0x%p\n" , &frame->uc); +DBG (1 ,"setup_rt_frame: frame->uc.uc_mcontext = 0x%p\n" , &frame->uc.uc_mcontext); + err |=setup_sigcontext (&frame->uc.uc_mcontext, regs, in_syscall); +/* FIXME: Should probably be converted aswell for the compat case */ + err |=__copy_to_user (&frame->uc.uc_sigmask, set,sizeof (*set)); + } +if (err) goto give_sigsegv;
@@ -315,8 +355,8 @@ setup_rt_frame(int sig, struct k_sigacti {int sid; asm ("mfsp %%sr3,%0" :"=r" (sid)); -DBG (("flushing 64 bytes at space %#x offset %p\n" , - sid, frame->tramp)); +DBG (1 ,"setup_rt_frame: Flushing 64 bytes at space %#x offset %p\n" , + sid, frame->tramp); }#endif
@@ -359,8 +399,8 @@ setup_rt_frame(int sig, struct k_sigacti haddr = fdesc.addr; regs->gr[19 ] = fdesc.gp; -DBG (("64 bit signal, exe=%#lx, r19=%#lx, in_syscall=%d\n" , - haddr, regs->gr[19], in_syscall)); +DBG (1 ,"setup_rt_frame: 64 bit signal, exe=%#lx, r19=%#lx, in_syscall=%d\n" , + haddr, regs->gr[19], in_syscall); }#endif
@@ -391,24 +431,33 @@ setup_rt_frame(int sig, struct k_sigacti regs->gr[2 ] = rp;/* userland return pointer */ regs->gr[26 ] = sig;/* signal number */ - regs->gr[25 ] =A (&frame->info);/* siginfo pointer */ - regs->gr[24 ] =A (&frame->uc);/* ucontext pointer */ -DBG (("making sigreturn frame: %#lx + %#x = %#lx\n" , +#ifdef __LP64__ +if (personality (current->personality) ==PER_LINUX32 ){ + regs->gr[25 ] =A (&compat_frame->info);/* siginfo pointer */ + regs->gr[24 ] =A (&compat_frame->uc);/* ucontext pointer */ + } else +#endif + { + regs->gr[25 ] =A (&frame->info);/* siginfo pointer */ + regs->gr[24 ] =A (&frame->uc);/* ucontext pointer */ + } + +DBG (1 ,"setup_rt_frame: making sigreturn frame: %#lx + %#lx = %#lx\n" , regs->gr[30 ], sigframe_size, - regs->gr[30 ] + sigframe_size)); + regs->gr[30 ] + sigframe_size);/* Raise the user stack pointer to make a proper call frame. */ regs->gr[30 ] = (A (frame) + sigframe_size); -DBG (("SIG deliver (%s:%d): frame=0x%p sp=%#lx iaoq=%#lx/%#lx rp=%#lx\n" , +DBG (1 ,"setup_rt_frame: sig deliver (%s,%d) frame=0x%p sp=%#lx iaoq=%#lx/%#lx rp=%#lx\n" , current->comm, current->pid, frame, regs->gr[30 ], - regs->iaoq[0 ], regs->iaoq[1 ], rp)); + regs->iaoq[0 ], regs->iaoq[1 ], rp);return 1 ; give_sigsegv: -DBG (("setup_rt_frame sending SIGSEGV\n" )); +DBG (1 ,"setup_rt_frame: sending SIGSEGV\n" );if (sig ==SIGSEGV ) ka->sa.sa_handler =SIG_DFL ; si.si_signo =SIGSEGV ;
@@ -431,8 +480,8 @@ handle_signal(unsigned long sig, siginfo {struct k_sigaction *ka = ¤t->sighand->action[sig-1 ]; -DBG (("handle_signal(sig=%ld, ka=%p, info=%p, oldset=%p, regs=%p)\n" , - sig, ka, info, oldset, regs)); +DBG (1 ,"handle_signal: sig=%ld, ka=%p, info=%p, oldset=%p, regs=%p\n" , + sig, ka, info, oldset, regs);/* Set up the stack frame */ if (!setup_rt_frame (sig, ka, info, oldset, regs, in_syscall))
@@ -470,8 +519,8 @@ do_signal(sigset_t *oldset, struct pt_restruct k_sigaction *ka;int signr; -DBG (("do_signal(oldset=0x%p, regs=0x%p, sr7 %#lx, pending %d, in_syscall=%d\n" , - oldset, regs, regs->sr[7 ], current->sigpending, in_syscall)); +DBG (1 ,"\ndo_signal: oldset=0x%p, regs=0x%p, sr7 %#lx, in_syscall=%d\n" , + oldset, regs, regs->sr[7 ], in_syscall);/* Everyone else checks to see if they are in kernel mode at this point and exits if that's the case. I'm not sure why
@@ -481,12 +530,13 @@ do_signal(sigset_t *oldset, struct pt_reif (!oldset) oldset = ¤t->blocked; -DBG (("do_signal: oldset %08lx:%08lx\n" , - oldset->sig[0 ], oldset->sig[1 ])); +DBG (1 ,"do_signal: oldset %08lx / %08lx\n" , + oldset->sig[0 ], oldset->sig[1 ]); signr =get_signal_to_deliver (&info, regs,NULL ); -/* printk("do_signal: signr = %d, regs->gr[28] = %ld\n", signr, regs->gr[28]); */ +DBG (3 ,"do_signal: signr = %d, regs->gr[28] = %ld\n" , signr, regs->gr[28 ]); +if (signr >0 ) {/* Restart a system call if necessary. */ if (in_syscall) {
@@ -495,14 +545,14 @@ do_signal(sigset_t *oldset, struct pt_recase -ERESTART_RESTARTBLOCK :current_thread_info ()->restart_block.fn = do_no_restart_syscall;case -ERESTARTNOHAND : -DBG (("ERESTARTNOHAND: returning -EINTR\n" )); +DBG (1 ,"ERESTARTNOHAND: returning -EINTR\n" ); regs->gr[28 ] = -EINTR ;break ;case -ERESTARTSYS : ka = ¤t->sighand->action[signr-1 ];if (!(ka->sa.sa_flags &SA_RESTART )) { -DBG (("ERESTARTSYS: putting -EINTR\n" )); +DBG (1 ,"ERESTARTSYS: putting -EINTR\n" ); regs->gr[28 ] = -EINTR ;break ; }
@@ -521,9 +571,8 @@ do_signal(sigset_t *oldset, struct pt_redelivery failed, we need to continue to iterate in this loop so we can deliver the SIGSEGV... */ if (handle_signal (signr, &info, oldset, regs, in_syscall)) { -DBG ((KERN_DEBUG -"Exiting do_signal (success), regs->gr[28] = %ld\n" , - regs->gr[28 ])); +DBG (1 ,KERN_DEBUG "do_signal: Exit (success), regs->gr[28] = %ld\n" , + regs->gr[28 ]);return 1 ; } }
@@ -577,8 +626,8 @@ do_signal(sigset_t *oldset, struct pt_re } } -DBG (("Exiting do_signal (not delivered), regs->gr[28] = %ld\n" , - regs->gr[28 ])); +DBG (1 ,"do_signal: Exit (not delivered), regs->gr[28] = %ld\n" , + regs->gr[28 ]);return 0 ; }
parisc/kernel/signal32.c +143 -13
183 lines not on this page · raw message
asm-parisc/compat.h +10 -0
@@ -24,6 +24,7 @@ typedef u16 compat_nlink_t;typedef u16 compat_ipc_pid_t ;typedef s32 compat_daddr_t ;typedef u32 compat_caddr_t ; +typedef u32 compat_timer_t ;typedef s32 compat_int_t ;typedef s32 compat_long_t ;
@@ -99,6 +100,15 @@ struct compat_statfs {s32 f_namelen;s32 f_frsize;s32 f_spare[5 ]; +}; + +struct compat_sigcontext { +compat_int_t sc_flags; +compat_int_t sc_gr[32 ];/* PSW in sc_gr[0] */ +u64 sc_fr[32 ];/* FIXME, do we need other state info? */ +compat_int_t sc_iasq[2 ]; +compat_int_t sc_iaoq[2 ]; +compat_int_t sc_sar;/* cr11 */ };#define COMPAT_RLIM_INFINITY 0xffffffff
asm-parisc/rt_sigframe.h +2 -11
@@ -1,22 +1,13 @@#ifndef _ASM_PARISC_RT_SIGFRAME_H#define _ASM_PARISC_RT_SIGFRAME_H +#include <asm/compat_rt_sigframe.h> +struct rt_sigframe {unsigned int tramp[4 ];struct siginfo info;struct ucontext uc; }; - -/* -* The 32-bit ABI wants at least 48 bytes for a function call frame: -* 16 bytes for arg0-arg3, and 32 bytes for magic (the only part of -* which Linux/parisc uses is sp-20 for the saved return pointer...) -* Then, the stack pointer must be rounded to a cache line (64 bytes). -*/ -#define SIGFRAME32 64 -#define FUNCTIONCALLFRAME32 48 -#define PARISC_RT_SIGFRAME_SIZE32 \ - (((sizeof(struct rt_sigframe) + FUNCTIONCALLFRAME32) + SIGFRAME32) & -SIGFRAME32)#ifdef __LP64__#define SIGFRAME 128
asm-parisc/siginfo.h +0 -2
@@ -1,8 +1,6 @@#ifndef _PARISC_SIGINFO_H#define _PARISC_SIGINFO_H -#define HAVE_ARCH_COPY_SIGINFO_TO_USER -#include <asm-generic/siginfo.h> /*
asm-parisc/ucontext.h +4 -4
@@ -1,12 +1,12 @@ -#ifndef _ASMPARISC_UCONTEXT_H -#define _ASMPARISC_UCONTEXT_H +#ifndef _ASM_PARISC_UCONTEXT_H +#define _ASM_PARISC_UCONTEXT_Hstruct ucontext { -unsigned long uc_flags; +unsigned int uc_flags;struct ucontext *uc_link;stack_t uc_stack;struct sigcontext uc_mcontext;sigset_t uc_sigmask;/* mask last for extensibility */ }; -#endif /* !_ASMPARISC_UCONTEXT_H */ +#endif /* !_ASM_PARISC_UCONTEXT_H */
Makefile +1 -1
@@ -5,7 +5,7 @@ obj-y = sched.o fork.o exec_domain.o panic.o printk.o profile.o \ exit.o itimer.o time.o softirq.o resource.o \ sysctl.o capability.o ptrace.o timer.o user.o \ - signal.o sys.o kmod.o workqueue.o pid.o \ + compat_signal.o signal.o sys.o kmod.o workqueue.o pid.o \ rcupdate.o intermodule.o extable.o params.o posix-timers.o obj-$(CONFIG_FUTEX) += futex.o
signal.c +8 -0
@@ -24,9 +24,11 @@#include <linux/binfmts.h> #include <linux/security.h> #include <linux/ptrace.h> +#include <linux/personality.h> #include <asm/param.h> #include <asm/uaccess.h> #include <asm/siginfo.h> +#include <asm/compat_siginfo.h> /* * SLAB caches for signal bits.
@@ -2006,6 +2008,12 @@ int copy_siginfo_to_user(siginfo_t __useif (from->si_code <0 )return __copy_to_user (to, from,sizeof (siginfo_t)) ? -EFAULT :0 ; + +/* Use compat_siginfo_t with 32-bit signals */ +if (personality (current->personality) ==PER_LINUX32 ){ +return compat_copy_siginfo_to_user ((compat_siginfo_t __user *)to,from); + } +/* * If you change siginfo_t structure, please be sure * this code is fixed accordingly.
parisc/kernel/signal32.h renamed from parisc/kernel/signal32.h.orig +22 -0
@@ -0,0 +1,22 @@ +#ifndef _PARISC64_KERNEL_SIGNAL32_H +#define _PARISC64_KERNEL_SIGNAL32_H + +#include <linux/compat.h> +#include <asm/compat_signal.h> + +/* ELF32 signal handling */ + +struct k_sigaction32 { +struct compat_sigaction sa; +}; + +void sigset_32to64 (sigset_t *s64,compat_sigset_t *s32); +void sigset_64to32 (compat_sigset_t *s32,sigset_t *s64); +int do_sigaltstack32 (const compat_stack_t *uss32, +compat_stack_t *uoss32,unsigned long sp); +long restore_sigcontext32 (struct compat_sigcontext *sc, +struct pt_regs *regs); +long setup_sigcontext32 (struct compat_sigcontext *sc, +struct pt_regs *regs,int in_syscall); + +#endif
asm-generic/compat_siginfo.h renamed from asm-generic/compat_siginfo.h.orig +154 -0
154 lines not on this page · raw message
asm-generic/compat_signal.h renamed from asm-generic/compat_signal.h.orig +28 -0
@@ -0,0 +1,28 @@ +#ifndef _ASM_GENERIC_COMPAT_SIGNAL_H +#define _ASM_GENERIC_COMPAT_SIGNAL_H + +# ifndef __ASSEMBLY__ +# include <linux/types.h> + +typedef compat_uptr_t compat_sighandler_t ; + +typedef struct compat_sigaltstack { +compat_uptr_t ss_sp; +compat_int_t ss_flags; +compat_size_t ss_size; +}compat_stack_t ; + +# ifdef __KERNEL__ + +/* Most things should be clean enough to redefine this at will, if care +is taken to make libc match. */ + +struct compat_sigaction { +compat_sighandler_t sa_handler; +compat_uint_t sa_flags; +compat_sigset_t sa_mask;/* mask last for extensibility */ +}; + +# endif /* __KERNEL__ */ +# endif /* !__ASSEMBLY */ +#endif /* _ASM_GENERIC_COMPAT_SIGNAL_H */
asm-parisc/compat_rt_sigframe.h renamed from asm-parisc/compat_rt_sigframe.h.orig +25 -0
@@ -0,0 +1,25 @@ +#include <linux/compat.h> +#include <asm/compat_siginfo.h> +#include <asm/compat_ucontext.h> + +#ifndef _ASM_PARISC_COMPAT_RT_SIGFRAME_H +#define _ASM_PARISC_COMPAT_RT_SIGFRAME_H + +struct compat_rt_sigframe { +compat_uint_t tramp[4 ]; +compat_siginfo_t info; +struct compat_ucontext uc; +}; + +/* +* The 32-bit ABI wants at least 48 bytes for a function call frame: +* 16 bytes for arg0-arg3, and 32 bytes for magic (the only part of +* which Linux/parisc uses is sp-20 for the saved return pointer...) +* Then, the stack pointer must be rounded to a cache line (64 bytes). +*/ +#define SIGFRAME32 64 +#define FUNCTIONCALLFRAME32 48 +#define PARISC_RT_SIGFRAME_SIZE32 \ + (((sizeof(struct compat_rt_sigframe) + FUNCTIONCALLFRAME32) + SIGFRAME32) & -SIGFRAME32) + +#endif
asm-parisc/compat_siginfo.h renamed from asm-parisc/compat_siginfo.h.orig +2 -0
@@ -0,0 +1,2 @@ +/* We use the generic compat struct */ +#include <asm-generic/compat_siginfo.h>
asm-parisc/compat_signal.h renamed from asm-parisc/compat_signal.h.orig +2 -0
@@ -0,0 +1,2 @@ +/* Use generic */ +#include <asm-generic/compat_signal.h>
asm-parisc/compat_ucontext.h renamed from asm-parisc/compat_ucontext.h.orig +19 -0
@@ -0,0 +1,19 @@ +#ifndef _ASM_PARISC_COMPAT_UCONTEXT_H +#define _ASM_PARISC_COMPAT_UCONTEXT_H + +#include <linux/compat.h> +#include <asm/compat_signal.h> + +/* ELF32 ucontext as seen from an ELF64 kernel */ +struct compat_ucontext { +compat_uint_t uc_flags; +compat_uptr_t uc_link; +compat_stack_t uc_stack;/* struct compat_sigaltstack */ + +compat_uint_t pad[1 ];/*FIXME: ELF32 structure is padded */ + +struct compat_sigcontext uc_mcontext; +compat_sigset_t uc_sigmask;/* mask last for extensibility */ +}; + +#endif /* !_ASM_PARISC_COMPAT_UCONTEXT_H */
compat_signal.c renamed from compat_signal.c.orig +126 -0
126 lines not on this page · raw message
Hi Carlos,
Just a stupid question: against which kernel is it foreseen (I just try against 2.4.23-pa1 but failled; but may be I wrongly capture the patch)?
Thanks,
Joel
Quoted 9 lines
-- Original Message --
From: Carlos O'Donell <[email protected]>
To: [email protected]
Date: Wed, 3 Dec 2003 02:21:26 -0500
Subject: [parisc-linux] [PATCH] ELF32 userspace, ELF64 kernel, and 32-bit signals on hppa. (help needed)
parisc,
*** Help needed, code broken ... ***
Currently our siginfo_t and ucontext_t structures delivered to an ELF32 userspace from an ELF64 kernel are not correct. The kernel thinking userspace is the same bitwidth, writes it's registers an
Quoted 1 line
values as
64-bits. Architectures like sparc64 and ppc64 have rolled their own solutions. I wanted to make it a little more generic.
jejb,
Thanks for the initial cleanup and poking me in the right direction! I promised this out a little while
Quoted 1 line
ack, but as a good hacker I'm up too
late to be thinking straight and get the patch out the door.
What does the patch do?
- Add siginfo_t generic compat structure and code to write it to userspace.
- Add generic compat signal structures.
- Ad
Quoted 1 line
generic kernel code to handle this structure.
- Add lots more PARISC compat structures.
- Add code in our signal path to distinguish the process personality and learn to setup/restore a 32-bit/64-bit rt frame structure.
There is a bug hiding i
Quoted 1 line
the code... I can't find it yet.
Userspace sorta works, but sometimes processes go splat, and I think it has to do with the following:
- In restore_context32 I have to ship the 32-bit value into a 64-bit registers. Should it be sign extended?
Quoted 1 line
= I think yes.
- Is stack address 0xfffffffffaf00410 the same as 0x00000000faf00410? = No?
What to do?
- Enable debugging in singal.c and signal32.c and keep looking for the bug :)
Cheers,
Carlos.
====
arch/parisc/kernel/signal.c
Quoted 1 line
| 277 +++++++++++++++------------
arch/parisc/kernel/signal32.c | 156 +++++++++++++-- arch/parisc/kernel/signal32.h | 22 ++ include/asm-generic/compat_siginfo.h | 154 +++++++++++++++
include/asm-generic/comp
Quoted 1 line
t_signal.h| 28 ++
include/asm-parisc/compat.h | 10 include/asm-parisc/compat_rt_sigframe.h | 25 ++ include/asm-parisc/compat_siginfo.h | 2 include/asm-parisc/compat_signal.h | 2
include/asm-parisc/compat_
Quoted 1 line
context.h| 19 +
include/asm-parisc/rt_sigframe.h | 13 - include/asm-parisc/siginfo.h | 2 include/asm-parisc/ucontext.h | 8 kernel/Makefile | 2
kernel/compat_signal.c
Quoted 1 line
| 126 ++++++++++++
kernel/signal.c | 8 16 files changed, 709 insertions(+), 145 deletions(-)
====
--- arch/parisc/kernel/signal.c 9 Nov 2003 18:57:46 -0000 1.14
+++ arch/parisc/kernel/signal.c 3 Dec 2003 06:4
Quoted 1 line
:32 -0000
@@ -27,19 +27,25 @@
#include <linux/compat.h>
#include <linux/elf.h>
#include <linux/personality.h>
+#include <linux/compat.h>
#include <asm/ucontext.h>
#include <asm/rt_sigframe.h>
#include <asm/uaccess.h>
#include <asm/pgall
Quoted 1 line
c.h>
#include <asm/cacheflush.h>
+#include "signal32.h"
-#define DEBUG_SIG 0
+#define DEBUG_SIG 0
+#define DEBUG_SIG_LEVEL 2
#if DEBUG_SIG
-#define DBG(x) printk x
+#define DBG(LEVEL, ...) \
+ ((DEBUG_SIG_LEVEL >= LEVEL) \
+ ?
Quoted 1 line
printk(__VA_ARGS__): (void) 0)
#else
-#define DBG(x)
+#define DBG(LEVEL, ...)
#endif
+
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
@@ -52,43 +58,6 @@
int do_signal(sigset_t *oldset, struct pt_regs *regs, int in_sy
Quoted 1 line
call);
-int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from) -{
- if (from->si_code < 0)
- return __copy_to_user(to, from, sizeof(siginfo_t));
- else {
- int err;
-
- /*
- * If you change siginfo_t structure, please be sure
- *
Quoted 1 line
his 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_
Quoted 1 line
igno);
- err |= __put_user(from->si_errno, &to->si_errno);
- err |= __put_user((short)from->si_code, &to->si_code);
- switch (from->si_code >> 16) {
- case __SI_FAULT >> 16:
- /* FIXME: should we put the interruption code here? */
-
Quoted 1 line
case __SI_POLL >> 16:
- err |= __put_user((unsigned long)from->si_addr, &to->si_addr);
- break;
- case __SI_CHLD >> 16:
- err |= __put_user(from->si_utime, &to->si_utime);
- err |= __put_user(from->si_stime, &to->si_stime);
-
Quoted 1 line
err |= __put_user(from->si_status, &to->si_status);
- default:
- err |= __put_user(from->si_uid, &to->si_uid);
- err |= __put_user(from->si_pid, &to->si_pid);
- break;
- /* case __SI_RT: This is not generated by the kernel as
Quoted 1 line
f now. */
- }
- return err;
- }
-}
-
/*
* Atomically swap in the new signal mask, and wait for a signal. */
@@ -101,26 +70,27 @@ sys_rt_sigsuspend(sigset_t *unewset, siz
{
sigset_t saveset, newset;
#ifdef __LP64__
- /* XXX FIXM
Quoted 1 line
-- assumes 32-bit user app! */
compat_sigset_t newset32;
- /* XXX: Don't preclude handling different sized sigset_t's. */
- if (sigsetsize != sizeof(compat_sigset_t))
- return -EINVAL;
-
- if (copy_from_user(&newset32, (compat_sigset_t *)
Quoted 1 line
newset, sizeof(newset32)))
- return -EFAULT;
-
- newset.sig[0] = newset32.sig[0] | ((unsigned long)newset32.sig[1] << 32);
-#else
-
- /* XXX: Don't preclude handling different sized sigset_t's. */
- if (sigsetsize != sizeof(sigset_t))
- retu
Quoted 1 line
n
-EINVAL;
-
- if (copy_from_user(&newset, unewset, sizeof(newset)))
- return -EFAULT;
+ if(personality(current->personality) == PER_LINUX32){
+ /* XXX: Don't preclude handling different sized sigset_t's. */
+ if (sigsetsize != sizeof(compat_
Quoted 1 line
igset_t))
+ return -EINVAL;
+ if (copy_from_user(&newset32, (compat_sigset_t *)unewset, sizeof(newset32)))
+ return -EFAULT;
+ sigset_32to64(&newset,&newset32);
+
+ } else
#endif
+ {
+ /* XXX: Don't preclude handling different sized
Quoted 1 line
sigset_t's. */
+ if (sigsetsize != sizeof(sigset_t))
+ return -EINVAL;
+
+ if (copy_from_user(&newset, unewset, sizeof(newset)))
+ return -EFAULT;
+ }
+
sigdelsetmask(&newset, ~_BLOCKABLE);
spin_lock_irq(¤t->sighand->siglo
Quoted 1 line
k);
@@ -161,7 +131,9 @@ restore_sigcontext(struct sigcontext *sc
err |= __copy_from_user(regs->iaoq, sc->sc_iaoq, sizeof(regs->iaoq)); err |= __copy_from_user(regs->iasq, sc->sc_iasq, sizeof(regs->iasq)); err |= __get_user(regs->sar, &sc->sc_
Quoted 1 line
ar);
- DBG(("restore_sigcontext: r28 is %ld\n", regs->gr[28]));
+ DBG(2,"restore_sigcontext: iaoq is 0x%#lx / 0x%#lx\n",
+ regs->iaoq[0],regs->iaoq[1]);
+ DBG(2,"restore_sigcontext: r28 is %ld\n", regs->gr[28]);
return err;
}
@@ -174,6
Quoted 1 line
146,9 @@ sys_rt_sigreturn(struct
pt_regs*regs, i
unsigned long usp = (regs->gr[30] & ~(0x01UL)); unsigned long sigframe_size = PARISC_RT_SIGFRAME_SIZE;
#ifdef __LP64__
+ compat_sigset_t compat_set;
+ struct compat_rt_sigframe * compat_frame;
Quoted 1 line
+
if(personality(current->personality) == PER_LINUX32)
sigframe_size = PARISC_RT_SIGFRAME_SIZE32;
#endif
@@ -182,11 +157,23 @@ sys_rt_sigreturn(struct pt_regs *regs, i
/* Unwind the user stack to get the rt_sigframe structure. */ fram
Quoted 1 line
= (struct
rt_sigframe*)
(usp - sigframe_size);
- DBG(("in sys_rt_sigreturn, frame is %p\n", frame));
-
- if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
- goto give_sigsegv;
+ DBG(2,"sys_rt_sigreturn: frame is %p\n", frame);
Quoted 1 line
+#ifdef __LP64__
+ compat_frame = (struct compat_rt_sigframe *)frame;
+
+ if(personality(current->personality) == PER_LINUX32){
+ DBG(2,"sys_rt_sigreturn: ELF32 process.\n");
+ if (__copy_from_user(&compat_set, &compat_frame->uc.uc_sigmask,
Quoted 1 line
sizeof(compat_set)))
+ goto give_sigsegv;
+ sigset_32to64(&set,&compat_set);
+ } else
+#endif
+ {
+ if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
+ goto give_sigsegv;
+ }
+
sigdelsetmask(&set, ~_BLOCKABLE);
spin
Quoted 1 line
lock_irq(¤t->sighand->siglock);
current->blocked = set;
@@ -194,17 +181,30 @@ sys_rt_sigreturn(struct pt_regs *regs, i
spin_unlock_irq(¤t->sighand->siglock);
/* Good thing we saved the old gr[30], eh? */
- if (restore_sigconte
Quoted 1 line
t(&frame->uc.uc_mcontext, regs))
- goto give_sigsegv;
-
- DBG(("usp: %#08lx stack %p", usp, &frame->uc.uc_stack));
+#ifdef __LP64__
+ if(personality(current->personality) == PER_LINUX32){
+ DBG(1,"sys_rt_sigreturn: compat_frame->uc.uc_mcontext
Quoted 1 line
x%p\n",
+ &compat_frame->uc.uc_mcontext);
+ if (restore_sigcontext32(&compat_frame->uc.uc_mcontext, regs))
+ goto give_sigsegv;
+ DBG(1,"sys_rt_sigreturn: usp %#08lx stack 0x%p\n",
+ usp, &compat_frame->uc.uc_stack);
+ if (do_sigaltst
Quoted 1 line
ck32(&compat_frame->uc.uc_stack, NULL, usp)==-EFAULT)
+ goto give_sigsegv;
+ } else
+#endif
+ {
+ DBG(1,"sys_rt_sigreturn: frame->uc.uc_mcontext 0x%p\n",
+ &frame->uc.uc_mcontext);
+ if (restore_sigcontext(&frame->uc.uc_mcontext, regs))
Quoted 1 line
+ goto give_sigsegv;
+ DBG(1,"sys_rt_sigreturn: usp %#08lx stack 0x%p\n",
+ usp, &frame->uc.uc_stack);
+ if (do_sigaltstack(&frame->uc.uc_stack, NULL, usp) == -EFAULT)
+ goto give_sigsegv;
+ }
+
- /* I don't know why everyone els
Quoted 1 line
assumes they can call this
- with a pointer to a stack_t on the kernel stack. That - makes no sense. Anyway we'll do it like m68k, since we - also are using segmentation in the same way as them. */
- if (do_sigaltst
Quoted 1 line
ck(&frame->uc.uc_stack, NULL, usp)==-EFAULT)
- goto give_sigsegv;
/* If we are on the syscall path IAOQ will not be restored, and
* if we are on the interrupt path we must not corrupt gr31.
@@ -212,14 +212,13 @@ sys_rt_sigreturn(struct p
Quoted 1 line
_regs*regs, i
if (in_syscall)
regs->gr[31] = regs->iaoq[0];
#if DEBUG_SIG
- DBG(("returning to %#lx\n", regs->iaoq[0]));
- DBG(("in sys_rt_sigreturn:\n"));
+ DBG(1,"sys_rt_sigreturn: returning to %#lx, DUMPING REGS:\n", regs->iaoq[0]);
Quoted 1 line
how_regs(regs);
#endif
return;
give_sigsegv:
- DBG(("sys_rt_sigreturn sending SIGSEGV\n"));
+ DBG(1,"sys_rt_sigreturn: Sending SIGSEGV\n");
si.si_signo = SIGSEGV;
si.si_errno = 0;
si.si_code = SI_KERNEL;
@@ -237,9 +236,16 @@ give_
Quoted 1 line
igsegv:
static inline void *
get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size) {
+ /*FIXME: ELF32 vs. ELF64 has different frame_size, but since we
+ don't use the parameter it doesn't matter */
+
+ DBG(1,"get_sigfram
Quoted 1 line
: ka = %#lx, sp = %#lx,
frame_size= %#lx\n",
+ (unsigned long)ka, sp, frame_size);
+
if ((ka->sa.sa_flags & SA_ONSTACK) != 0 && ! on_sig_stack(sp))
sp = current->sas_ss_sp; /* Stacks grow up! */
+ DBG(1,"get_sigframe: Returning sp = %#
Quoted 1 line
x\n", (unsigned long)sp);
return (void *) sp; /* Stacks grow up. Fun. */
}
@@ -259,20 +265,20 @@ setup_sigcontext(struct sigcontext *sc,
err |= __put_user(regs->gr[31]+4, &sc->sc_iaoq[1]); err |= __put_user(regs->sr[3], &sc->sc_iasq[
Quoted 1 line
]);
err |= __put_user(regs->sr[3], &sc->sc_iasq[1]);
- DBG(("setup_sigcontext: iaoq %#lx/%#lx\n",
- regs->gr[31], regs->gr[31]));
+ DBG(1,"setup_sigcontext: iaoq %#lx / %#lx (in syscall)\n",
+ regs->gr[31], regs->gr[31]+4);
} else {
Quoted 1 line
err |= __copy_to_user(sc->sc_iaoq, regs->iaoq, sizeof(regs->iaoq));
err |= __copy_to_user(sc->sc_iasq, regs->iasq, sizeof(regs->iasq));
- DBG(("setup_sigcontext: iaoq %#lx/%#lx\n",
- regs->iaoq[0], regs->iaoq[1]));
+ DBG(1,"setup_sigcontex
Quoted 1 line
: iaoq %#lx / %#lx (not in syscall)\n",
+ regs->iaoq[0], regs->iaoq[1]);
}
err |= __put_user(flags, &sc->sc_flags); err |= __copy_to_user(sc->sc_gr, regs->gr, sizeof(regs->gr)); err |= __copy_to_user(sc->sc_fr, regs->fr, sizeof(regs-
Quoted 1 line
fr));
err |= __put_user(regs->sar, &sc->sc_sar);
- DBG(("setup_sigcontext: r28 is %ld\n", regs->gr[28]));
+ DBG(1,"setup_sigcontext: r28 is %ld\n", regs->gr[28]);
return err;
}
@@ -286,19 +292,53 @@ setup_rt_frame(int sig, struct k_sigact
Quoted 1 line
unsigned long haddr, sigframe_size;
struct siginfo si;
int err = 0;
-
+#ifdef __LP64__
+ compat_int_t compat_val;
+ struct compat_rt_sigframe * compat_frame;
+ compat_sigset_t compat_set;
+#endif
+
usp = (regs->gr[30] & ~(0x01UL));
Quoted 1 line
+ /*FIXME: frame_size parameter is unused, remove it. */
frame = get_sigframe(ka, usp, sizeof(*frame));
- DBG(("setup_rt_frame 1: frame %p info %p\n", frame, info));
+ DBG(1,"setup_rt_frame: frame %p info %p\n", frame, info);
- err |= __co
Quoted 1 line
y_to_user(&frame->info, info, sizeof(siginfo_t));
- err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp); - err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); - err |= __put_user(sas_ss_flags(regs->gr[30]), - &fra
Quoted 1 line
e->uc.uc_stack.ss_flags);
- err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, in_syscall);
- err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
+
+#ifdef __LP64__
+
+ compat_frame = (struct compat_rt_sigframe *)frame;
+
+ if
Quoted 1 line
personality(current->personality)==PER_LINUX32) {
+ DBG(1,"setup_rt_frame: frame->info = 0x%p\n", &compat_frame->info);
+ err |= compat_copy_siginfo_to_user(&compat_frame->info, info);
+ compat_val = (compat_int_t)current->sas_ss_sp;
+ err |=
Quoted 1 line
__put_user(compat_val, &compat_frame->uc.uc_stack.ss_sp);
+ compat_val = (compat_int_t)current->sas_ss_size;
+ err |= __put_user(compat_val, &compat_frame->uc.uc_stack.ss_size);
+ compat_val = sas_ss_flags(regs->gr[30]);
+ err |= __put_user(c
Quoted 1 line
mpat_val,&compat_frame->uc.uc_stack.ss_flags);
+ DBG(1,"setup_rt_frame: frame->uc = 0x%p\n", &compat_frame->uc);
+ DBG(1,"setup_rt_frame: frame->uc.uc_mcontext = 0x%p\n", &compat_frame->uc.uc_mcontext);
+ err |= setup_sigcontext32(&compat_fram
Quoted 1 line
->uc.uc_mcontext, regs,
in_syscall);
+ sigset_64to32(&compat_set,set);
+ err |= __copy_to_user(&compat_frame->uc.uc_sigmask, &compat_set, sizeof(compat_set));
+ } else
+#endif
+ {
+ DBG(1,"setup_rt_frame: frame->info = 0x%p\n", &frame->info);
Quoted 1 line
+ err |= copy_siginfo_to_user(&frame->info, info); + err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp); + err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); + err |= __put_user(sas_ss_flags(regs->gr[30]),
+
Quoted 1 line
&frame->uc.uc_stack.ss_flags);
+ DBG(1,"setup_rt_frame: frame->uc = 0x%p\n", &frame->uc);
+ DBG(1,"setup_rt_frame: frame->uc.uc_mcontext = 0x%p\n", &frame->uc.uc_mcontext);
+ err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, in_syscall);
+
Quoted 1 line
/* FIXME: Should probably be converted aswell for the compat case */
+ err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
+ }
+
if (err)
goto give_sigsegv;
@@ -315,8 +355,8 @@ setup_rt_frame(int sig, struct k_sigacti
{
Quoted 1 line
int sid;
asm ("mfsp %%sr3,%0" : "=r" (sid));
- DBG(("flushing 64 bytes at space %#x offset %p\n",
- sid, frame->tramp));
+ DBG(1,"setup_rt_frame: Flushing 64 bytes at space %#x offset %p\n",
+ sid, frame->tramp);
}
#e
Quoted 1 line
dif
@@ -359,8 +399,8 @@ setup_rt_frame(int sig, struct k_sigacti
haddr = fdesc.addr;
regs->gr[19] = fdesc.gp;
- DBG(("64 bit signal, exe=%#lx, r19=%#lx, in_syscall=%d\n",
- haddr, regs->gr[19], in_syscall));
+ DBG(1,"setup_r
Quoted 1 line
_frame: 64 bit signal, exe=%#lx, r19=%#lx, in_syscall=%d\n",
+ haddr, regs->gr[19], in_syscall);
}
#endif
@@ -391,24 +431,33 @@ setup_rt_frame(int sig, struct k_sigacti
regs->gr[2] = rp; /* userland return pointer
Quoted 1 line
/
regs->gr[26] = sig; /* signal number */
- regs->gr[25] = A(&frame->info); /* siginfo pointer */
- regs->gr[24] = A(&frame->uc); /* ucontext pointer */
- DBG(("making sigreturn frame: %#lx + %#x = %#lx\n",
+#ifdef __LP64__
Quoted 1 line
if(personality(current->personality) == PER_LINUX32){+ regs->gr[25] = A(&compat_frame->info); /* siginfo pointer */
+ regs->gr[24] = A(&compat_frame->uc); /* ucontext pointer */
+ } else
+#endif
+ {
+ regs->gr[25] = A(&frame->info); /* s
Quoted 1 line
ginfo pointer */
+ regs->gr[24] = A(&frame->uc); /* ucontext pointer */
+ }
+
+ DBG(1,"setup_rt_frame: making sigreturn frame: %#lx + %#lx = %#lx\n",
regs->gr[30], sigframe_size,
- regs->gr[30] + sigframe_size));
+ reg
Quoted 1 line
->gr[30] +
sigframe_size);
/* Raise the user stack pointer to make a proper call frame. */ regs->gr[30] = (A(frame) + sigframe_size);
- DBG(("SIG deliver (%s:%d): frame=0x%p sp=%#lx iaoq=%#lx/%#lx rp=%#lx\n",
+ DBG(1,"setup_rt_frame: sig
Quoted 1 line
eliver (%s,%d) frame=0x%p sp=%#lx iaoq=%#lx/%#lx rp=%#lx\n",
current->comm, current->pid, frame, regs->gr[30],
- regs->iaoq[0], regs->iaoq[1], rp));
+ regs->iaoq[0], regs->iaoq[1], rp);
return 1;
give_sigsegv:
- DB
Quoted 1 line
(("
setup_rt_framesending SIGSEGV\n"));
+ DBG(1,"setup_rt_frame: sending SIGSEGV\n");
if (sig == SIGSEGV)
ka->sa.sa_handler = SIG_DFL;
si.si_signo = SIGSEGV;
@@ -431,8 +480,8 @@ handle_signal(unsigned long sig, siginfo
{
struct k_sigac
Quoted 1 line
ion *ka = ¤t->sighand->action[sig-1];
- DBG(("handle_signal(sig=%ld, ka=%p, info=%p, oldset=%p, regs=%p)\n",
- sig, ka, info, oldset, regs));
+ DBG(1,"handle_signal: sig=%ld, ka=%p, info=%p, oldset=%p, regs=%p\n",
+ sig, ka,
Quoted 1 line
nfo, oldset, regs);
/* Set up the stack frame */
if (!setup_rt_frame(sig, ka, info, oldset, regs, in_syscall))
@@ -470,8 +519,8 @@ do_signal(sigset_t *oldset, struct pt_re
struct k_sigaction *ka;
int signr;
- DBG(("do_signal(oldset
Quoted 1 line
0x%p, regs=0x%p, sr7 %#lx, pending %d, in_syscall=%d\n",
- oldset, regs, regs->sr[7], current->sigpending, in_syscall));
+ DBG(1,"\ndo_signal: oldset=0x%p, regs=0x%p, sr7 %#lx, in_syscall=%d\n",
+ oldset, regs, regs->sr[7], in_syscall)
Quoted 1 line
/* Everyone else checks to see if they are in kernel mode at
this point and exits if that's the case. I'm not sure why
@@ -481,12 +530,13 @@ do_signal(sigset_t *oldset, struct pt_re
if (!oldset)
oldset = ¤t->blocked;
- D
Quoted 1 line
G(("do_signal: oldset %08lx:%08lx\n",
- oldset->sig[0], oldset->sig[1]));
+ DBG(1,"do_signal: oldset %08lx / %08lx\n",
+ oldset->sig[0], oldset->sig[1]);
signr = get_signal_to_deliver(&info, regs, NULL);
- /* printk("do_signal: signr =
Quoted 1 line
%d, regs->gr[28] = %ld\n", signr, regs->gr[28]); */
+ DBG(3,"do_signal: signr = %d, regs->gr[28] = %ld\n", signr, regs->gr[28]);
+
if (signr > 0) {
/* Restart a system call if necessary. */ if (in_syscall) {
@@ -495,14 +545,14 @@ do_sig
Quoted 1 line
al(sigset_t *oldset, struct
pt_re
case -ERESTART_RESTARTBLOCK:
current_thread_info()->restart_block.fn = do_no_restart_syscall;
case -ERESTARTNOHAND:
- DBG(("ERESTARTNOHAND: returning -EINTR\n"));
+ DBG(1,"ERESTARTNOHAND:
Quoted 1 line
returning -EINTR\n");
regs->gr[28] = -EINTR; break;
case -ERESTARTSYS:
ka = ¤t->sighand->action[signr-1]; if (!(ka->sa.sa_flags & SA_RESTART)) {
- DBG(("ERESTARTSYS: putting -EINTR\n"));
+ DBG(1,"ERESTART
Quoted 1 line
YS: putting -EINTR\n");
regs->gr[28] = -EINTR; break;
}
@@ -521,9 +571,8 @@ do_signal(sigset_t *oldset, struct pt_re
delivery failed, we need to continue to iterate in this loop so we can deliver the SIGSEGV... */
Quoted 1 line
if (
handle_signal(signr, &info, oldset, regs, in_syscall)) {
- DBG((KERN_DEBUG
- "Exiting do_signal (success), regs->gr[28] = %ld\n",
- regs->gr[28]));
+ DBG(1,KERN_DEBUG "do_signal: Exit (success), regs->gr[28] = %ld\n",
+ regs->gr[2
Quoted 1 line
]);
return 1;
}
}
@@ -577,8 +626,8 @@ do_signal(sigset_t *oldset, struct pt_re
}
}
- DBG(("Exiting do_signal (not delivered), regs->gr[28] = %ld\n",
- regs->gr[28]));
+ DBG(1,"do_signal: Exit (not delivered), regs->gr[28] =
Quoted 1 line
%ld\n",
+ regs->gr[28]);
return 0;
}
parisc/kernel/signal32.c +0 -0
@@ -10,20 +10,32 @@#include <linux/types.h> #include <linux/errno.h>
Quoted 1 line
+#include <asm/compat_signal.h>
#include <asm/uaccess.h>
+
+#include "signal32.h"
#include "sys32.h"
-struct k_sigaction32 {
- struct sigaction32 sa;
-};
+#define DEBUG_COMPAT_SIG 0
+#define DEBUG_COMPAT_SIG_LEVEL 2
+
+#if DEBUG_COMPA
Quoted 1 line
_SIG
+#define DBG(LEVEL, ...) \
+ ((DEBUG_COMPAT_SIG_LEVEL >= LEVEL) \
+ ? printk(__VA_ARGS__) : (void) 0)
+#else
+#define DBG(LEVEL, ...)
+#endif
-static inline void
+#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) +
+inline v
Quoted 1 line
id
sigset_32to64(sigset_t *s64, compat_sigset_t *s32)
{
s64->sig[0] = s32->sig[0] | ((unsigned long)s32->sig[1] << 32);
}
-static inline void
+inline void
sigset_64to32(compat_sigset_t *s32, sigset_t *s64) {
s32->sig[0] = s64->sig[
Quoted 1 line
] &
0xffffffffUL;
@@ -120,16 +132,10 @@ sys32_rt_sigaction(int sig, const struct
return ret;
}
-typedef struct {
- unsigned int ss_sp;
- int ss_flags;
- compat_size_t ss_size;
-} stack_t32;
-
int
-do_sigaltstack32 (const stack_t32 *u
Quoted 1 line
s32,
stack_t32*uoss32, unsigned long sp)
+do_sigaltstack32 (const compat_stack_t *uss32, compat_stack_t *uoss32, unsigned long sp)
{
- stack_t32 ss32, oss32;
+ compat_stack_t ss32, oss32;
stack_t ss, oss;
stack_t *ssp = NULL, *ossp = NULL;
Quoted 1 line
int ret;
@@ -159,4 +165,128 @@ do_sigaltstack32 (const stack_t32 *uss32
}
return ret;
+}
+
+long
+restore_sigcontext32(struct compat_sigcontext *sc, struct pt_regs *regs) +{
+ long err = 0;
+ compat_int_t compat_reg;
+ int regn;
+
Quoted 1 line
+ /* When loading 32-bit values into 64-bit registers make
+ sure to clear the upper 32-bits */
+ DBG(2,"restore_sigcontext32: PER_LINUX32 process\n");
+ DBG(2,"restore_sigcontext32: sc = 0x%p, regs = 0x%p\n",sc,regs);
+ DBG(2,"restore_sigconte
Quoted 1 line
t32:
compat_sigcontextis %#lx bytes\n",sizeof(*sc));
+ for(regn=0; regn < 32; regn++){
+ err |= __get_user(compat_reg,&sc->sc_gr[regn]);
+ regs->gr[regn] = compat_reg;
+ }
+ DBG(2,"restore_sigcontext32: sc->sc_fr = 0x%p\n",sc->sc_fr);
+ /* XX
Quoted 1 line
: BE WARNED FR's are 64-BIT! */
+ err |= __copy_from_user(regs->fr, sc->sc_fr, sizeof(regs->fr));
+
+ /* Better safe than sorry, pass __get_user two things of
+ the same size and let gcc do the upward conversion to
+ 64-bits */
+ err |
Quoted 1 line
__get_user(compat_reg, &sc->sc_iaoq[0]);
+ DBG(2,"restore_sigcontext32: sc->sc_iaoq[0] = %p => %#x\n",
+ &sc->sc_iaoq[0],compat_reg);
+ regs->iaoq[0] = compat_reg;
+ err |= __get_user(compat_reg, &sc->sc_iaoq[1]);
+ DBG(2,"restore_sigcontext32
Quoted 1 line
sc->sc_iaoq[1] = %p => %#x\n",
+ &sc->sc_iaoq[1],compat_reg);
+ regs->iaoq[1] = compat_reg;
+ DBG(2,"restore_sigcontext32: iaoq is %#lx / %#lx\n",
+ regs->iaoq[0],regs->iaoq[1]);
+
+ err |= __get_user(compat_reg, &sc->sc_iasq[0]);
+ reg
Quoted 1 line
->iasq[0] =
compat_reg;
+ err |= __get_user(compat_reg, &sc->sc_iasq[1]);
+ regs->iasq[1] = compat_reg;
+ DBG(2,"restore_sigcontext32: iasq is %#lx / %#lx\n",
+ regs->iasq[0],regs->iasq[1]);
+
+ err |= __get_user(compat_reg, &sc->sc_sar);
+
Quoted 1 line
egs->sar=compat_reg;
+
+ DBG(2,"restore_sigcontext32: r28 is %ld\n", regs->gr[28]);
+ return err;
+}
+
+/*
+ * Set up the sigcontext structure for this process.
+ * This is not an easy task if the kernel is 64-bit, it will require
+ * that
Quoted 1 line
e examine the process personality to determine if we need to
+ * truncate for a 32-bit userspace.
+ */
+long
+setup_sigcontext32(struct compat_sigcontext *sc, struct pt_regs *regs, int in_syscall)
+
+{
+ compat_int_t flags = 0;
+ long err =
Quoted 1 line
;
+ compat_int_t compat_reg;
+ int regn;
+
+ if (on_sig_stack((unsigned long) sc))
+ flags |= PARISC_SC_FLAG_ONSTACK;
+
+ if (in_syscall) {
+ DBG(1,"setup_sigcontext32: in_syscall\n");
+ flags |= PARISC_SC_FLAG_IN_SYSCALL;
+ /* Truncate
Quoted 1 line
gr31 */
+ compat_reg = (compat_int_t)(regs->gr[31]);
+ DBG(2,"setup_sigcontext32: sc->sc_iaoq[0] = %p <= %#x\n",
+ &sc->sc_iaoq[0],compat_reg);
+ /* regs->iaoq is undefined in the syscall return path */
+ err |= __put_user(compat_reg, &sc->
Quoted 1 line
c_iaoq[0]);
+ compat_reg = (compat_int_t)(regs->gr[31]+4);
+ DBG(2,"setup_sigcontext32: sc->sc_iaoq[1] = %p <= %#x\n",
+ &sc->sc_iaoq[1],compat_reg);
+ err |= __put_user(compat_reg, &sc->sc_iaoq[1]);
+ /* Truncate sr3 */
+ compat_reg = (c
Quoted 1 line
mpat_int_t)(regs->sr[3]);
+ err |= __put_user(compat_reg, &sc->sc_iasq[0]);
+ err |= __put_user(compat_reg, &sc->sc_iasq[1]);
+
+ DBG(1,"setup_sigcontext32: iaoq %#lx / %#lx\n",
+ regs->gr[31], regs->gr[31]+4);
+ } else {
+ compat_reg
Quoted 1 line
(compat_int_t)(regs->iaoq[0]);
+ DBG(2,"setup_sigcontext32: sc->sc_iaoq[0] = %p <= %#x\n",
+ &sc->sc_iaoq[0],compat_reg);
+ err |= __put_user(compat_reg, &sc->sc_iaoq[0]);
+ compat_reg = (compat_int_t)(regs->iaoq[1]);
+ DBG(2,"setup_sigcon
Quoted 1 line
ext32: sc->sc_iaoq[1] = %p <= %#x\n",
+ &sc->sc_iaoq[1],compat_reg);
+ err |= __put_user(compat_reg, &sc->sc_iaoq[1]);
+
+ compat_reg = (compat_int_t)(regs->iasq[0]);
+ err |= __put_user(compat_reg, &sc->sc_iasq[0]);
+ compat_reg = (comp
Quoted 1 line
t_int_t)(regs->iasq[1]);
+ err |= __put_user(compat_reg, &sc->sc_iasq[1]);
+
+ DBG(1,"setup_sigcontext32: iaoq %#lx / %#lx\n",
+ regs->iaoq[0], regs->iaoq[1]);
+ }
+
+ err |= __put_user(flags, &sc->sc_flags);
+
+ DBG(1,"setup_sigcontex
Quoted 1 line
32: Truncating.\n");
+ for(regn=0; regn < 32; regn++){
+ /* Truncate a general register */
+ compat_reg = (compat_int_t)(regs->gr[regn]);
+ err |= __put_user(compat_reg, &sc->sc_gr[regn]);
+ }
+ /* Copy the floating point registers (same size)
Quoted 1 line
*/
+ /* XXX: BE WARNED FR's are 64-BIT! */
+ err |= __copy_to_user(sc->sc_fr, regs->fr, sizeof(regs->fr));
+ compat_reg = (compat_int_t)(regs->sar);
+ err |= __put_user(compat_reg, &sc->sc_sar);
+
+ DBG(1,"setup_sigcontext32: r28 is %ld\n", regs
Quoted 1 line
Quoted 1 line
gr[28]);
+
+ return err;
}
asm-parisc/compat.h +0 -0
@@ -24,6 +24,7 @@ typedef u16 compat_nlink_t;typedef u16 compat_ipc_pid_t ;typedef s32 comp
Quoted 1 line
t_daddr_t;
typedef u32 compat_caddr_t;
+typedef u32 compat_timer_t;
typedef s32 compat_int_t;
typedef s32 compat_long_t;
@@ -99,6 +100,15 @@ struct compat_statfs {
s32 f_namelen;
s32 f_frsize;
s32 f_spare[5];
+};
+
+struct com
Quoted 1 line
at_sigcontext{
+ compat_int_t sc_flags;
+ compat_int_t sc_gr[32]; /* PSW in sc_gr[0] */
+ u64 sc_fr[32]; /* FIXME, do we need other state info? */
+ compat_int_t sc_iasq[2];
+ compat_int_t sc_iaoq[2];
+ compat_int_t sc_sar; /* cr11 */
};
Quoted 1 line
define
COMPAT_RLIM_INFINITY0xffffffff
asm-parisc/rt_sigframe.h +0 -0
@@ -1,22 +1,13 @@#ifndef _ASM_PARISC_RT_SIGFRAME_H#define _ASM_PARISC_RT_
Quoted 1 line
IGFRAME_H
+#include <asm/compat_rt_sigframe.h>
+
struct rt_sigframe {
unsigned int tramp[4];
struct siginfo info;
struct ucontext uc;
};
-
-/*
- * The 32-bit ABI wants at least 48 bytes for a function call frame:
- * 16 bytes for
Quoted 1 line
rg0-arg3, and 32 bytes for magic (the only part of
- * which Linux/parisc uses is sp-20 for the saved return pointer...)
- * Then, the stack pointer must be rounded to a cache line (64 bytes).
- */
-#define SIGFRAME32 64
-#define FUNCTIONCALLFRAM
Quoted 1 line
32 48
-#define PARISC_RT_SIGFRAME_SIZE32 \
- (((sizeof(struct rt_sigframe) + FUNCTIONCALLFRAME32) + SIGFRAME32) & -SIGFRAME32)
#ifdef __LP64__
#define SIGFRAME 128
--- include/asm-parisc/siginfo.h 29 Jul 2003 17:02:04 -0000 1.1
+++ incl
Quoted 1 line
de/asm-parisc/siginfo.h3 Dec 2003 06:49:35 -0000
@@ -1,8 +1,6 @@
#ifndef _PARISC_SIGINFO_H
#define _PARISC_SIGINFO_H
-#define HAVE_ARCH_COPY_SIGINFO_TO_USER
-
#include <asm-generic/siginfo.h>
/*
--- include/asm-parisc/ucontext.h 29 J
Quoted 1 line
l 2003 17:02:04 -0000 1.1
+++ include/asm-parisc/ucontext.h 3 Dec 2003 06:49:35 -0000
@@ -1,12 +1,12 @@
-#ifndef _ASMPARISC_UCONTEXT_H
-#define _ASMPARISC_UCONTEXT_H
+#ifndef _ASM_PARISC_UCONTEXT_H
+#define _ASM_PARISC_UCONTEXT_H
struct ucon
Quoted 1 line
ext {
- unsigned long uc_flags;
+ unsigned int uc_flags;
struct ucontext *uc_link;
stack_t uc_stack;
struct sigcontext uc_mcontext;
sigset_t uc_sigmask; /* mask last for extensibility */
};
-#endif /* !_ASMPARISC_UCONTEXT_
Quoted 1 line
*/
+#endif /* !_ASM_PARISC_UCONTEXT_H */
Makefile +0 -0
@@ -5,7 +5,7 @@ obj-y = sched.o fork.o exec_domain.o panic.o printk.o profile.o \ exit.o itimer.o
Quoted 1 line
time.o softirq.o resource.o \
sysctl.o capability.o ptrace.o timer.o user.o \
- signal.o sys.o kmod.o workqueue.o pid.o \
+ compat_signal.o signal.o sys.o kmod.o workqueue.o pid.o \
rcupdate.o intermodule.o extable.o params.o po
Quoted 1 line
ix-timers.o
obj-$(CONFIG_FUTEX) += futex.o
signal.c +0 -0
@@ -24,9 +24,11 @@#include <linux/binfmts.h> #include <linux/security.h> #include <linux/ptrace.h
Quoted 1 line
+#include <linux/personality.h>
#include <asm/param.h>
#include <asm/uaccess.h>
#include <asm/siginfo.h>
+#include <asm/compat_siginfo.h>
/*
* SLAB caches for signal bits.
@@ -2006,6 +2008,12 @@ int copy_siginfo_to_user(siginfo_t __us
Quoted 1 line
if (from->si_code < 0)
return __copy_to_user(to, from, sizeof(siginfo_t))
? -EFAULT : 0;
+
+ /* Use compat_siginfo_t with 32-bit signals */
+ if(personality(current->personality) == PER_LINUX32){
+ return compat_copy_siginfo_to_user((
Quoted 1 line
ompat_siginfo_t__user*)to,from);
+ }
+
/*
* If you change siginfo_t structure, please be sure
* this code is fixed accordingly.
--- arch/parisc/kernel/signal32.h.orig 1969-12-31 19:00:00.000000000 -0500
+++ arch/parisc/kernel/signal32
Quoted 1 line
h 2003-11-28 15:18:40.000000000 -0500
@@ -0,0 +1,22 @@
+#ifndef _PARISC64_KERNEL_SIGNAL32_H
+#define _PARISC64_KERNEL_SIGNAL32_H
+
+#include <linux/compat.h>
+#include <asm/compat_signal.h>
+
+/* ELF32 signal handling */
+
+struct k_sigaction
Quoted 1 line
2 {
+ struct compat_sigaction sa;
+};
+
+void sigset_32to64(sigset_t *s64, compat_sigset_t *s32); +void sigset_64to32(compat_sigset_t *s32, sigset_t *s64); +int do_sigaltstack32 (const compat_stack_t *uss32,
+ compat_stack_t *uoss32, unsigned
Quoted 1 line
ong sp);
+long restore_sigcontext32(struct compat_sigcontext *sc,
+ struct pt_regs *regs);
+long setup_sigcontext32(struct compat_sigcontext *sc,
+ struct pt_regs *regs, int in_syscall);
+
+#endif
--- include/asm-generic/compat_siginfo.h.ori
Quoted 1 line
1969-12-31 19:00:00.000000000 -0500
+++ include/asm-generic/compat_siginfo.h 2003-11-28 07:49:19.000000000 -0500
@@ -0,0 +1,154 @@
+#include <linux/compiler.h>
+#include <linux/types.h>
+#include <linux/compat.h>
+
+#ifndef _ASM_GENERIC_COMPAT_
Quoted 1 line
IGINFO_H
+#define _ASM_GENERIC_COMPAT_SIGINFO_H
+
+/* compat view of sigval_t */
+typedef union compat_sigval {
+ compat_int_t sival_int;
+ compat_uptr_t sival_ptr;
+} compat_sigval_t;
+
+/*
+ * This is the size (including padding) of the par
Quoted 1 line
of the
+ * struct siginfo that is before the union.
+ */
+#ifndef __ARCH_SI_COMPAT_PREAMBLE_SIZE
+#define __ARCH_SI_COMPAT_PREAMBLE_SIZE (3 * sizeof(int))
+#endif
+
+#define SI_COMPAT_MAX_SIZE 128
+#ifndef SI_COMPAT_PAD_SIZE
+#define SI_COMPA
Quoted 1 line
_PAD_SIZE((SI_COMPAT_MAX_SIZE-__ARCH_SI_COMPAT_PREAMBLE_SIZE) / sizeof(int))
+#endif
+
+/* ELF32 view of si.uid_t */
+#ifndef __ARCH_SI_COMPAT_UID_T
+#define __ARCH_SI_COMPAT_UID_T compat_uid_t
+#endif
+
+/* ELF32 view of si.band_t */
+#ifn
Quoted 1 line
ef
__ARCH_SI_COMPAT_BAND_T
+#define __ARCH_SI_COMPAT_BAND_T compat_int_t
+#endif
+
+#ifndef HAVE_ARCH_COMPAT_SIGINFO_T
+
+/* Compat (ELF32) view of siginfo_t */
+typedef struct compat_siginfo {
+ compat_int_t si_signo;
+ compat_int_t si_errno;
Quoted 1 line
+ compat_int_t si_code;
+
+ union {
+ compat_int_t _pad[SI_COMPAT_PAD_SIZE];
+
+ /* kill() */
+ struct {
+ compat_pid_t _pid; /* sender's pid */
+ __ARCH_SI_COMPAT_UID_T _uid; /* sender's uid */
+ } _kill;
+
+ /* POSIX.1b timers */
Quoted 1 line
+ struct {
+ compat_timer_t _tid; /* timer id */
+ compat_int_t _overrun; /* overrun count */
+ char _pad[sizeof( __ARCH_SI_UID_T) - sizeof(int)];
+ compat_sigval_t _sigval; /* same as below */
+ compat_int_t _sys_private; /* no
Quoted 1 line
to be passed to user */
+ } _timer;
+
+ /* POSIX.1b signals */
+ struct {
+ compat_pid_t _pid; /* sender's pid */
+ __ARCH_SI_COMPAT_UID_T _uid; /* sender's uid */
+ compat_sigval_t _sigval;
+ } _rt;
+
+ /* SIGCHLD */
+ struct
Quoted 1 line
+ compat_pid_t _pid; /* which child */
+ __ARCH_SI_COMPAT_UID_T _uid; /* sender's uid */
+ compat_int_t _status; /* exit code */
+ compat_clock_t _utime;
+ compat_clock_t _stime;
+ } _sigchld;
+
+ /* SIGILL, SIGFPE, SIGSEGV, SIGB
Quoted 1 line
S */
+ struct {
+ compat_uptr_t _addr; /* faulting insn/memory ref. */
+#ifdef __ARCH_SI_TRAPNO
+ compat_int_t _trapno; /* TRAP # which caused the signal */
+#endif
+ } _sigfault;
+
+ /* SIGPOLL */
+ struct {
+ __ARCH_SI_COMPAT_BAND
Quoted 1 line
T
_band; /*POLL_IN,POLL_OUT,POLL_MSG*/
+ compat_int_t _fd;
+ } _sigpoll;
+ } _sifields;
+} compat_siginfo_t;
+#endif
+
+/*
+ * sigevent definitions
+ *
+ * It seems likely that SIGEV_THREAD will have to be handled from
+ * userspace
Quoted 1 line
libpthread transmuting it to
SIGEV_SIGNAL, which the
+ * thread manager then catches and does the appropriate nonsense.
+ * However, everything is written out here so as to not get lost.
+ */
+
+#define SIGEV_COMPAT_MAX_SIZE 64
+#ifndef SIGEV_CO
Quoted 1 line
PAT_PAD_SIZE
+#define SIGEV_COMPAT_PAD_SIZE ((SIGEV_COMPAT_MAX_SIZE/sizeof(int)) - 3)
+#endif
+
+#ifndef HAVE_ARCH_COMPAT_SIGEVENT_T
+
+/* ELF32 view of sigevent_t */
+typedef struct compat_sigevent {
+ compat_sigval_t sigev_value;
+ compat_in
Quoted 1 line
_t
sigev_signo;
+ compat_int_t sigev_notify;
+ union {
+ compat_int_t _pad[SIGEV_COMPAT_PAD_SIZE];
+ compat_int_t _tid;
+
+ struct {
+ compat_uptr_t _function;
+ compat_uptr_t _attribute; /* really pthread_attr_t */
+ } _sigev_thread;
Review
Quoted 1 line
(quoted diff) +1
-0+ } _sigev_un;
+} compat_sigevent_t;
+
+#endif
+
+#ifdef __KERNEL__
+
+struct compat_siginfo;
+/*void do_schedule_next_timer(struct siginfo *info);*/ +
+#ifndef HAVE_ARCH_COMPAT_COPY_SIGINFO
+
+#include <linux/string.h>
+
+static inline v
Quoted 1 line
id compat_copy_siginfo(struct
compat_siginfo*to, structcompat_siginfo
*from)
+{
+ if (from->si_code < 0)
+ memcpy(to, from, sizeof(*to));
+ else
+ /* _sigchld is currently the largest know union member */
+ memcpy(to, from, __ARCH_SI_COMPAT_
Quoted 1 line
REAMBLE_SIZE+sizeof(from->_sifields._sigchld));
+}
+
+#endif
+
+extern int compat_copy_siginfo_to_user(compat_siginfo_t __user *to, struct siginfo *from);
+
+#endif /* __KERNEL__ */
+
+#endif
--- include/asm-generic/compat_signal.h.orig 196
Quoted 1 line
-12-31 19:00:00.000000000 -0500
+++ include/asm-generic/compat_signal.h 2003-12-02 23:01:44.000000000 -0500
@@ -0,0 +1,28 @@
+#ifndef _ASM_GENERIC_COMPAT_SIGNAL_H
+#define _ASM_GENERIC_COMPAT_SIGNAL_H
+
+# ifndef __ASSEMBLY__
+# include <linux/
Quoted 1 line
ypes.h>
+
+typedef compat_uptr_t compat_sighandler_t;
+
+typedef struct compat_sigaltstack {
+ compat_uptr_t ss_sp;
+ compat_int_t ss_flags;
+ compat_size_t ss_size;
+} compat_stack_t;
+
+# ifdef __KERNEL__
+
+/* Most things should be clea
Quoted 1 line
enough to redefine this at will, if care
+ is taken to make libc match. */
+
+struct compat_sigaction {
+ compat_sighandler_t sa_handler;
+ compat_uint_t sa_flags;
+ compat_sigset_t sa_mask; /* mask last for extensibility */
+};
+
+# end
Quoted 1 line
f /*
__KERNEL__*/
+# endif /* !__ASSEMBLY */
+#endif /* _ASM_GENERIC_COMPAT_SIGNAL_H */
--- include/asm-parisc/compat_rt_sigframe.h.orig 1969-12-31 19:00:00.000000000
-0500
+++ include/asm-parisc/compat_rt_sigframe.h 2003-12-02 23:11:20.000000000
Quoted 1 line
0500
@@ -0,0 +1,25 @@
+#include<linux/compat.h>
+#include<asm/compat_siginfo.h>
+#include<asm/compat_ucontext.h>
+
+#ifndef _ASM_PARISC_COMPAT_RT_SIGFRAME_H
+#define _ASM_PARISC_COMPAT_RT_SIGFRAME_H
+
+struct compat_rt_sigframe {
+ compat_uin
Quoted 1 line
_t tramp[4];
+ compat_siginfo_t info;
+ struct compat_ucontext uc;
+};
+
+/*
+ * The 32-bit ABI wants at least 48 bytes for a function call frame:
+ * 16 bytes for arg0-arg3, and 32 bytes for magic (the only part of
+ * which Linux/parisc uses
Quoted 1 line
s sp-20 for the saved return pointer...)
+ * Then, the stack pointer must be rounded to a cache line (64 bytes).
+ */
+#define SIGFRAME32 64
+#define FUNCTIONCALLFRAME32 48
+#define PARISC_RT_SIGFRAME_SIZE32 \
+ (((sizeof(struct compat_rt_si
Quoted 1 line
frame) + FUNCTIONCALLFRAME32) + SIGFRAME32) & -SIGFRAME32)
+
+#endif
--- include/asm-parisc/compat_siginfo.h.orig 1969-12-31 19:00:00.000000000
-0500
+++ include/asm-parisc/compat_siginfo.h 2003-11-21 06:11:59.000000000 -0500
@@ -0,0 +1,2 @@
+/*
Quoted 1 line
e use the generic compat struct */
+#include <asm-generic/compat_siginfo.h>
--- include/asm-parisc/compat_signal.h.orig 1969-12-31 19:00:00.000000000
-0500
+++ include/asm-parisc/compat_signal.h 2003-11-28 06:22:13.000000000 -0500
@@ -0,0 +1,2 @@
Quoted 1 line
/* Use generic */
+#include <asm-generic/compat_signal.h>
--- include/asm-parisc/compat_ucontext.h.orig 1969-12-31 19:00:00.000000000
-0500
+++ include/asm-parisc/compat_ucontext.h 2003-12-02 23:45:17.000000000 -0500
@@ -0,0 +1,19 @@
+#ifndef _ASM
Quoted 1 line
PARISC_COMPAT_UCONTEXT_H
+#define _ASM_PARISC_COMPAT_UCONTEXT_H
+
+#include<linux/compat.h> +#include<asm/compat_signal.h>
+
+/* ELF32 ucontext as seen from an ELF64 kernel */ +struct compat_ucontext {
+ compat_uint_t uc_flags;
+ compat_uptr_t
Quoted 1 line
uc_link;
+ compat_stack_t uc_stack; /* struct compat_sigaltstack */
+
+ compat_uint_t pad[1]; /*FIXME: ELF32 structure is padded */
+
+ struct compat_sigcontext uc_mcontext;
+ compat_sigset_t uc_sigmask; /* mask last for extensibility */
+};
Quoted 1 line
+
+#endif /* !_ASM_PARISC_COMPAT_UCONTEXT_H */
compat_signal.c renamed from compat_signal.c.orig +3 -0
@@ -0,0 +1,126 @@ +/* +* Copyright (C) 2003 Carlos O'Donell +*
Quoted 1 line
+ * 2003-12-20 Carlos O'Donell
+ * Copied linux/kernel/compat_signal.c (copy_siginfo_to_user) + * and modified to use compat_siginfo_t for thunking down to + * 32-bit userspace with an ELF64 kernel.
+ *
Quoted 1 line
+ * 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; either version 2 of the License, or (at
+ * your option) an
Quoted 1 line
later version.
+ *
+ * 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.
Quoted 1 line
See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 0
Quoted 1 line
139, USA.
+ *
+ */
+
+/*#define __KERNEL_SYSCALLS__*/
+
+#include <asm/errno.h>
+#include <asm/compat_siginfo.h>
+#include <asm/uaccess.h>
+#include <asm/siginfo.h>
+
+#ifndef HAVE_ARCH_COMPAT_COPY_SIGINFO_TO_USER
+
+int compat_copy_siginf
Quoted 1 line
_to_user(compat_siginfo_t __user *to, siginfo_t *from)
+{
+ int err;
+ compat_siginfo_t compat_from;
+
+ if (!access_ok (VERIFY_WRITE, to, sizeof(compat_siginfo_t)))
+ return -EFAULT;
+
+ /*
+ * If you change siginfo_t structure, please be
Quoted 1 line
sure
+ * 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.
+ */
+
+ /* Convert structure, don't leak
Quoted 1 line
anything in the copy */
+ memset(&compat_from,'\0',sizeof(compat_siginfo_t));
+ compat_from.si_signo = (compat_int_t)(from->si_signo);
+ compat_from.si_errno = (compat_int_t)(from->si_errno);
+ compat_from.si_code = (compat_int_t)(from->si_code);
Quoted 1 line
+ if (from->si_code < 0)
+ return __copy_to_user(to, &compat_from, sizeof(compat_siginfo_t))
+ ? -EFAULT : 0;
+
+ err = __put_user(compat_from.si_signo, &to->si_signo);
+ err |= __put_user(compat_from.si_errno, &to->si_errno);
+ err |= __p
Quoted 1 line
t_user(compat_from.si_code, &to->si_code);
+
+ switch (from->si_code & __SI_MASK) {
+ case __SI_KILL:
+ compat_from.si_pid = (compat_pid_t)(from->si_pid);
+ compat_from.si_uid = (__ARCH_SI_COMPAT_UID_T)(from->si_uid);
+ err |= __put_user(comp
Quoted 1 line
t_from.si_pid,
&to->si_pid);
+ err |= __put_user(compat_from.si_uid, &to->si_uid);
+ break;
+ case __SI_TIMER:
+ compat_from.si_pid = (compat_timer_t)(from->si_tid);
+ compat_from.si_overrun = (compat_int_t)(from->si_overrun);
+ compat_from.
Quoted 1 line
i_ptr= (compat_uptr_t)((u64)(from->si_ptr) &0xffffffffUL);
+ err |= __put_user(compat_from.si_tid, &to->si_tid); + err |= __put_user(compat_from.si_overrun, &to->si_overrun); + err |= __put_user(compat_from.si_ptr, &to->si_ptr);
+ break;
+ c
Quoted 1 line
se
__SI_POLL:
+ compat_from.si_band = (__ARCH_SI_COMPAT_BAND_T)(from->si_band);
+ compat_from.si_fd = (compat_int_t)(from->si_fd);
+ err |= __put_user(compat_from.si_band, &to->si_band);
+ err |= __put_user(compat_from.si_fd, &to->si_fd);
+ b
Quoted 1 line
eak;
+ case __SI_FAULT:
+ compat_from.si_addr = (compat_uptr_t)((u64)(from->si_addr) & 0xffffffffUL);
+ err |= __put_user(compat_from.si_addr, &to->si_addr);
+#ifdef __ARCH_SI_TRAPNO
+ compat_from.si_trapno = (compat_int_t)(from->si_addr);
+
Quoted 1 line
rr |=
__put_user(compat_from.si_trapno, &to->si_trapno);
+#endif
+ break;
+ case __SI_CHLD:
+ compat_from.si_pid = (compat_pid_t)(from->si_pid);
+ compat_from.si_uid = (__ARCH_SI_COMPAT_UID_T)(from->si_uid);
+ compat_from.si_status = (compat_
Quoted 1 line
nt_t)(from->si_status);
+ compat_from.si_utime = (compat_clock_t)(from->si_utime);
+ compat_from.si_stime = (compat_clock_t)(from->si_stime);
+ err |= __put_user(compat_from.si_pid, &to->si_pid);
+ err |= __put_user(compat_from.si_uid, &to->si_
Quoted 1 line
id);
+ err |= __put_user(compat_from.si_status, &to->si_status); + err |= __put_user(compat_from.si_utime, &to->si_utime); + err |= __put_user(compat_from.si_stime, &to->si_stime);
+ break;
+ case __SI_RT: /* This is not generated by the kerne
Quoted 1 line
as of now. */
+ compat_from.si_pid = (compat_pid_t)(from->si_pid);
+ compat_from.si_uid = (__ARCH_SI_COMPAT_UID_T)(from->si_uid);
+ compat_from.si_int = (compat_int_t)(from->si_int);
+ compat_from.si_ptr = (compat_uptr_t)((u64)(from->si_ptr) &
Quoted 1 line
0xffffffffUL);
+ err |= __put_user(compat_from.si_pid, &to->si_pid); + err |= __put_user(compat_from.si_uid, &to->si_uid); + err |= __put_user(compat_from.si_int, &to->si_int); + err |= __put_user(compat_from.si_ptr, &to->si_ptr);
+ break;
+
Quoted 1 line
default: /* this is just in case for now ... */
+ compat_from.si_pid = (compat_pid_t)(from->si_pid);
+ compat_from.si_uid = (__ARCH_SI_COMPAT_UID_T)(from->si_uid);
+ err |= __put_user(compat_from.si_pid, &to->si_pid);
+ err |= __put_user(compat
Quoted 1 line
from.si_uid,
&to->si_uid);
+ break;
+ }
+ return err;
+}
+
+#endif
_______________________________________________
parisc-linux mailing list
[email protected]
http://lists.parisc-linux.org/mailman/listinfo/parisc-linux
-------------------------------------------------------------------------
Tiscali ADSL: 12 mois à 29,50 €/mois! L'Internet rapide, c'est pour tout le monde.
http://reg.tiscali.be/default.asp?lg=fr
Quoted 9 lines · Carlos O'Donell
parisc,
*** Help needed, code broken ... ***
There is a bug hiding in the code... I can't find it yet. Userspace sorta works, but sometimes processes go splat, and I think it has to do with the following:
Quoted 5 lines
- In
restore_context32I have to ship the 32-bit value into a 64-bit registers. Should it be sign extended?
= I think yes.
- Is stack address0xfffffffffaf00410the same as0x00000000faf00410? = No?
This turned out to be the issue. I just did a zero-extended load into an unsigned variable and *everything* works now. I need to go into more testing now.
c.