sigaltstack() patch v2 works with fork() now

Melvin Smith (msmith@quix.robins.af.mil)
Sun, 26 May 1996 00:45:09 -0400 (EDT)


Ok, scrap the old patch. This code supports forking before or
after sigaltstack() installation. Also the fork support is not
arch dependant so if the other ports will implement the syscall
then the core should work with it. Follows is a test program
to play with which also tests forking with sigstacks. The patch is for
kernel pre2.0.7 and follows the test program.

-Melvin S.

TODO: Test with clone flags ( I don't expect it to work ) but I'm
not sure what the expected action is when we mix sig-stack with
CLONE_VM | CLONE_SIG, anyone?

/*
* Test program to test sigaltstack() system call.
* Does a stack overflow, which normally linux will not be able
* to deliver. There are other ways of demonstrating but this is
* the easiest. Of course apply the sigaltstack() patch first or
* you wont see diddly.
*
* Version 2 - Added initial testing of fork() with sig-stack.
*/

#include <sys/signal.h>
#include <asm/unistd.h>
#include <stdio.h>
#include <errno.h>
#include <setjmp.h>

static inline _syscall2(int,sigaltstack, stack_t *, sa_in, stack_t *, sa_out )

struct sigaction act;

#define GET_STACK( x ) \
__asm__ __volatile("movl %%esp, %0\n\t" : "=q" (x) : :"%0" )

pid_t pid;
jmp_buf back;

void handler()
{
unsigned long ss_sp;
printf( "[%d] Caught SIGSEGV and handled stack overflow correctly.\n", pid );
GET_STACK( ss_sp );
printf( "[%d] signal handler stack pointer = %p\n", pid, ss_sp );
longjmp( back, 1 );
}

void recurse()
{
char buf[ 4096 ];
recurse();
}

int main()
{
long ret;
struct sigaltstack sa, sa_old;
unsigned long ss_sp;

/* Step 1 - setup your alternate sig-stack */
sa.ss_sp = malloc( MINSIGSTKSZ * 2);
if( !sa.ss_sp )
printf( "malloc failed\n" );

sa.ss_size = MINSIGSTKSZ * 2;
sa.ss_flags = 0;

if( sigaltstack( &sa, &sa_old ) < 0 ) {
printf( "failed to install alt-stack!\n" );
exit(0);
}

/* Step 2 - setup a sighandler and specify we want it delivered
* on the alternate stack */
act.sa_handler = handler;
act.sa_flags = SA_ONSTACK;

if( sigaction( SIGSEGV, &act, 0 ) < 0 ) {
printf( "failed to install sig-handler!\n" );
exit(0);
}

/* Step 3 - Generate a stack-overflow with recursion.
* Without the sigaltstack you will not handle the SIGSEGV
* because there will be no more space left on the processes
* main stack for the call.
* With the patch, you will catch it correctly! Wheee!!
*/

pid = fork();
if( pid < 0 ) {
printf( "fork() failed.\n" );
exit(0);
}

if( pid == 0 )
pid = getppid();
else
sleep(1); /* let child get pid first */

GET_STACK( ss_sp );
printf( "[%d] main stack pointer = %p\n", pid, ss_sp );

if( setjmp( back ) ) {
printf( "[%d] recovered from stack-overflow.\n", pid );
GET_STACK( ss_sp );
printf( "[%d] main stack pointer after recover = %p\n", pid, ss_sp );
exit(0);
}

recurse();
}

---PATCH STARTS---

diff -urN /usr/src/linux-pre2.0.7/arch/i386/kernel/entry.S /usr/src/linux/arch/i386/kernel/entry.S
--- /usr/src/linux-pre2.0.7/arch/i386/kernel/entry.S Mon May 13 16:23:08 1996
+++ /usr/src/linux/arch/i386/kernel/entry.S Sat May 25 22:46:07 1996
@@ -674,4 +674,5 @@
.long SYMBOL_NAME(sys_sched_rr_get_interval)
.long SYMBOL_NAME(sys_nanosleep)
.long SYMBOL_NAME(sys_mremap)
- .space (NR_syscalls-163)*4
+ .long SYMBOL_NAME(sys_sigaltstack)
+ .space (NR_syscalls-164)*4
diff -urN /usr/src/linux-pre2.0.7/arch/i386/kernel/process.c /usr/src/linux/arch/i386/kernel/process.c
--- /usr/src/linux-pre2.0.7/arch/i386/kernel/process.c Fri Apr 19 11:35:15 1996
+++ /usr/src/linux/arch/i386/kernel/process.c Sun May 26 00:11:16 1996
@@ -267,6 +267,12 @@
for (i=0 ; i<8 ; i++)
current->debugreg[i] = 0;

+ /* zero sigaltstack */
+ if( current->sa_info ) {
+ kfree( current->sa_info );
+ current->sa_info = 0;
+ }
+
/*
* Forget coprocessor state..
*/
diff -urN /usr/src/linux-pre2.0.7/arch/i386/kernel/signal.c /usr/src/linux/arch/i386/kernel/signal.c
--- /usr/src/linux-pre2.0.7/arch/i386/kernel/signal.c Mon May 6 09:31:18 1996
+++ /usr/src/linux/arch/i386/kernel/signal.c Sat May 25 22:46:45 1996
@@ -2,6 +2,10 @@
* linux/arch/i386/kernel/signal.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
+ *
+ * 05.25.96 Melvin Smith
+ * Started reliable signal handling. Signal stacks implemented.
+ * Hopefully SA_SIGINFO is next.
*/

#include <linux/config.h>
@@ -11,6 +15,7 @@
#include <linux/kernel.h>
#include <linux/signal.h>
#include <linux/errno.h>
+#include <linux/malloc.h>
#include <linux/wait.h>
#include <linux/ptrace.h>
#include <linux/unistd.h>
@@ -72,10 +77,83 @@
restore_i387_soft(buf);
#endif
}
-
+
+/* Right now I'm checking not only instack but instack->ss_sp, maybe wrong
+ * but I think it is safe. System shouldn't let user install stack if it
+ * is too small anyway
+ */
+asmlinkage int sys_sigaltstack( const struct sigaltstack * sa_in,
+ struct sigaltstack *sa_out )
+{
+ /* In case sa_in == sa_out */
+ struct sigaltstack sa_temp, sa_new;
+
+ /* If old sigstack pointer then save old info in that pointer */
+ if( sa_out ) {
+ if( verify_area( VERIFY_WRITE, sa_out, sizeof( struct sigaltstack ) ) )
+ return -EINVAL;
+
+ if( !current->sa_info )
+ memset( &sa_temp, 0, sizeof( struct sigaltstack ) );
+ else
+ memcpy( &sa_temp, current->sa_info, sizeof( struct sigaltstack ) );
+ }
+
+ /* If new sigstack is passed then update current */
+ sa_new.ss_sp = 0;
+ if( sa_in ) {
+ if( verify_area( VERIFY_READ, sa_in, sizeof( struct sigaltstack ) ) )
+ return -EINVAL;
+ memcpy_fromfs( &sa_new, sa_in, sizeof( *sa_in ) );
+ }
+
+ if( sa_new.ss_sp ) {
+ /* If SS_DISABLE, ignore stack info */
+ if( !( sa_new.ss_flags & SS_DISABLE ) ) {
+ /* Can't change stack while executing on that stack */
+ if( current->sa_info && (current->sa_info->ss_flags & SA_ONSTACK) )
+ return -EINVAL;
+
+ /* Make sure the stack is as big as the user says it is, either
+ * way it must be at least MINSIGSTKSZ bytes */
+ if( sa_new.ss_size < MINSIGSTKSZ )
+ return -EINVAL;
+ else if( verify_area( VERIFY_WRITE, sa_new.ss_sp, sa_new.ss_size ) )
+ return -EINVAL;
+ }
+
+ if( !current->sa_info ) {
+ current->sa_info = (struct sigaltstack *)kmalloc( sizeof( struct sigaltstack ),
+ GFP_KERNEL );
+ if( !current->sa_info )
+ return -ENOMEM;
+ }
+
+ memcpy( current->sa_info, &sa_new, sizeof( struct sigaltstack ) );
+ /* i386 stack starts at high mem.
+ * This is transparent to caller, reset if sigaltstack queried.
+ */
+ (char *)current->sa_info->ss_sp += ( current->sa_info->ss_size - 1 );
+ }
+ else if( current->sa_info ) {
+ /* sa_in.ss_sp = 0 so we remove sig-stack from task struct */
+ kfree( current->sa_info );
+ current->sa_info = 0;
+ }
+
+ if( sa_out ) {
+ /* Set back to low memory so user can handle it like normal. */
+ if( sa_temp.ss_sp )
+ (char *)sa_temp.ss_sp -= ( sa_temp.ss_size - 1 );
+ memcpy_tofs( sa_out, &sa_temp, sizeof( struct sigaltstack ) );
+ }
+
+ return 0;
+}
+

