diff -Nru linux/Documentation/Configure.help linux-2.0.32-stack-symlink/Documentation/Configure.help
--- linux/Documentation/Configure.help	Sat Sep  6 05:43:58 1997
+++ linux-2.0.32-stack-symlink/Documentation/Configure.help	Tue Nov 18 11:58:50 1997
@@ -720,6 +720,35 @@
   later load the module when you install the JDK or find an interesting
   Java program that you can't live without.
 
+Non-executable user stack area (EXPERIMENTAL)
+CONFIG_STACKEXEC
+  Most buffer overflow exploits are based on overwriting a function's
+  return address on the stack to point to some arbitrary code, which is
+  also put onto the stack. If the stack area is non-executable, buffer
+  overflow vulnerabilities become harder to exploit. However, a few
+  programs depend on the stack being executable, and might stop working
+  unless you also enable GCC trampolines autodetection below, or enable
+  the stack area execution permission for every such program separately
+  using chstk.c. If you don't know what all this is about, or don't care
+  about security that much, say N.
+
+Autodetect GCC trampolines
+CONFIG_STACKEXEC_AUTOENABLE
+  GCC generates trampolines on the stack to correctly pass control to
+  nested functions when calling from outside. This requires the stack
+  being executable. When this option is enabled, programs containing
+  trampolines will automatically get their stack area executable when
+  a trampoline is found. However, in some cases this autodetection can
+  be fooled in a buffer overflow exploit, so it is more secure to
+  disable this option and use chstk.c to enable the stack area execution
+  permission for every such program separately. If you're too lazy,
+  answer Y.
+
+Log buffer overflow exploit attempts
+CONFIG_STACKEXEC_LOG
+  This option enables logging of buffer overflow exploit attempts. No
+  more than one attempt per minute is logged, so this is safe. Say Y.
+
 Processor type
 CONFIG_M386
   This is the processor type of your CPU. It is used for optimizing
@@ -2951,6 +2980,27 @@
   netatalk, new mars-nwe and other file servers. At the time of
   writing none of these are available. So it's safest to say N here
   unless you really know that you need this feature.
+
+Symlink security fix (EXPERIMENTAL)
+CONFIG_SYMLINK_FIX
+  A very common class of security hole on UNIX-like systems involves
+  a malicious user creating a symbolic link in /tmp pointing at
+  another user's file. When the victim then writes to that file they
+  inadvertently write to the wrong file. Enabling this option fixes
+  this class of hole by preventing a process from following a link
+  which is in a +t directory unless they own the link. However, this
+  fix does not affect links owned by root, since these could only be
+  created by someone having root access already. To prevent someone
+  from using a hard link instead, this fix does not allow non-root
+  users to create hard links in a +t directory to files they don't
+  own. Note that this fix might break things. Only say Y if security
+  is more important.
+
+Log symlink exploit attempts
+CONFIG_SYMLINK_LOG
+  This option enables logging of symlink (and hard link) exploit
+  attempts. No more than one attempt per minute is logged, so this is
+  safe. Say Y.
 
 Minix fs support
 CONFIG_MINIX_FS
diff -Nru linux/arch/alpha/defconfig linux-2.0.32-stack-symlink/arch/alpha/defconfig
--- linux/arch/alpha/defconfig	Sat Sep  6 05:43:58 1997
+++ linux-2.0.32-stack-symlink/arch/alpha/defconfig	Tue Nov 18 12:00:31 1997
@@ -180,6 +180,8 @@
 # Filesystems
 #
 # CONFIG_QUOTA is not set
+# CONFIG_SYMLINK_FIX is not set
+CONFIG_SYMLINK_LOG=y
 # CONFIG_MINIX_FS is not set
 # CONFIG_EXT_FS is not set
 CONFIG_EXT2_FS=y
diff -Nru linux/arch/i386/config.in linux-2.0.32-stack-symlink/arch/i386/config.in
--- linux/arch/i386/config.in	Mon May 13 06:17:23 1996
+++ linux-2.0.32-stack-symlink/arch/i386/config.in	Tue Nov 18 11:58:50 1997
@@ -35,6 +35,11 @@
 tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
   tristate 'Kernel support for JAVA binaries' CONFIG_BINFMT_JAVA
