-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;
++ }
++