/*
- * This sets regs->esp even though we don't actually use sigstacks yet..
+ * 5.25.96 Added sigaltstack restore
*/
asmlinkage int sys_sigreturn(unsigned long __unused)
{
@@ -92,6 +170,7 @@
goto badframe;
memcpy_fromfs(&context,(void *) regs->esp, sizeof(context));
current->blocked = context.oldmask & _BLOCKABLE;
+
COPY_SEG(ds);
COPY_SEG(es);
COPY_SEG(fs);
@@ -106,6 +185,18 @@
regs->eflags &= ~0x40DD5;
regs->eflags |= context.eflags & 0x40DD5;
regs->orig_eax = -1; /* disable syscall checks */
+
+#define CUR_ALT_STACK_BOT (unsigned long)current->sa_info->ss_sp
+#define CUR_ALT_STACK_TOP CUR_ALT_STACK_BOT - ((unsigned long)current->sa_info->ss_sp - 1 )
+
+ /* Before clearing altstack bit, test if esp still within altstack
+ * space. A nested signal handler on alt stack maybe */
+ if( current->sa_info && ( current->sa_info->ss_flags & SS_ONSTACK ) ) {
+ if( regs->esp <= CUR_ALT_STACK_BOT
+ || regs->esp >= CUR_ALT_STACK_TOP )
+ current->sa_info->ss_flags &= ~SS_ONSTACK;
+ }
+
if (context.fpstate) {
struct _fpstate * buf = context.fpstate;
if (verify_area(VERIFY_READ, buf, sizeof(*buf)))
@@ -156,6 +247,9 @@
/*
* Set up a signal frame... Make the stack look the way iBCS2 expects
* it to look.
+ * 5.17.96 Added sigstack support. DEC UNIX manpage says if longjmp() is
+ * called from a -nested- signal on an alternate stack then the effect is
+ * undefined. I try to handle it here.
*/
static void setup_frame(struct sigaction * sa,
struct pt_regs * regs, int signr,
@@ -164,10 +258,19 @@
unsigned long * frame;

frame = (unsigned long *) regs->esp;
- if (regs->ss != USER_DS && sa->sa_restorer)
- frame = (unsigned long *) sa->sa_restorer;
+
+ /* See if sigaction requests alternate stack...
+ * Now see if we are already on that stack, or the stack is disabled.
+ */
+ if (regs->ss == USER_DS && sa->sa_flags & SA_ONSTACK
+ && current->sa_info
+ && !( current->sa_info->ss_flags & (SS_DISABLE | SS_ONSTACK) ) ) {
+ frame = (unsigned long *) current->sa_info->ss_sp;
+ current->sa_info->ss_flags = SS_ONSTACK;
+ }
+
frame -= 64;
- if (verify_area(VERIFY_WRITE,frame,64*4))
+ if (verify_area(VERIFY_WRITE,frame,64*sizeof(*frame)))
do_exit(SIGSEGV);

/* set up the "normal" stack seen by the signal handler (iBCS2) */
diff -urN /usr/src/linux-pre2.0.7/include/asm-i386/signal.h /usr/src/linux/include/asm-i386/signal.h
--- /usr/src/linux-pre2.0.7/include/asm-i386/signal.h Fri Mar 1 00:50:56 1996
+++ /usr/src/linux/include/asm-i386/signal.h Sat May 25 22:46:56 1996
@@ -44,17 +44,17 @@
#define SIGUNUSED 31

/*
- * sa_flags values: SA_STACK is not currently supported, but will allow the
- * usage of signal stacks by using the (now obsolete) sa_restorer field in
- * the sigaction structure as a stack pointer. This is now possible due to
- * the changes in signal handling. LBT 010493.
+ * SA_STACK changed to SA_ONSTACK and implementation started.
+ * The stack pointer is not on the sigact struct however, I don't think it
+ * belongs there but I may be wrong. I added sigaltstack struct and added
+ * a sigaltstack member to task_struct - 5.17.96 Melvin Smith
* SA_INTERRUPT is a no-op, but left due to historical reasons. Use the
* SA_RESTART flag to get restarting signals (which were the default long ago)
* SA_SHIRQ flag is for shared interrupt support on PCI and EISA.
*/
#define SA_NOCLDSTOP 1
#define SA_SHIRQ 0x04000000
-#define SA_STACK 0x08000000
+#define SA_ONSTACK 0x08000000
#define SA_RESTART 0x10000000
#define SA_INTERRUPT 0x20000000
#define SA_NOMASK 0x40000000
@@ -89,6 +89,21 @@
unsigned long sa_flags;
void (*sa_restorer)(void);
};
+
+#define MINSIGSTKSZ 4096 /* minimum signal handler alternate stack size */
+#define SIGSTKSZ 16384 /* average or default alternate stack size */
+
+#define SS_DISABLE 1 /* alternate stack disabled */
+#define SS_ONSTACK 2 /* process is currently executing on the alternate stack */
+
+/* Used by sigaltstack() call (not fully implemented) */
+struct sigaltstack {
+ char * ss_sp;
+ unsigned long ss_flags;
+ long ss_size;
+};
+
+typedef struct sigaltstack stack_t;

#ifdef __KERNEL__
#include <asm/sigcontext.h>
diff -urN /usr/src/linux-pre2.0.7/include/asm-i386/unistd.h /usr/src/linux/include/asm-i386/unistd.h
--- /usr/src/linux-pre2.0.7/include/asm-i386/unistd.h Fri Mar 22 01:34:02 1996
+++ /usr/src/linux/include/asm-i386/unistd.h Sat May 25 22:47:10 1996
@@ -169,6 +169,7 @@
#define __NR_sched_rr_get_interval 161
#define __NR_nanosleep 162
#define __NR_mremap 163
+#define __NR_sigaltstack 164

/* XXX - _foo needs to be __foo, while __NR_bar could be _NR_bar. */
#define _syscall0(type,name) \
diff -urN /usr/src/linux-pre2.0.7/include/linux/sched.h /usr/src/linux/include/linux/sched.h
--- /usr/src/linux-pre2.0.7/include/linux/sched.h Tue May 21 07:38:02 1996
+++ /usr/src/linux/include/linux/sched.h Sat May 25 22:47:20 1996
@@ -244,6 +244,8 @@
struct mm_struct *mm;
/* signal handlers */
struct signal_struct *sig;
+/* signal stack */
+ struct sigaltstack *sa_info;
#ifdef __SMP__
int processor;
int last_processor;
@@ -309,6 +311,7 @@
/* files */ &init_files, \
/* mm */ &init_mm, \
/* signals */ &init_signals, \
+/* sig stack */ 0, \
}

extern struct mm_struct init_mm;
diff -urN /usr/src/linux-pre2.0.7/kernel/fork.c /usr/src/linux/kernel/fork.c
--- /usr/src/linux-pre2.0.7/kernel/fork.c Mon Apr 22 06:08:47 1996
+++ /usr/src/linux/kernel/fork.c Sun May 26 00:23:43 1996
@@ -190,6 +190,15 @@
return -1;
tsk->sig->count = 1;
memcpy(tsk->sig->action, current->sig->action, sizeof(tsk->sig->action));
+ /* copy sigstack */
+ if( current->sa_info ) {
+ tsk->sa_info = kmalloc(sizeof(struct sigaltstack), GFP_KERNEL);
+ if (!tsk->sa_info) {
+ exit_sighand(tsk);
+ return -1;
+ }
+ memcpy(tsk->sa_info, current->sa_info, sizeof(struct sigaltstack));
+ }
return 0;
}