+  bool 'Non-executable user stack area (EXPERIMENTAL)' CONFIG_STACKEXEC
+  if [ "$CONFIG_STACKEXEC" = "y" ]; then
+    bool '   Autodetect GCC trampolines' CONFIG_STACKEXEC_AUTOENABLE
+    bool '   Log buffer overflow exploit attempts' CONFIG_STACKEXEC_LOG
+  fi
 fi
 bool 'Compile kernel as ELF - if your GCC is ELF-GCC' CONFIG_KERNEL_ELF
 
diff -Nru linux/arch/i386/defconfig linux-2.0.32-stack-symlink/arch/i386/defconfig
--- linux/arch/i386/defconfig	Mon Sep 22 22:44:01 1997
+++ linux-2.0.32-stack-symlink/arch/i386/defconfig	Tue Nov 18 12:01:10 1997
@@ -24,6 +24,9 @@
 CONFIG_SYSVIPC=y
 CONFIG_BINFMT_AOUT=y
 CONFIG_BINFMT_ELF=y
+# CONFIG_STACKEXEC is not set
+CONFIG_STACKEXEC_AUTOENABLE=y
+CONFIG_STACKEXEC_LOG=y
 CONFIG_KERNEL_ELF=y
 # CONFIG_M386 is not set
 # CONFIG_M486 is not set
@@ -134,6 +137,8 @@
 # Filesystems
 #
 # CONFIG_QUOTA is not set
+# CONFIG_SYMLINK_FIX is not set
+CONFIG_SYMLINK_LOG=y
 CONFIG_MINIX_FS=y
 # CONFIG_EXT_FS is not set
 CONFIG_EXT2_FS=y
diff -Nru linux/arch/i386/kernel/head.S linux-2.0.32-stack-symlink/arch/i386/kernel/head.S
--- linux/arch/i386/kernel/head.S	Fri Nov 14 01:28:44 1997
+++ linux-2.0.32-stack-symlink/arch/i386/kernel/head.S	Tue Nov 18 11:58:51 1997
@@ -400,10 +400,17 @@
 	.quad 0x0000000000000000	/* not used */
 	.quad 0xc0c39a000000ffff	/* 0x10 kernel 1GB code at 0xC0000000 */
 	.quad 0xc0c392000000ffff	/* 0x18 kernel 1GB data at 0xC0000000 */
+#ifdef CONFIG_STACKEXEC
+	.quad 0x00cafa000000ffff	/* 0x23 user   2.75GB code at 0 */
+	.quad 0x00cbf2000000ffff	/* 0x2b user   3GB data at 0 */
+	.quad 0x00cbda000000ffff	/* 0x32 user   3GB code at 0, DPL=2 */
+	.quad 0x00cbd2000000ffff	/* 0x3a user   3GB stack at 0, DPL=2 */
+#else
 	.quad 0x00cbfa000000ffff	/* 0x23 user   3GB code at 0x00000000 */
 	.quad 0x00cbf2000000ffff	/* 0x2b user   3GB data at 0x00000000 */
 	.quad 0x0000000000000000	/* not used */
 	.quad 0x0000000000000000	/* not used */
+#endif
 	.fill 2*NR_TASKS,8,0		/* space for LDT's and TSS's etc */
 #ifdef CONFIG_APM
 	.quad 0x00c09a0000000000	/* APM CS    code */
