Skip to contentSkip to conversation

ELF32 userspace, ELF64 kernel, and 32-bit signals on hppa. (help needed)

PATCH In review Carlos O'Donell 2 participants 3 messages Dec 3, 2003 Kbuild

lore
Share & tools
lore
#0 lore raw

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(&current->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, 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;
+	
 	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(&current->sighand->siglock);
 	current->blocked = set;
@@ -194,17 +181,30 @@ sys_rt_sigreturn(struct pt_regs *regs, i
 	spin_unlock_irq(&current->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, 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]);
 	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_sigacti
 	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));
+	/*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 = &current->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_re
 	struct 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_re
 	if (!oldset)
 		oldset = &current->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_re
 		        case -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 = &current->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_re
 		   delivery 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_H
 
 struct 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 __use
 	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((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

#1 lore raw

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(&current->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(&current->sighand->siglock);

current->blocked = set;
@@ -194,17 +181,30 @@ sys_rt_sigreturn(struct pt_regs *regs, i
spin_unlock_irq(&current->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_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_sigac

Quoted 1 line

ion *ka = &current->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 = &current->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 = &current->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_sigcontext is %#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_INFINITY 0xffffffff

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.h 3 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, struct compat_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

#2 lore raw
In reply to Carlos O'Donell
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_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?

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.