diff -urN /usr/src/linux-pre2.0.7/sigaltstack.patch /usr/src/linux/sigaltstack.patch
--- /usr/src/linux-pre2.0.7/sigaltstack.patch Wed Dec 31 19:00:00 1969
+++ /usr/src/linux/sigaltstack.patch Sun May 26 00:26:10 1996
@@ -0,0 +1,292 @@
+diff -urN /usr/src/linux-pre2.0.7/arch/i386/kernel/entry.S /usr/src/linux/arch/i386/kernel/entry.S
+--- /usr/src/linux-pre2.0.7/arch/i386/kernel/entry.S Mon May 13 16:23:08 1996
++++ /usr/src/linux/arch/i386/kernel/entry.S Sat May 25 22:46:07 1996
+@@ -674,4 +674,5 @@
+ .long SYMBOL_NAME(sys_sched_rr_get_interval)
+ .long SYMBOL_NAME(sys_nanosleep)
+ .long SYMBOL_NAME(sys_mremap)
+- .space (NR_syscalls-163)*4
++ .long SYMBOL_NAME(sys_sigaltstack)
++ .space (NR_syscalls-164)*4
+diff -urN /usr/src/linux-pre2.0.7/arch/i386/kernel/process.c /usr/src/linux/arch/i386/kernel/process.c
+--- /usr/src/linux-pre2.0.7/arch/i386/kernel/process.c Fri Apr 19 11:35:15 1996
++++ /usr/src/linux/arch/i386/kernel/process.c Sun May 26 00:11:16 1996
+@@ -267,6 +267,12 @@
+ for (i=0 ; i<8 ; i++)
+ current->debugreg[i] = 0;
+
++ /* zero sigaltstack */
++ if( current->sa_info ) {
++ kfree( current->sa_info );
++ current->sa_info = 0;
++ }
++
+ /*
+ * Forget coprocessor state..
+ */
+diff -urN /usr/src/linux-pre2.0.7/arch/i386/kernel/signal.c /usr/src/linux/arch/i386/kernel/signal.c
+--- /usr/src/linux-pre2.0.7/arch/i386/kernel/signal.c Mon May 6 09:31:18 1996
++++ /usr/src/linux/arch/i386/kernel/signal.c Sat May 25 22:46:45 1996
+@@ -2,6 +2,10 @@
+ * linux/arch/i386/kernel/signal.c
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
++ *
++ * 05.25.96 Melvin Smith
++ * Started reliable signal handling. Signal stacks implemented.
++ * Hopefully SA_SIGINFO is next.
+ */
+
+ #include <linux/config.h>
+@@ -11,6 +15,7 @@
+ #include <linux/kernel.h>
+ #include <linux/signal.h>
+ #include <linux/errno.h>
++#include <linux/malloc.h>
+ #include <linux/wait.h>
+ #include <linux/ptrace.h>
+ #include <linux/unistd.h>
+@@ -72,10 +77,83 @@
+ restore_i387_soft(buf);
+ #endif
+ }
+-
++
++/* Right now I'm checking not only instack but instack->ss_sp, maybe wrong
++ * but I think it is safe. System shouldn't let user install stack if it
++ * is too small anyway
++ */
++asmlinkage int sys_sigaltstack( const struct sigaltstack * sa_in,
++ struct sigaltstack *sa_out )
++{
++ /* In case sa_in == sa_out */
++ struct sigaltstack sa_temp, sa_new;
++
++ /* If old sigstack pointer then save old info in that pointer */
++ if( sa_out ) {
++ if( verify_area( VERIFY_WRITE, sa_out, sizeof( struct sigaltstack ) ) )
++ return -EINVAL;
++
++ if( !current->sa_info )
++ memset( &sa_temp, 0, sizeof( struct sigaltstack ) );
++ else
++ memcpy( &sa_temp, current->sa_info, sizeof( struct sigaltstack ) );
++ }
++
++ /* If new sigstack is passed then update current */
++ sa_new.ss_sp = 0;
++ if( sa_in ) {
++ if( verify_area( VERIFY_READ, sa_in, sizeof( struct sigaltstack ) ) )
++ return -EINVAL;
++ memcpy_fromfs( &sa_new, sa_in, sizeof( *sa_in ) );
++ }
++
++ if( sa_new.ss_sp ) {
++ /* If SS_DISABLE, ignore stack info */
++ if( !( sa_new.ss_flags & SS_DISABLE ) ) {
++ /* Can't change stack while executing on that stack */
++ if( current->sa_info && (current->sa_info->ss_flags & SA_ONSTACK) )
++ return -EINVAL;
++
++ /* Make sure the stack is as big as the user says it is, either
++ * way it must be at least MINSIGSTKSZ bytes */
++ if( sa_new.ss_size < MINSIGSTKSZ )
++ return -EINVAL;
++ else if( verify_area( VERIFY_WRITE, sa_new.ss_sp, sa_new.ss_size ) )
++ return -EINVAL;
++ }
++
++ if( !current->sa_info ) {
++ current->sa_info = (struct sigaltstack *)kmalloc( sizeof( struct sigaltstack ),
++ GFP_KERNEL );
++ if( !current->sa_info )
++ return -ENOMEM;
++ }
++
++ memcpy( current->sa_info, &sa_new, sizeof( struct sigaltstack ) );
++ /* i386 stack starts at high mem.
++ * This is transparent to caller, reset if sigaltstack queried.
++ */
++ (char *)current->sa_info->ss_sp += ( current->sa_info->ss_size - 1 );
++ }
++ else if( current->sa_info ) {
++ /* sa_in.ss_sp = 0 so we remove sig-stack from task struct */
++ kfree( current->sa_info );
++ current->sa_info = 0;
++ }
++
++ if( sa_out ) {
++ /* Set back to low memory so user can handle it like normal. */
++ if( sa_temp.ss_sp )
++ (char *)sa_temp.ss_sp -= ( sa_temp.ss_size - 1 );
++ memcpy_tofs( sa_out, &sa_temp, sizeof( struct sigaltstack ) );
++ }
++
++ return 0;
++}
++
+
+ /*
+- * This sets regs->esp even though we don't actually use sigstacks yet..
++ * 5.25.96 Added sigaltstack restore
+ */
+ asmlinkage int sys_sigreturn(unsigned long __unused)
+ {
+@@ -92,6 +170,7 @@
+ goto badframe;
+ memcpy_fromfs(&context,(void *) regs->esp, sizeof(context));
+ current->blocked = context.oldmask & _BLOCKABLE;
++
+ COPY_SEG(ds);
+ COPY_SEG(es);
+ COPY_SEG(fs);
+@@ -106,6 +185,18 @@
+ regs->eflags &= ~0x40DD5;
+ regs->eflags |= context.eflags & 0x40DD5;
+ regs->orig_eax = -1; /* disable syscall checks */
++
++#define CUR_ALT_STACK_BOT (unsigned long)current->sa_info->ss_sp
++#define CUR_ALT_STACK_TOP CUR_ALT_STACK_BOT - ((unsigned long)current->sa_info->ss_sp - 1 )
++
++ /* Before clearing altstack bit, test if esp still within altstack
++ * space. A nested signal handler on alt stack maybe */
++ if( current->sa_info && ( current->sa_info->ss_flags & SS_ONSTACK ) ) {
++ if( regs->esp <= CUR_ALT_STACK_BOT
++ || regs->esp >= CUR_ALT_STACK_TOP )
++ current->sa_info->ss_flags &= ~SS_ONSTACK;
++ }
++
+ if (context.fpstate) {
+ struct _fpstate * buf = context.fpstate;
+ if (verify_area(VERIFY_READ, buf, sizeof(*buf)))
+@@ -156,6 +247,9 @@
+ /*
+ * Set up a signal frame... Make the stack look the way iBCS2 expects
+ * it to look.
++ * 5.17.96 Added sigstack support. DEC UNIX manpage says if longjmp() is
++ * called from a -nested- signal on an alternate stack then the effect is
++ * undefined. I try to handle it here.
+ */
+ static void setup_frame(struct sigaction * sa,
+ struct pt_regs * regs, int signr,
+@@ -164,10 +258,19 @@
+ unsigned long * frame;
+
+ frame = (unsigned long *) regs->esp;
+- if (regs->ss != USER_DS && sa->sa_restorer)
+- frame = (unsigned long *) sa->sa_restorer;
++
++ /* See if sigaction requests alternate stack...
++ * Now see if we are already on that stack, or the stack is disabled.
++ */
++ if (regs->ss == USER_DS && sa->sa_flags & SA_ONSTACK
++ && current->sa_info
++ && !( current->sa_info->ss_flags & (SS_DISABLE | SS_ONSTACK) ) ) {
++ frame = (unsigned long *) current->sa_info->ss_sp;
++ current->sa_info->ss_flags = SS_ONSTACK;
++ }
++
+ frame -= 64;
+- if (verify_area(VERIFY_WRITE,frame,64*4))
++ if (verify_area(VERIFY_WRITE,frame,64*sizeof(*frame)))
+ do_exit(SIGSEGV);
+
+ /* set up the "normal" stack seen by the signal handler (iBCS2) */
+diff -urN /usr/src/linux-pre2.0.7/include/asm-i386/signal.h /usr/src/linux/include/asm-i386/signal.h
+--- /usr/src/linux-pre2.0.7/include/asm-i386/signal.h Fri Mar 1 00:50:56 1996
++++ /usr/src/linux/include/asm-i386/signal.h Sat May 25 22:46:56 1996
+@@ -44,17 +44,17 @@
+ #define SIGUNUSED 31
+
+ /*
+- * sa_flags values: SA_STACK is not currently supported, but will allow the
+- * usage of signal stacks by using the (now obsolete) sa_restorer field in
+- * the sigaction structure as a stack pointer. This is now possible due to
+- * the changes in signal handling. LBT 010493.
++ * SA_STACK changed to SA_ONSTACK and implementation started.
++ * The stack pointer is not on the sigact struct however, I don't think it
++ * belongs there but I may be wrong. I added sigaltstack struct and added
++ * a sigaltstack member to task_struct - 5.17.96 Melvin Smith
+ * SA_INTERRUPT is a no-op, but left due to historical reasons. Use the
+ * SA_RESTART flag to get restarting signals (which were the default long ago)
+ * SA_SHIRQ flag is for shared interrupt support on PCI and EISA.
+ */
+ #define SA_NOCLDSTOP 1
+ #define SA_SHIRQ 0x04000000
+-#define SA_STACK 0x08000000
++#define SA_ONSTACK 0x08000000
+ #define SA_RESTART 0x10000000
+ #define SA_INTERRUPT 0x20000000
+ #define SA_NOMASK 0x40000000
+@@ -89,6 +89,21 @@
+ unsigned long sa_flags;
+ void (*sa_restorer)(void);
+ };
++
++#define MINSIGSTKSZ 4096 /* minimum signal handler alternate stack size */
++#define SIGSTKSZ 16384 /* average or default alternate stack size */
++
++#define SS_DISABLE 1 /* alternate stack disabled */
++#define SS_ONSTACK 2 /* process is currently executing on the alternate stack */
++
++/* Used by sigaltstack() call (not fully implemented) */
++struct sigaltstack {
++ char * ss_sp;
++ unsigned long ss_flags;
++ long ss_size;
++};
++
++typedef struct sigaltstack stack_t;
+
+ #ifdef __KERNEL__
+ #include <asm/sigcontext.h>
+diff -urN /usr/src/linux-pre2.0.7/include/asm-i386/unistd.h /usr/src/linux/include/asm-i386/unistd.h
+--- /usr/src/linux-pre2.0.7/include/asm-i386/unistd.h Fri Mar 22 01:34:02 1996
++++ /usr/src/linux/include/asm-i386/unistd.h Sat May 25 22:47:10 1996
+@@ -169,6 +169,7 @@
+ #define __NR_sched_rr_get_interval 161
+ #define __NR_nanosleep 162
+ #define __NR_mremap 163
++#define __NR_sigaltstack 164
+
+ /* XXX - _foo needs to be __foo, while __NR_bar could be _NR_bar. */
+ #define _syscall0(type,name) \
+diff -urN /usr/src/linux-pre2.0.7/include/linux/sched.h /usr/src/linux/include/linux/sched.h
+--- /usr/src/linux-pre2.0.7/include/linux/sched.h Tue May 21 07:38:02 1996
++++ /usr/src/linux/include/linux/sched.h Sat May 25 22:47:20 1996
+@@ -244,6 +244,8 @@
+ struct mm_struct *mm;
+ /* signal handlers */
+ struct signal_struct *sig;
++/* signal stack */
++ struct sigaltstack *sa_info;
+ #ifdef __SMP__
+ int processor;
+ int last_processor;
+@@ -309,6 +311,7 @@
+ /* files */ &init_files, \
+ /* mm */ &init_mm, \
+ /* signals */ &init_signals, \
++/* sig stack */ 0, \
+ }
+
+ extern struct mm_struct init_mm;
+diff -urN /usr/src/linux-pre2.0.7/kernel/fork.c /usr/src/linux/kernel/fork.c
+--- /usr/src/linux-pre2.0.7/kernel/fork.c Mon Apr 22 06:08:47 1996
++++ /usr/src/linux/kernel/fork.c Sun May 26 00:23:43 1996
+@@ -190,6 +190,15 @@
+ return -1;
+ tsk->sig->count = 1;
+ memcpy(tsk->sig->action, current->sig->action, sizeof(tsk->sig->action));
++ /* copy sigstack */
++ if( current->sa_info ) {
++ tsk->sa_info = kmalloc(sizeof(struct sigaltstack), GFP_KERNEL);
++ if (!tsk->sa_info) {
++ exit_sighand(tsk);
++ return -1;
++ }
++ memcpy(tsk->sa_info, current->sa_info, sizeof(struct sigaltstack));
++ }
+ return 0;
+ }
+
diff -urN /usr/src/linux-pre2.0.7/sigaltstack.patch.3 /usr/src/linux/sigaltstack.patch.3
--- /usr/src/linux-pre2.0.7/sigaltstack.patch.3 Wed Dec 31 19:00:00 1969
+++ /usr/src/linux/sigaltstack.patch.3 Sun May 26 00:15:01 1996
@@ -0,0 +1,584 @@
+diff -urN /usr/src/linux-pre2.0.7/arch/i386/kernel/entry.S /usr/src/linux/arch/i386/kernel/entry.S
+--- /usr/src/linux-pre2.0.7/arch/i386/kernel/entry.S Mon May 13 16:23:08 1996
++++ /usr/src/linux/arch/i386/kernel/entry.S Sat May 25 22:46:07 1996
+@@ -674,4 +674,5 @@
+ .long SYMBOL_NAME(sys_sched_rr_get_interval)
+ .long SYMBOL_NAME(sys_nanosleep)
+ .long SYMBOL_NAME(sys_mremap)
+- .space (NR_syscalls-163)*4
++ .long SYMBOL_NAME(sys_sigaltstack)
++ .space (NR_syscalls-164)*4
+diff -urN /usr/src/linux-pre2.0.7/arch/i386/kernel/process.c /usr/src/linux/arch/i386/kernel/process.c
+--- /usr/src/linux-pre2.0.7/arch/i386/kernel/process.c Fri Apr 19 11:35:15 1996
++++ /usr/src/linux/arch/i386/kernel/process.c Sun May 26 00:11:16 1996
+@@ -267,6 +267,12 @@
+ for (i=0 ; i<8 ; i++)
+ current->debugreg[i] = 0;
+
++ /* zero sigaltstack */
++ if( current->sa_info ) {
++ kfree( current->sa_info );
++ current->sa_info = 0;
++ }
++
+ /*
+ * Forget coprocessor state..
+ */
+diff -urN /usr/src/linux-pre2.0.7/arch/i386/kernel/signal.c /usr/src/linux/arch/i386/kernel/signal.c
+--- /usr/src/linux-pre2.0.7/arch/i386/kernel/signal.c Mon May 6 09:31:18 1996
++++ /usr/src/linux/arch/i386/kernel/signal.c Sat May 25 22:46:45 1996
+@@ -2,6 +2,10 @@
+ * linux/arch/i386/kernel/signal.c
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
++ *
++ * 05.25.96 Melvin Smith
++ * Started reliable signal handling. Signal stacks implemented.
++ * Hopefully SA_SIGINFO is next.
+ */
+
+ #include <linux/config.h>
+@@ -11,6 +15,7 @@
+ #include <linux/kernel.h>
+ #include <linux/signal.h>
+ #include <linux/errno.h>
++#include <linux/malloc.h>
+ #include <linux/wait.h>
+ #include <linux/ptrace.h>
+ #include <linux/unistd.h>
+@@ -72,10 +77,83 @@
+ restore_i387_soft(buf);
+ #endif
+ }
+-
++
++/* Right now I'm checking not only instack but instack->ss_sp, maybe wrong
++ * but I think it is safe. System shouldn't let user install stack if it
++ * is too small anyway
++ */
++asmlinkage int sys_sigaltstack( const struct sigaltstack * sa_in,
++ struct sigaltstack *sa_out )
++{
++ /* In case sa_in == sa_out */
++ struct sigaltstack sa_temp, sa_new;
++
++ /* If old sigstack pointer then save old info in that pointer */
++ if( sa_out ) {
++ if( verify_area( VERIFY_WRITE, sa_out, sizeof( struct sigaltstack ) ) )
++ return -EINVAL;
++
++ if( !current->sa_info )
++ memset( &sa_temp, 0, sizeof( struct sigaltstack ) );
++ else
++ memcpy( &sa_temp, current->sa_info, sizeof( struct sigaltstack ) );
++ }
++
++ /* If new sigstack is passed then update current */
++ sa_new.ss_sp = 0;
++ if( sa_in ) {
++ if( verify_area( VERIFY_READ, sa_in, sizeof( struct sigaltstack ) ) )
++ return -EINVAL;
++ memcpy_fromfs( &sa_new, sa_in, sizeof( *sa_in ) );
++ }
++
++ if( sa_new.ss_sp ) {
++ /* If SS_DISABLE, ignore stack info */
++ if( !( sa_new.ss_flags & SS_DISABLE ) ) {
++ /* Can't change stack while executing on that stack */
++ if( current->sa_info && (current->sa_info->ss_flags & SA_ONSTACK) )
++ return -EINVAL;
++
++ /* Make sure the stack is as big as the user says it is, either
++ * way it must be at least MINSIGSTKSZ bytes */
++ if( sa_new.ss_size < MINSIGSTKSZ )
++ return -EINVAL;
++ else if( verify_area( VERIFY_WRITE, sa_new.ss_sp, sa_new.ss_size ) )
++ return -EINVAL;
++ }
++
++ if( !current->sa_info ) {
++ current->sa_info = (struct sigaltstack *)kmalloc( sizeof( struct sigaltstack ),
++ GFP_KERNEL );
++ if( !current->sa_info )
++ return -ENOMEM;
++ }
++
++ memcpy( current->sa_info, &sa_new, sizeof( struct sigaltstack ) );
++ /* i386 stack starts at high mem.
++ * This is transparent to caller, reset if sigaltstack queried.
++ */
++ (char *)current->sa_info->ss_sp += ( current->sa_info->ss_size - 1 );
++ }
++ else if( current->sa_info ) {
++ /* sa_in.ss_sp = 0 so we remove sig-stack from task struct */
++ kfree( current->sa_info );
++ current->sa_info = 0;
++ }
++
++ if( sa_out ) {
++ /* Set back to low memory so user can handle it like normal. */
++ if( sa_temp.ss_sp )
++ (char *)sa_temp.ss_sp -= ( sa_temp.ss_size - 1 );
++ memcpy_tofs( sa_out, &sa_temp, sizeof( struct sigaltstack ) );
++ }
++
++ return 0;
++}
++
+
+ /*
+- * This sets regs->esp even though we don't actually use sigstacks yet..
++ * 5.25.96 Added sigaltstack restore
+ */
+ asmlinkage int sys_sigreturn(unsigned long __unused)
+ {
+@@ -92,6 +170,7 @@
+ goto badframe;
+ memcpy_fromfs(&context,(void *) regs->esp, sizeof(context));
+ current->blocked = context.oldmask & _BLOCKABLE;
++
+ COPY_SEG(ds);
+ COPY_SEG(es);
+ COPY_SEG(fs);
+@@ -106,6 +185,18 @@
+ regs->eflags &= ~0x40DD5;
+ regs->eflags |= context.eflags & 0x40DD5;
+ regs->orig_eax = -1; /* disable syscall checks */
++
++#define CUR_ALT_STACK_BOT (unsigned long)current->sa_info->ss_sp
++#define CUR_ALT_STACK_TOP CUR_ALT_STACK_BOT - ((unsigned long)current->sa_info->ss_sp - 1 )
++
++ /* Before clearing altstack bit, test if esp still within altstack
++ * space. A nested signal handler on alt stack maybe */
++ if( current->sa_info && ( current->sa_info->ss_flags & SS_ONSTACK ) ) {
++ if( regs->esp <= CUR_ALT_STACK_BOT
++ || regs->esp >= CUR_ALT_STACK_TOP )
++ current->sa_info->ss_flags &= ~SS_ONSTACK;
++ }
++
+ if (context.fpstate) {
+ struct _fpstate * buf = context.fpstate;
+ if (verify_area(VERIFY_READ, buf, sizeof(*buf)))
+@@ -156,6 +247,9 @@
+ /*
+ * Set up a signal frame... Make the stack look the way iBCS2 expects
+ * it to look.
++ * 5.17.96 Added sigstack support. DEC UNIX manpage says if longjmp() is
++ * called from a -nested- signal on an alternate stack then the effect is
++ * undefined. I try to handle it here.
+ */
+ static void setup_frame(struct sigaction * sa,
+ struct pt_regs * regs, int signr,
+@@ -164,10 +258,19 @@
+ unsigned long * frame;
+
+ frame = (unsigned long *) regs->esp;
+- if (regs->ss != USER_DS && sa->sa_restorer)
+- frame = (unsigned long *) sa->sa_restorer;
++
++ /* See if sigaction requests alternate stack...
++ * Now see if we are already on that stack, or the stack is disabled.
++ */
++ if (regs->ss == USER_DS && sa->sa_flags & SA_ONSTACK
++ && current->sa_info
++ && !( current->sa_info->ss_flags & (SS_DISABLE | SS_ONSTACK) ) ) {
++ frame = (unsigned long *) current->sa_info->ss_sp;
++ current->sa_info->ss_flags = SS_ONSTACK;
++ }
++
+ frame -= 64;
+- if (verify_area(VERIFY_WRITE,frame,64*4))
++ if (verify_area(VERIFY_WRITE,frame,64*sizeof(*frame)))
+ do_exit(SIGSEGV);
+
+ /* set up the "normal" stack seen by the signal handler (iBCS2) */
+diff -urN /usr/src/linux-pre2.0.7/include/asm-i386/signal.h /usr/src/linux/include/asm-i386/signal.h
+--- /usr/src/linux-pre2.0.7/include/asm-i386/signal.h Fri Mar 1 00:50:56 1996
++++ /usr/src/linux/include/asm-i386/signal.h Sat May 25 22:46:56 1996
+@@ -44,17 +44,17 @@
+ #define SIGUNUSED 31
+
+ /*
+- * sa_flags values: SA_STACK is not currently supported, but will allow the
+- * usage of signal stacks by using the (now obsolete) sa_restorer field in
+- * the sigaction structure as a stack pointer. This is now possible due to
+- * the changes in signal handling. LBT 010493.
++ * SA_STACK changed to SA_ONSTACK and implementation started.
++ * The stack pointer is not on the sigact struct however, I don't think it
++ * belongs there but I may be wrong. I added sigaltstack struct and added
++ * a sigaltstack member to task_struct - 5.17.96 Melvin Smith
+ * SA_INTERRUPT is a no-op, but left due to historical reasons. Use the
+ * SA_RESTART flag to get restarting signals (which were the default long ago)
+ * SA_SHIRQ flag is for shared interrupt support on PCI and EISA.
+ */
+ #define SA_NOCLDSTOP 1
+ #define SA_SHIRQ 0x04000000
+-#define SA_STACK 0x08000000
++#define SA_ONSTACK 0x08000000
+ #define SA_RESTART 0x10000000
+ #define SA_INTERRUPT 0x20000000
+ #define SA_NOMASK 0x40000000
+@@ -89,6 +89,21 @@
+ unsigned long sa_flags;
+ void (*sa_restorer)(void);
+ };
++
++#define MINSIGSTKSZ 4096 /* minimum signal handler alternate stack size */
++#define SIGSTKSZ 16384 /* average or default alternate stack size */
++
++#define SS_DISABLE 1 /* alternate stack disabled */
++#define SS_ONSTACK 2 /* process is currently executing on the alternate stack */
++
++/* Used by sigaltstack() call (not fully implemented) */
++struct sigaltstack {
++ char * ss_sp;
++ unsigned long ss_flags;
++ long ss_size;
++};
++
++typedef struct sigaltstack stack_t;
+
+ #ifdef __KERNEL__
+ #include <asm/sigcontext.h>
+diff -urN /usr/src/linux-pre2.0.7/include/asm-i386/unistd.h /usr/src/linux/include/asm-i386/unistd.h
+--- /usr/src/linux-pre2.0.7/include/asm-i386/unistd.h Fri Mar 22 01:34:02 1996
++++ /usr/src/linux/include/asm-i386/unistd.h Sat May 25 22:47:10 1996
+@@ -169,6 +169,7 @@
+ #define __NR_sched_rr_get_interval 161
+ #define __NR_nanosleep 162
+ #define __NR_mremap 163
++#define __NR_sigaltstack 164
+
+ /* XXX - _foo needs to be __foo, while __NR_bar could be _NR_bar. */
+ #define _syscall0(type,name) \
+diff -urN /usr/src/linux-pre2.0.7/include/linux/sched.h /usr/src/linux/include/linux/sched.h
+--- /usr/src/linux-pre2.0.7/include/linux/sched.h Tue May 21 07:38:02 1996
++++ /usr/src/linux/include/linux/sched.h Sat May 25 22:47:20 1996
+@@ -244,6 +244,8 @@
+ struct mm_struct *mm;
+ /* signal handlers */
+ struct signal_struct *sig;
++/* signal stack */
++ struct sigaltstack *sa_info;
+ #ifdef __SMP__
+ int processor;
+ int last_processor;
+@@ -309,6 +311,7 @@
+ /* files */ &init_files, \
+ /* mm */ &init_mm, \
+ /* signals */ &init_signals, \
++/* sig stack */ 0, \
+ }
+
+ extern struct mm_struct init_mm;
+diff -urN /usr/src/linux-pre2.0.7/kernel/fork.c /usr/src/linux/kernel/fork.c
+--- /usr/src/linux-pre2.0.7/kernel/fork.c Mon Apr 22 06:08:47 1996
++++ /usr/src/linux/kernel/fork.c Sat May 25 23:52:49 1996
+@@ -190,6 +190,13 @@
+ return -1;
+ tsk->sig->count = 1;
+ memcpy(tsk->sig->action, current->sig->action, sizeof(tsk->sig->action));
++ /* copy sigstack */
++ if( current->sa_info ) {
++ tsk->sa_info = kmalloc(sizeof(struct sigaltstack), GFP_KERNEL);
++ if (!tsk->sa_info)
++ return -1;
++ memcpy(tsk->sa_info, current->sa_info, sizeof(struct sigaltstack));
++ }
+ return 0;
+ }
+
+diff -urN /usr/src/linux-pre2.0.7/sigaltstack.patch.3 /usr/src/linux/sigaltstack.patch.3
+--- /usr/src/linux-pre2.0.7/sigaltstack.patch.3 Wed Dec 31 19:00:00 1969
++++ /usr/src/linux/sigaltstack.patch.3 Sun May 26 00:14:50 1996
+@@ -0,0 +1,290 @@
++diff -urN /usr/src/linux-pre2.0.7/arch/i386/kernel/entry.S /usr/src/linux/arch/i386/kernel/entry.S
++--- /usr/src/linux-pre2.0.7/arch/i386/kernel/entry.S Mon May 13 16:23:08 1996
+++++ /usr/src/linux/arch/i386/kernel/entry.S Sat May 25 22:46:07 1996
++@@ -674,4 +674,5 @@
++ .long SYMBOL_NAME(sys_sched_rr_get_interval)
++ .long SYMBOL_NAME(sys_nanosleep)
++ .long SYMBOL_NAME(sys_mremap)
++- .space (NR_syscalls-163)*4
+++ .long SYMBOL_NAME(sys_sigaltstack)
+++ .space (NR_syscalls-164)*4
++diff -urN /usr/src/linux-pre2.0.7/arch/i386/kernel/process.c /usr/src/linux/arch/i386/kernel/process.c
++--- /usr/src/linux-pre2.0.7/arch/i386/kernel/process.c Fri Apr 19 11:35:15 1996
+++++ /usr/src/linux/arch/i386/kernel/process.c Sun May 26 00:11:16 1996
++@@ -267,6 +267,12 @@
++ for (i=0 ; i<8 ; i++)
++ current->debugreg[i] = 0;
++
+++ /* zero sigaltstack */
+++ if( current->sa_info ) {
+++ kfree( current->sa_info );
+++ current->sa_info = 0;
+++ }
+++
++ /*
++ * Forget coprocessor state..
++ */
++diff -urN /usr/src/linux-pre2.0.7/arch/i386/kernel/signal.c /usr/src/linux/arch/i386/kernel/signal.c
++--- /usr/src/linux-pre2.0.7/arch/i386/kernel/signal.c Mon May 6 09:31:18 1996
+++++ /usr/src/linux/arch/i386/kernel/signal.c Sat May 25 22:46:45 1996
++@@ -2,6 +2,10 @@
++ * linux/arch/i386/kernel/signal.c
++ *
++ * Copyright (C) 1991, 1992 Linus Torvalds
+++ *
+++ * 05.25.96 Melvin Smith
+++ * Started reliable signal handling. Signal stacks implemented.
+++ * Hopefully SA_SIGINFO is next.
++ */
++
++ #include <linux/config.h>
++@@ -11,6 +15,7 @@
++ #include <linux/kernel.h>
++ #include <linux/signal.h>
++ #include <linux/errno.h>
+++#include <linux/malloc.h>
++ #include <linux/wait.h>
++ #include <linux/ptrace.h>
++ #include <linux/unistd.h>
++@@ -72,10 +77,83 @@
++ restore_i387_soft(buf);
++ #endif
++ }
++-
+++
+++/* Right now I'm checking not only instack but instack->ss_sp, maybe wrong
+++ * but I think it is safe. System shouldn't let user install stack if it
+++ * is too small anyway
+++ */
+++asmlinkage int sys_sigaltstack( const struct sigaltstack * sa_in,
+++ struct sigaltstack *sa_out )
+++{
+++ /* In case sa_in == sa_out */
+++ struct sigaltstack sa_temp, sa_new;
+++
+++ /* If old sigstack pointer then save old info in that pointer */
+++ if( sa_out ) {
+++ if( verify_area( VERIFY_WRITE, sa_out, sizeof( struct sigaltstack ) ) )
+++ return -EINVAL;
+++
+++ if( !current->sa_info )
+++ memset( &sa_temp, 0, sizeof( struct sigaltstack ) );
+++ else
+++ memcpy( &sa_temp, current->sa_info, sizeof( struct sigaltstack ) );
+++ }
+++
+++ /* If new sigstack is passed then update current */
+++ sa_new.ss_sp = 0;
+++ if( sa_in ) {
+++ if( verify_area( VERIFY_READ, sa_in, sizeof( struct sigaltstack ) ) )
+++ return -EINVAL;
+++ memcpy_fromfs( &sa_new, sa_in, sizeof( *sa_in ) );
+++ }
+++
+++ if( sa_new.ss_sp ) {
+++ /* If SS_DISABLE, ignore stack info */
+++ if( !( sa_new.ss_flags & SS_DISABLE ) ) {
+++ /* Can't change stack while executing on that stack */
+++ if( current->sa_info && (current->sa_info->ss_flags & SA_ONSTACK) )
+++ return -EINVAL;
+++
+++ /* Make sure the stack is as big as the user says it is, either
+++ * way it must be at least MINSIGSTKSZ bytes */
+++ if( sa_new.ss_size < MINSIGSTKSZ )
+++ return -EINVAL;
+++ else if( verify_area( VERIFY_WRITE, sa_new.ss_sp, sa_new.ss_size ) )
+++ return -EINVAL;
+++ }
+++
+++ if( !current->sa_info ) {
+++ current->sa_info = (struct sigaltstack *)kmalloc( sizeof( struct sigaltstack ),
+++ GFP_KERNEL );
+++ if( !current->sa_info )
+++ return -ENOMEM;
+++ }
+++
+++ memcpy( current->sa_info, &sa_new, sizeof( struct sigaltstack ) );
+++ /* i386 stack starts at high mem.
+++ * This is transparent to caller, reset if sigaltstack queried.
+++ */
+++ (char *)current->sa_info->ss_sp += ( current->sa_info->ss_size - 1 );
+++ }
+++ else if( current->sa_info ) {
+++ /* sa_in.ss_sp = 0 so we remove sig-stack from task struct */
+++ kfree( current->sa_info );
+++ current->sa_info = 0;
+++ }
+++
+++ if( sa_out ) {
+++ /* Set back to low memory so user can handle it like normal. */
+++ if( sa_temp.ss_sp )
+++ (char *)sa_temp.ss_sp -= ( sa_temp.ss_size - 1 );
+++ memcpy_tofs( sa_out, &sa_temp, sizeof( struct sigaltstack ) );
+++ }
+++
+++ return 0;
+++}
+++
++
++ /*
++- * This sets regs->esp even though we don't actually use sigstacks yet..
+++ * 5.25.96 Added sigaltstack restore
++ */
++ asmlinkage int sys_sigreturn(unsigned long __unused)
++ {
++@@ -92,6 +170,7 @@
++ goto badframe;
++ memcpy_fromfs(&context,(void *) regs->esp, sizeof(context));
++ current->blocked = context.oldmask & _BLOCKABLE;
+++
++ COPY_SEG(ds);
++ COPY_SEG(es);
++ COPY_SEG(fs);
++@@ -106,6 +185,18 @@
++ regs->eflags &= ~0x40DD5;
++ regs->eflags |= context.eflags & 0x40DD5;
++ regs->orig_eax = -1; /* disable syscall checks */
+++
+++#define CUR_ALT_STACK_BOT (unsigned long)current->sa_info->ss_sp
+++#define CUR_ALT_STACK_TOP CUR_ALT_STACK_BOT - ((unsigned long)current->sa_info->ss_sp - 1 )
+++
+++ /* Before clearing altstack bit, test if esp still within altstack
+++ * space. A nested signal handler on alt stack maybe */
+++ if( current->sa_info && ( current->sa_info->ss_flags & SS_ONSTACK ) ) {
+++ if( regs->esp <= CUR_ALT_STACK_BOT
+++ || regs->esp >= CUR_ALT_STACK_TOP )
+++ current->sa_info->ss_flags &= ~SS_ONSTACK;
+++ }
+++
++ if (context.fpstate) {
++ struct _fpstate * buf = context.fpstate;
++ if (verify_area(VERIFY_READ, buf, sizeof(*buf)))
++@@ -156,6 +247,9 @@
++ /*
++ * Set up a signal frame... Make the stack look the way iBCS2 expects
++ * it to look.
+++ * 5.17.96 Added sigstack support. DEC UNIX manpage says if longjmp() is
+++ * called from a -nested- signal on an alternate stack then the effect is
+++ * undefined. I try to handle it here.
++ */
++ static void setup_frame(struct sigaction * sa,
++ struct pt_regs * regs, int signr,
++@@ -164,10 +258,19 @@
++ unsigned long * frame;
++
++ frame = (unsigned long *) regs->esp;
++- if (regs->ss != USER_DS && sa->sa_restorer)
++- frame = (unsigned long *) sa->sa_restorer;
+++
+++ /* See if sigaction requests alternate stack...
+++ * Now see if we are already on that stack, or the stack is disabled.
+++ */
+++ if (regs->ss == USER_DS && sa->sa_flags & SA_ONSTACK
+++ && current->sa_info
+++ && !( current->sa_info->ss_flags & (SS_DISABLE | SS_ONSTACK) ) ) {
+++ frame = (unsigned long *) current->sa_info->ss_sp;
+++ current->sa_info->ss_flags = SS_ONSTACK;
+++ }
+++
++ frame -= 64;
++- if (verify_area(VERIFY_WRITE,frame,64*4))
+++ if (verify_area(VERIFY_WRITE,frame,64*sizeof(*frame)))
++ do_exit(SIGSEGV);
++
++ /* set up the "normal" stack seen by the signal handler (iBCS2) */
++diff -urN /usr/src/linux-pre2.0.7/include/asm-i386/signal.h /usr/src/linux/include/asm-i386/signal.h
++--- /usr/src/linux-pre2.0.7/include/asm-i386/signal.h Fri Mar 1 00:50:56 1996
+++++ /usr/src/linux/include/asm-i386/signal.h Sat May 25 22:46:56 1996
++@@ -44,17 +44,17 @@
++ #define SIGUNUSED 31
++
++ /*
++- * sa_flags values: SA_STACK is not currently supported, but will allow the
++- * usage of signal stacks by using the (now obsolete) sa_restorer field in
++- * the sigaction structure as a stack pointer. This is now possible due to
++- * the changes in signal handling. LBT 010493.
+++ * SA_STACK changed to SA_ONSTACK and implementation started.
+++ * The stack pointer is not on the sigact struct however, I don't think it
+++ * belongs there but I may be wrong. I added sigaltstack struct and added
+++ * a sigaltstack member to task_struct - 5.17.96 Melvin Smith
++ * SA_INTERRUPT is a no-op, but left due to historical reasons. Use the
++ * SA_RESTART flag to get restarting signals (which were the default long ago)
++ * SA_SHIRQ flag is for shared interrupt support on PCI and EISA.
++ */
++ #define SA_NOCLDSTOP 1
++ #define SA_SHIRQ 0x04000000
++-#define SA_STACK 0x08000000
+++#define SA_ONSTACK 0x08000000
++ #define SA_RESTART 0x10000000
++ #define SA_INTERRUPT 0x20000000
++ #define SA_NOMASK 0x40000000
++@@ -89,6 +89,21 @@
++ unsigned long sa_flags;
++ void (*sa_restorer)(void);
++ };
+++
+++#define MINSIGSTKSZ 4096 /* minimum signal handler alternate stack size */
+++#define SIGSTKSZ 16384 /* average or default alternate stack size */
+++
+++#define SS_DISABLE 1 /* alternate stack disabled */
+++#define SS_ONSTACK 2 /* process is currently executing on the alternate stack */
+++
+++/* Used by sigaltstack() call (not fully implemented) */
+++struct sigaltstack {
+++ char * ss_sp;
+++ unsigned long ss_flags;
+++ long ss_size;
+++};
+++
+++typedef struct sigaltstack stack_t;
++
++ #ifdef __KERNEL__
++ #include <asm/sigcontext.h>
++diff -urN /usr/src/linux-pre2.0.7/include/asm-i386/unistd.h /usr/src/linux/include/asm-i386/unistd.h
++--- /usr/src/linux-pre2.0.7/include/asm-i386/unistd.h Fri Mar 22 01:34:02 1996
+++++ /usr/src/linux/include/asm-i386/unistd.h Sat May 25 22:47:10 1996
++@@ -169,6 +169,7 @@
++ #define __NR_sched_rr_get_interval 161
++ #define __NR_nanosleep 162
++ #define __NR_mremap 163
+++#define __NR_sigaltstack 164
++
++ /* XXX - _foo needs to be __foo, while __NR_bar could be _NR_bar. */
++ #define _syscall0(type,name) \
++diff -urN /usr/src/linux-pre2.0.7/include/linux/sched.h /usr/src/linux/include/linux/sched.h
++--- /usr/src/linux-pre2.0.7/include/linux/sched.h Tue May 21 07:38:02 1996
+++++ /usr/src/linux/include/linux/sched.h Sat May 25 22:47:20 1996
++@@ -244,6 +244,8 @@
++ struct mm_struct *mm;
++ /* signal handlers */
++ struct signal_struct *sig;
+++/* signal stack */
+++ struct sigaltstack *sa_info;
++ #ifdef __SMP__
++ int processor;
++ int last_processor;
++@@ -309,6 +311,7 @@
++ /* files */ &init_files, \
++ /* mm */ &init_mm, \
++ /* signals */ &init_signals, \
+++/* sig stack */ 0, \
++ }
++
++ extern struct mm_struct init_mm;
++diff -urN /usr/src/linux-pre2.0.7/kernel/fork.c /usr/src/linux/kernel/fork.c
++--- /usr/src/linux-pre2.0.7/kernel/fork.c Mon Apr 22 06:08:47 1996
+++++ /usr/src/linux/kernel/fork.c Sat May 25 23:52:49 1996
++@@ -190,6 +190,13 @@
++ return -1;
++ tsk->sig->count = 1;
++ memcpy(tsk->sig->action, current->sig->action, sizeof(tsk->sig->action));
+++ /* copy sigstack */
+++ if( current->sa_info ) {
+++ tsk->sa_info = kmalloc(sizeof(struct sigaltstack), GFP_KERNEL);
+++ if (!tsk->sa_info)
+++ return -1;
+++ memcpy(tsk->sa_info, current->sa_info, sizeof(struct sigaltstack));
+++ }
++ return 0;
++ }
++