diff -Nru linux/arch/i386/kernel/ptrace.c linux-2.0.32-stack-symlink/arch/i386/kernel/ptrace.c
--- linux/arch/i386/kernel/ptrace.c	Fri Nov  7 18:11:42 1997
+++ linux-2.0.32-stack-symlink/arch/i386/kernel/ptrace.c	Tue Nov 18 11:58:51 1997
@@ -555,7 +555,7 @@
 			    addr == FS || addr == GS ||
 			    addr == CS || addr == SS) {
 			    	data &= 0xffff;
-			    	if (data && (data & 3) != 3)
+			    	if (data && (data & 3) < 2)
 					return -EIO;
 			}
 			if (addr == EFL) {   /* flags. */
@@ -565,6 +565,10 @@
 		  /* Do not allow the user to set the debug register for kernel
 		     address space */
 		  if(addr < 17){
+			if (addr == EIP && (data & 0xF0000000) == 0xB0000000)
+			if (put_stack_long(child, CS*sizeof(long)-MAGICNUMBER, USER_HUGE_CS) ||
+			    put_stack_long(child, SS*sizeof(long)-MAGICNUMBER, USER_HUGE_SS))
+				return -EIO;
 			  if (put_stack_long(child, sizeof(long)*addr-MAGICNUMBER, data))
 				return -EIO;
 			return 0;
diff -Nru linux/arch/i386/kernel/signal.c linux-2.0.32-stack-symlink/arch/i386/kernel/signal.c
--- linux/arch/i386/kernel/signal.c	Mon Aug  4 21:12:51 1997
+++ linux-2.0.32-stack-symlink/arch/i386/kernel/signal.c	Tue Nov 18 11:58:51 1997
@@ -83,10 +83,10 @@
 #define COPY_SEG(x) \
 if (   (context.x & 0xfffc)     /* not a NULL selectors */ \
     && (context.x & 0x4) != 0x4 /* not a LDT selector */ \
-    && (context.x & 3) != 3     /* not a RPL3 GDT selector */ \
+    && (context.x & 3) < 2      /* not a RPL3 or RPL2 GDT selector */ \
    ) goto badframe; COPY(x);
 #define COPY_SEG_STRICT(x) \
-if (!(context.x & 0xfffc) || (context.x & 3) != 3) goto badframe; COPY(x);
+if (!(context.x & 0xfffc) || (context.x & 3) < 2) goto badframe; COPY(x);
 	struct sigcontext_struct context;
 	struct pt_regs * regs;
 
@@ -167,16 +167,20 @@
 	unsigned long * frame;
 
 	frame = (unsigned long *) regs->esp;
-	if (regs->ss != USER_DS && sa->sa_restorer)
+	if (regs->ss != USER_DS && regs->ss != USER_HUGE_SS && sa->sa_restorer)
 		frame = (unsigned long *) sa->sa_restorer;
 	frame -= 64;
 	if (verify_area(VERIFY_WRITE,frame,64*4))
 		do_exit(SIGSEGV);
 
 /* set up the "normal" stack seen by the signal handler (iBCS2) */
+#ifdef CONFIG_STACKEXEC
+	put_user((unsigned long)MAGIC_SIGRETURN, frame);
+#else
 #define __CODE ((unsigned long)(frame+24))
 #define CODE(x) ((unsigned long *) ((x)+__CODE))
 	put_user(__CODE,frame);
+#endif
 	if (current->exec_domain && current->exec_domain->signal_invmap)
 		put_user(current->exec_domain->signal_invmap[signr], frame+1);
 	else
@@ -204,19 +208,17 @@
 /* non-iBCS2 extensions.. */
 	put_user(oldmask, frame+22);
 	put_user(current->tss.cr2, frame+23);
+#ifndef CONFIG_STACKEXEC
 /* set up the return code... */
 	put_user(0x0000b858, CODE(0));	/* popl %eax ; movl $,%eax */
 	put_user(0x80cd0000, CODE(4));	/* int $0x80 */
 	put_user(__NR_sigreturn, CODE(2));
 #undef __CODE
 #undef CODE
+#endif
 
 	/* Set up registers for signal handler */
-	regs->esp = (unsigned long) frame;
-	regs->eip = (unsigned long) sa->sa_handler;
-	regs->cs = USER_CS; regs->ss = USER_DS;
-	regs->ds = USER_DS; regs->es = USER_DS;
-	regs->gs = USER_DS; regs->fs = USER_DS;
+	start_thread(regs, (unsigned long)sa->sa_handler, (unsigned long)frame);
 	regs->eflags &= ~TF_MASK;
 }
 
diff -Nru linux/arch/i386/kernel/traps.c linux-2.0.32-stack-symlink/arch/i386/kernel/traps.c
--- linux/arch/i386/kernel/traps.c	Fri Nov 14 17:12:25 1997
+++ linux-2.0.32-stack-symlink/arch/i386/kernel/traps.c	Tue Nov 18 11:58:51 1997
@@ -118,7 +118,7 @@
 
 	esp = (unsigned long) &regs->esp;
 	ss = KERNEL_DS;
-	if ((regs->eflags & VM_MASK) || (3 & regs->cs) == 3)
+	if ((regs->eflags & VM_MASK) || (3 & regs->cs) >= 2)
 		return;
 	if (regs->cs & 3) {
 		esp = regs->esp;
@@ -194,11 +194,82 @@
 
 asmlinkage void do_general_protection(struct pt_regs * regs, long error_code)
 {
+#ifdef CONFIG_STACKEXEC
+	unsigned long retaddr;
+#endif
+
 	if (regs->eflags & VM_MASK) {
 		handle_vm86_fault((struct vm86_regs *) regs, error_code);
 		return;
 	}
+
+#ifdef CONFIG_STACKEXEC
+/* Check if it was return from a signal handler */
+	if (regs->cs == USER_CS || regs->cs == USER_HUGE_CS)
+	if (get_seg_byte(USER_DS, (char *)regs->eip) == 0xC3)
+	if (!verify_area(VERIFY_READ, (void *)regs->esp, 4))
+	if ((retaddr = get_seg_long(USER_DS, (char *)regs->esp)) ==
+	    MAGIC_SIGRETURN) {
+/*
+ * Call sys_sigreturn() to restore the context. It would definitely be better
+ * to convert sys_sigreturn() into an inline function accepting a pointer to
+ * pt_regs, making this faster...
+ */
+		regs->esp += 8;
+		__asm__("movl %3,%%esi;"
+			"subl %1,%%esp;"
+			"movl %2,%%ecx;"
+			"movl %%esp,%%edi;"
+			"cld; rep; movsl;"
+			"call sys_sigreturn;"
+			"leal %3,%%edi;"
+			"addl %1,%%edi;"
+			"movl %%esp,%%esi;"
+			"movl (%%edi),%%edi;"
+			"movl %2,%%ecx;"
+			"cld; rep; movsl;"
+			"movl %%esi,%%esp"
+		:
+/* %eax is returned separately */
+		"=a" (regs->eax)
+		:
+		"i" (sizeof(*regs)),
+		"i" (sizeof(*regs) >> 2),
+		"m" (regs)
+		:
+		"cx", "dx", "si", "di", "cc", "memory");
+		return;
+	}
+
+#ifdef CONFIG_STACKEXEC_LOG
+/*
+ * Check if we're returning to the stack area, which is only likely to happen
+ * when attempting to exploit a buffer overflow.
+ */
+	else if (regs->cs == USER_CS &&
+	    (retaddr & 0xF0000000) == 0xB0000000)
+		security_alert("buffer overflow");
+#endif
+#endif
+
 	die_if_kernel("general protection",regs,error_code);
+
+#if defined(CONFIG_STACKEXEC) && defined(CONFIG_STACKEXEC_AUTOENABLE)
+/*
+ * Switch to the original huge code segment (and allow code execution on the
+ * stack for this entire process), if the faulty instruction is a call %reg,
+ * except for call %esp.
+ */
+	if (regs->cs == USER_CS)
+	if (get_seg_byte(USER_DS, (char *)regs->eip) == 0xFF &&
+	    (get_seg_byte(USER_DS, (char *)(regs->eip + 1)) & 0xD8) == 0xD0 &&
+	    get_seg_byte(USER_DS, (char *)(regs->eip + 1)) != 0xD4) {
+		current->flags |= PF_STACKEXEC;
+		regs->cs = USER_HUGE_CS; regs->ss = USER_HUGE_SS;
+		return;
+	}
+#endif
+
 	current->tss.error_code = error_code;
 	current->tss.trap_no = 13;
 	force_sig(SIGSEGV, current);	
diff -Nru linux/arch/i386/mm/fault.c linux-2.0.32-stack-symlink/arch/i386/mm/fault.c
--- linux/arch/i386/mm/fault.c	Mon Nov 17 02:12:14 1997
+++ linux-2.0.32-stack-symlink/arch/i386/mm/fault.c	Tue Nov 18 11:58:51 1997
@@ -166,6 +166,7 @@
 	unsigned long page;
 	int write;
 
+	if ((regs->cs & 3) >= 2) error_code |= 4;
 	/* get the address */
 	__asm__("movl %%cr2,%0":"=r" (address));
 	down(&mm->mmap_sem);
diff -Nru linux/arch/m68k/defconfig linux-2.0.32-stack-symlink/arch/m68k/defconfig
--- linux/arch/m68k/defconfig	Sat Sep  6 05:43:58 1997
+++ linux-2.0.32-stack-symlink/arch/m68k/defconfig	Tue Nov 18 11:58:51 1997
@@ -107,6 +107,8 @@
 # Filesystems
 #
 # CONFIG_QUOTA is not set
+# CONFIG_SYMLINK_FIX is not set
+CONFIG_SYMLINK_LOG=y
 CONFIG_MINIX_FS=y
 # CONFIG_EXT_FS is not set
 CONFIG_EXT2_FS=y
diff -Nru linux/arch/mips/defconfig linux-2.0.32-stack-symlink/arch/mips/defconfig
--- linux/arch/mips/defconfig	Sat Sep  6 05:43:58 1997
+++ linux-2.0.32-stack-symlink/arch/mips/defconfig	Tue Nov 18 11:58:51 1997
@@ -52,6 +52,8 @@
 #
 # Filesystems
 #
+# CONFIG_SYMLINK_FIX is not set
+CONFIG_SYMLINK_LOG=y
 # CONFIG_MINIX_FS is not set
 # CONFIG_EXT_FS is not set
 CONFIG_EXT2_FS=y
diff -Nru linux/arch/sparc/defconfig linux-2.0.32-stack-symlink/arch/sparc/defconfig
--- linux/arch/sparc/defconfig	Sat Sep  6 05:43:58 1997
+++ linux-2.0.32-stack-symlink/arch/sparc/defconfig	Tue Nov 18 11:58:51 1997
@@ -96,6 +96,8 @@
 # Filesystems
 #
 # CONFIG_QUOTA is not set
+# CONFIG_SYMLINK_FIX is not set
+CONFIG_SYMLINK_LOG=y
 # CONFIG_MINIX_FS is not set
 # CONFIG_EXT_FS is not set
 CONFIG_EXT2_FS=y
diff -Nru linux/fs/Config.in linux-2.0.32-stack-symlink/fs/Config.in
--- linux/fs/Config.in	Sat Sep  6 05:43:59 1997
+++ linux-2.0.32-stack-symlink/fs/Config.in	Tue Nov 18 12:02:22 1997
@@ -5,6 +5,12 @@
 comment 'Filesystems'
 
 bool	 'Quota support' CONFIG_QUOTA
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+  bool 'Symlink security fix (EXPERIMENTAL)' CONFIG_SYMLINK_FIX
+  if [ "$CONFIG_SYMLINK_FIX" = "y" ]; then
+    bool '   Log symlink exploit attempts' CONFIG_SYMLINK_LOG
+  fi
+fi
 tristate 'Minix fs support' CONFIG_MINIX_FS
 tristate 'Extended fs support' CONFIG_EXT_FS
 tristate 'Second extended fs support' CONFIG_EXT2_FS
diff -Nru linux/fs/binfmt_aout.c linux-2.0.32-stack-symlink/fs/binfmt_aout.c
--- linux/fs/binfmt_aout.c	Wed Oct 15 23:56:43 1997
+++ linux-2.0.32-stack-symlink/fs/binfmt_aout.c	Tue Nov 18 11:58:51 1997
@@ -315,6 +315,7 @@
 	current->suid = current->euid = current->fsuid = bprm->e_uid;
 	current->sgid = current->egid = current->fsgid = bprm->e_gid;
  	current->flags &= ~PF_FORKNOEXEC;
+	if (N_FLAGS(ex) & F_STACKEXEC) current->flags |= PF_STACKEXEC;
 	if (N_MAGIC(ex) == OMAGIC) {
 #ifdef __alpha__
 		do_mmap(NULL, N_TXTADDR(ex) & PAGE_MASK,
diff -Nru linux/fs/binfmt_elf.c linux-2.0.32-stack-symlink/fs/binfmt_elf.c
--- linux/fs/binfmt_elf.c	Wed Oct 15 23:56:43 1997
+++ linux-2.0.32-stack-symlink/fs/binfmt_elf.c	Tue Nov 18 11:58:51 1997
@@ -55,7 +55,10 @@
 #define ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(ELF_EXEC_PAGESIZE-1))
 #define ELF_PAGEOFFSET(_v) ((_v) & (ELF_EXEC_PAGESIZE-1))
 
-static struct linux_binfmt elf_format = {
+#ifndef CONFIG_STACKEXEC
+static
+#endif
+struct linux_binfmt elf_format = {
 #ifndef MODULE
 	NULL, NULL, load_elf_binary, load_elf_library, elf_core_dump
 #else
@@ -662,6 +665,7 @@
 	current->suid = current->euid = current->fsuid = bprm->e_uid;
 	current->sgid = current->egid = current->fsgid = bprm->e_gid;
 	current->flags &= ~PF_FORKNOEXEC;
+	if (elf_ex.e_flags & EF_STACKEXEC) current->flags |= PF_STACKEXEC;
 	bprm->p = (unsigned long) 
 	  create_elf_tables((char *)bprm->p,
 			bprm->argc,
diff -Nru linux/fs/exec.c linux-2.0.32-stack-symlink/fs/exec.c
--- linux/fs/exec.c	Fri Nov  7 18:57:30 1997
+++ linux-2.0.32-stack-symlink/fs/exec.c	Tue Nov 18 11:59:01 1997
@@ -477,6 +477,8 @@
 	}
 	current->comm[i] = '\0';
 
+	current->flags &= ~PF_STACKEXEC;
+
 	/* Release all of the old mmap stuff. */
 	if (exec_mmap())
 		return -ENOMEM;
diff -Nru linux/fs/namei.c linux-2.0.32-stack-symlink/fs/namei.c
--- linux/fs/namei.c	Sun Aug 17 01:23:19 1997
+++ linux-2.0.32-stack-symlink/fs/namei.c	Tue Nov 18 11:59:01 1997
@@ -19,6 +19,7 @@
 #include <linux/fcntl.h>
 #include <linux/stat.h>
 #include <linux/mm.h>
+#include <linux/config.h>
 
 #define ACC_MODE(x) ("\000\004\002\006"[(x)&O_ACCMODE])
 
@@ -207,6 +208,23 @@
 		*res_inode = inode;
 		return 0;
 	}
+#ifdef CONFIG_SYMLINK_FIX
+/*
+ * Don't follow links that we don't own in +t directories, unless the link
+ * is owned by root.
+ */
+	if (S_ISLNK(inode->i_mode) && (dir->i_mode & S_ISVTX) &&
+	    inode->i_uid &&
+	    current->fsuid != inode->i_uid) {
+#ifdef CONFIG_SYMLINK_LOG
+		security_alert("symlink");
+#endif
+		iput(dir);
+		iput(inode);
+		*res_inode = NULL;
+		return -EPERM;
+	}
+#endif
 	return inode->i_op->follow_link(dir,inode,flag,mode,res_inode);
 }
 
@@ -787,6 +805,22 @@
 		iput(dir);
 		return -EPERM;
 	}
+#ifdef CONFIG_SYMLINK_FIX
+/*
+ * Don't allow non-root users to create hard links to files they don't own
+ * in a +t directory.
+ */
+	if ((dir->i_mode & S_ISVTX) &&
+	    current->fsuid != oldinode->i_uid &&
+	    !fsuser()) {
+#ifdef CONFIG_SYMLINK_LOG
+		security_alert("hard link");
+#endif
+		iput(oldinode);
+		iput(dir);
+		return -EPERM;
+	}
+#endif
 	if (IS_RDONLY(dir)) {
 		iput(oldinode);
 		iput(dir);
diff -Nru linux/include/asm-i386/processor.h linux-2.0.32-stack-symlink/include/asm-i386/processor.h
--- linux/include/asm-i386/processor.h	Thu Nov 13 05:45:40 1997
+++ linux-2.0.32-stack-symlink/include/asm-i386/processor.h	Tue Nov 18 11:59:01 1997
@@ -9,6 +9,8 @@
 
 #include <asm/vm86.h>
 #include <asm/math_emu.h>
+#include <linux/binfmts.h>
+#include <linux/config.h>
 
 /*
  * System setup and hardware bug flags..
@@ -41,6 +43,15 @@
  */
 #define TASK_SIZE	(0xC0000000UL)
 
+#if defined(CONFIG_STACKEXEC) && defined(CONFIG_BINFMT_ELF)
+extern struct linux_binfmt elf_format;
+#define MMAP_ADDR ( \
+	current->binfmt == &elf_format && \
+	!(current->flags & PF_STACKEXEC) \
+	? 0x00110000UL \
+	: TASK_SIZE / 3 )
+#endif
+
 /*
  * Size of io_bitmap in longwords: 32 is ports 0-0x3ff.
  */
@@ -134,14 +145,6 @@
 #define alloc_kernel_stack()    __get_free_page(GFP_KERNEL)
 #define free_kernel_stack(page) free_page((page))
 
-static inline void start_thread(struct pt_regs * regs, unsigned long eip, unsigned long esp)
-{
-	regs->cs = USER_CS;
-	regs->ds = regs->es = regs->ss = regs->fs = regs->gs = USER_DS;
-	regs->eip = eip;
-	regs->esp = esp;
-}
-
 /*
  * Return saved PC of a blocked thread.
  */
@@ -151,3 +154,25 @@
 }
 
 #endif /* __ASM_I386_PROCESSOR_H */
+
+#if defined(current) && !defined(__START_THREAD)
+#define __START_THREAD
+
+static inline void start_thread(struct pt_regs * regs, unsigned long eip, unsigned long esp)
+{
+#ifdef CONFIG_STACKEXEC
+	if (current->flags & PF_STACKEXEC) {
+		regs->cs = USER_HUGE_CS; regs->ss = USER_HUGE_SS;
+	} else {
+		regs->cs = USER_CS; regs->ss = USER_DS;
+	}
+	regs->ds = regs->es = regs->fs = regs->gs = USER_DS;
+#else
+	regs->cs = USER_CS;
+	regs->ds = regs->es = regs->fs = regs->gs = regs->ss = USER_DS;
+#endif
+	regs->eip = eip;
+	regs->esp = esp;
+}
+
+#endif /* __START_THREAD */
diff -Nru linux/include/asm-i386/segment.h linux-2.0.32-stack-symlink/include/asm-i386/segment.h
--- linux/include/asm-i386/segment.h	Tue Apr  9 09:35:29 1996
+++ linux-2.0.32-stack-symlink/include/asm-i386/segment.h	Tue Nov 18 11:59:01 1997
@@ -1,11 +1,27 @@
 #ifndef _ASM_SEGMENT_H
 #define _ASM_SEGMENT_H
 
+#include <linux/config.h>
+
 #define KERNEL_CS	0x10
 #define KERNEL_DS	0x18
 
 #define USER_CS		0x23
 #define USER_DS		0x2B
+
+#ifdef CONFIG_STACKEXEC
+#define USER_HUGE_CS	0x32
+#define USER_HUGE_SS	0x3A
+#else
+#define USER_HUGE_CS	0x23
+#define USER_HUGE_SS	0x2B
+#endif
+
+/*
+ * Magic address to return to the kernel from signal handlers, any address
+ * beyond user code segment limit will do.
+ */
+#define MAGIC_SIGRETURN	0xC1428571
 
 #ifndef __ASSEMBLY__
 
diff -Nru linux/include/linux/a.out.h linux-2.0.32-stack-symlink/include/linux/a.out.h
--- linux/include/linux/a.out.h	Sat Aug 17 20:19:28 1996
+++ linux-2.0.32-stack-symlink/include/linux/a.out.h	Tue Nov 18 11:59:01 1997
@@ -37,6 +37,9 @@
   M_MIPS2 = 152,	/* MIPS R6000/R4000 binary */
 };
 
+/* Constants for the N_FLAGS field */
+#define F_STACKEXEC	1	/* Executable stack area forced */
+
 #if !defined (N_MAGIC)
 #define N_MAGIC(exec) ((exec).a_info & 0xffff)
 #endif
diff -Nru linux/include/linux/elf.h linux-2.0.32-stack-symlink/include/linux/elf.h
--- linux/include/linux/elf.h	Sat Aug 10 09:03:15 1996
+++ linux-2.0.32-stack-symlink/include/linux/elf.h	Tue Nov 18 11:59:01 1997
@@ -57,6 +57,9 @@
  */
 #define EM_ALPHA	0x9026
 
+/* Constants for the e_flags field */
+#define EF_STACKEXEC	1	/* Executable stack area forced */
+
 
 /* This is the info that is needed to parse the dynamic section of the file */
 #define DT_NULL		0
diff -Nru linux/include/linux/kernel.h linux-2.0.32-stack-symlink/include/linux/kernel.h
--- linux/include/linux/kernel.h	Thu Aug 14 19:05:47 1997
+++ linux-2.0.32-stack-symlink/include/linux/kernel.h	Tue Nov 18 11:59:01 1997
@@ -78,6 +78,27 @@
         (((addr) >> 16) & 0xff), \
         (((addr) >> 24) & 0xff)
 
+#define security_alert(msg) { \
+	static unsigned long warning_time = 0, no_flood_yet = 0; \
+\
+/* Make sure at least one minute passed since the last warning logged */ \
+	if (!warning_time || jiffies - warning_time > 60 * HZ) { \
+		warning_time = jiffies; no_flood_yet = 1; \
+		printk( \
+			KERN_ALERT \
+			"Possible " msg " exploit attempt:\n" \
+			KERN_ALERT \
+			"Process %s (pid %d, uid %d, euid %d).\n", \
+			current->comm, current->pid, \
+			current->uid, current->euid); \
+	} else if (no_flood_yet) { \
+		warning_time = jiffies; no_flood_yet = 0; \
+		printk( \
+			KERN_ALERT \
+			"More possible " msg " exploit attempts follow.\n"); \
+	} \
+}
+
 #endif /* __KERNEL__ */
 
 #define SI_LOAD_SHIFT	16
diff -Nru linux/include/linux/sched.h linux-2.0.32-stack-symlink/include/linux/sched.h
--- linux/include/linux/sched.h	Fri Nov 14 01:12:29 1997
+++ linux-2.0.32-stack-symlink/include/linux/sched.h	Tue Nov 18 11:59:01 1997
@@ -269,6 +269,8 @@
 #define PF_USEDFPU	0x00100000	/* Process used the FPU this quantum (SMP only) */
 #define PF_DTRACE	0x00200000	/* delayed trace (used on m68k) */
 
+#define PF_STACKEXEC	0x01000000	/* Executable stack area forced */
+
 /*
  * Limit the stack by to some sane default: root can always
  * increase this limit if needed..  8MB seems reasonable.
@@ -490,6 +492,9 @@
 
 #define for_each_task(p) \
 	for (p = &init_task ; (p = p->next_task) != &init_task ; )
+
+/* x86 start_thread() */
+#include <asm/processor.h>
 
 #endif /* __KERNEL__ */
 
diff -Nru linux/mm/mmap.c linux-2.0.32-stack-symlink/mm/mmap.c
--- linux/mm/mmap.c	Fri Nov  7 18:57:31 1997
+++ linux-2.0.32-stack-symlink/mm/mmap.c	Tue Nov 18 11:59:01 1997
@@ -309,7 +309,11 @@
 	if (len > TASK_SIZE)
 		return 0;
 	if (!addr)
+#ifdef MMAP_ADDR
+		addr = MMAP_ADDR;
+#else
 		addr = TASK_SIZE / 3;
+#endif
 	addr = PAGE_ALIGN(addr);
 
 	for (vmm = find_vma(current->mm, addr); ; vmm = vmm->vm_next) {
