diff -urPX nopatch linux-2.2.18/Documentation/Configure.help linux/Documentation/Configure.help
--- linux-2.2.18/Documentation/Configure.help	Thu Dec 14 09:25:34 2000
+++ linux/Documentation/Configure.help	Thu Dec 14 10:47:44 2000
@@ -13506,6 +13506,109 @@
   another UltraSPARC-IIi-cEngine boardset with digital display,
   you should say N to this option.
    
+Non-executable user stack area
+CONFIG_SECURE_STACK
+  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 and emulation
+  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 and emulate GCC trampolines
+CONFIG_SECURE_STACK_SMART
+  GCC generates trampolines on the stack to correctly pass control to
+  nested functions when calling from outside. Normally, this requires
+  the stack being executable. When this option is enabled, the kernel
+  will trap faults resulting from trampoline calls, and will emulate the
+  trampolines. However, in some cases this autodetection can be fooled
+  in a buffer overflow exploit, so, if you've got no programs that use
+  GCC trampolines, it is more secure to disable this option. If you're
+  too lazy to find that out, answer Y. Note: if you're using glibc 2.0
+  (and not libc 5 or glibc 2.1+), you have to say Y here, or the system
+  won't even boot.
+
+Restricted links in /tmp
+CONFIG_SECURE_LINK
+  There's a very common attack that involves a malicious user creating
+  a symbolic link in /tmp, with a carefully chosen name, pointing at
+  another user's file. When the victim then writes to that file name,
+  without the required precautions, they inadvertently write to the
+  wrong file. Enabling this option reduces the impact of this class of
+  holes (some get fixed, many others allow for DoS attacks only, most
+  of the rest become harder to exploit) by preventing a process from
+  following a link which is in a +t directory, unless the link owner
+  is trusted (that is, it's the user we're running as or the directory
+  owner). To prevent from using a hard link in an attack instead, this
+  option does not allow users to create hard links to files they don't
+  own, unless they could read and write the file. This might break
+  things. Say Y if security is more important.
+
+Restricted FIFOs in /tmp
+CONFIG_SECURE_FIFO
+  In addition to restricting links, you might also want to restrict
+  writes into untrusted FIFOs (named pipes), to make data spoofing
+  attacks harder. Enabling this option disallows writing into FIFOs
+  not owned by the user in +t directories, unless the owner is the
+  same as that of the directory or the FIFO is opened without the
+  O_CREAT flag.
+
+Restricted /proc
+CONFIG_SECURE_PROC
+  This option restricts the permissions on directories in /proc so
+  that non-root users can see their own processes only, and nothing
+  about active network connections, unless they're in a special group.
+  This group's id is specified via the gid= mount option, and is 0 by
+  default. (Note: if you're using identd, you will need to edit the
+  inetd.conf line to run identd as this special group.) Also, this
+  disables dmesg(8) for the users. You might want to use this on an ISP
+  shell server where privacy is an issue.
+
+Special handling of fd 0, 1, and 2
+CONFIG_SECURE_FD_0_1_2
+  File descriptors 0, 1, and 2 have a special meaning for the C library
+  and lots of programs. Thus, they're often referenced by number. Still,
+  it is normally possible to execute a program with one or more of these
+  fd's closed, and any open(2) calls it might do will happily provide
+  these fd numbers. The program (or the libraries it is linked with)
+  will continue using the fd's for their usual purposes, in reality
+  accessing files the program has just opened. If such a program is
+  installed SUID and/or SGID, then we might have a security problem.
+  Enable this option to ensure that fd's 0, 1, and 2 are always open on
+  execution of a SUID/SGID binary.
+
+Enforce RLIMIT_NPROC on execve(2)
+CONFIG_SECURE_RLIMIT_NPROC
+  Linux lets you set a limit on how many processes a user can have, via
+  a setrlimit(2) call with RLIMIT_NPROC. Unfortunately, this limit is
+  only looked at when a new process is created on fork(2). If a process
+  changes its UID, it might exceed the limit for its new UID. This is
+  not a security issue by itself, as changing the UID is a privileged
+  operation. However, there're privileged programs that want to switch
+  to a user's context, including setting up some resource limits. The
+  only fork(2) required (if at all) is done before switching the UID,
+  and thus doesn't result in a check against RLIMIT_NPROC. Enable this
+  option to enforce RLIMIT_NPROC on execve(2) calls.
+
+Destroy shared memory segments not in use
+CONFIG_SECURE_SHM
+  Linux lets you set resource limits, including on how much memory one
+  process can consume, via setrlimit(2). Unfortunately, shared memory
+  segments are allowed to exist without association with any process,
+  and thus might not be counted against any resource limits. This option
+  automatically destroys shared memory segments when their attach count
+  becomes zero after a detach or a process termination. It will also
+  destroy segments that were created, but never attached to, on exit from
+  the process. (In case you're curious, the only use left for IPC_RMID is
+  to immediately destroy an unattached segment.) Of course, this breaks
+  the way things are defined, so some applications might stop working.
+  Note that this feature will do you no good unless you also configure
+  your resource limits (in particular, RLIMIT_AS and RLIMIT_NPROC). Most
+  systems don't need this.
+
 #
 # A couple of things I keep forgetting:
 #   capitalize: AppleTalk, Ethernet, DOS, DMA, FAT, FTP, Internet, 
diff -urPX nopatch linux-2.2.18/arch/alpha/config.in linux/arch/alpha/config.in
--- linux-2.2.18/arch/alpha/config.in	Thu Dec 14 09:25:34 2000
+++ linux/arch/alpha/config.in	Thu Dec 14 09:33:08 2000
@@ -292,6 +292,8 @@
 fi
 endmenu
 
+source security/Config.in
+
 mainmenu_option next_comment
 comment 'Kernel hacking'
 
diff -urPX nopatch linux-2.2.18/arch/alpha/defconfig linux/arch/alpha/defconfig
--- linux-2.2.18/arch/alpha/defconfig	Tue Jan  4 21:12:10 2000
+++ linux/arch/alpha/defconfig	Thu Dec 14 09:33:08 2000
@@ -328,6 +328,16 @@
 # CONFIG_SOUND is not set
 
 #
+# Security
+#
+CONFIG_SECURE_LINK=y
+CONFIG_SECURE_FIFO=y
+# CONFIG_SECURE_PROC is not set
+CONFIG_SECURE_FD_0_1_2=y
+CONFIG_SECURE_RLIMIT_NPROC=y
+# CONFIG_SECURE_SHM is not set
+
+#
 # Kernel hacking
 #
 CONFIG_MATHEMU=y
diff -urPX nopatch linux-2.2.18/arch/arm/config.in linux/arch/arm/config.in
--- linux-2.2.18/arch/arm/config.in	Thu Dec 14 09:25:34 2000
+++ linux/arch/arm/config.in	Thu Dec 14 09:33:08 2000
@@ -255,6 +255,8 @@
 
 source fs/Config.in
 
+source security/Config.in
+
 mainmenu_option next_comment
 comment 'Kernel hacking'
 
diff -urPX nopatch linux-2.2.18/arch/arm/defconfig linux/arch/arm/defconfig
--- linux-2.2.18/arch/arm/defconfig	Thu Dec 14 09:25:34 2000
+++ linux/arch/arm/defconfig	Thu Dec 14 09:33:08 2000
@@ -483,6 +483,16 @@
 # CONFIG_NLS_KOI8_R is not set
 
 #
+# Security
+#
+CONFIG_SECURE_LINK=y
+CONFIG_SECURE_FIFO=y
+# CONFIG_SECURE_PROC is not set
+CONFIG_SECURE_FD_0_1_2=y
+CONFIG_SECURE_RLIMIT_NPROC=y
+# CONFIG_SECURE_SHM is not set
+
+#
 # Kernel hacking
 #
 CONFIG_FRAME_POINTER=y
diff -urPX nopatch linux-2.2.18/arch/i386/config.in linux/arch/i386/config.in
--- linux-2.2.18/arch/i386/config.in	Thu Dec 14 09:25:34 2000
+++ linux/arch/i386/config.in	Thu Dec 14 09:33:08 2000
@@ -206,6 +206,18 @@
 endmenu
 
 mainmenu_option next_comment
+comment 'Security options'
+
+bool 'Non-executable user stack area' CONFIG_SECURE_STACK
+if [ "$CONFIG_SECURE_STACK" = "y" ]; then
+  bool '   Autodetect and emulate GCC trampolines' CONFIG_SECURE_STACK_SMART
+fi
+
+source security/Common.in
+
+endmenu
+
+mainmenu_option next_comment
 comment 'Kernel hacking'
 
 #bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC
diff -urPX nopatch linux-2.2.18/arch/i386/defconfig linux/arch/i386/defconfig
--- linux-2.2.18/arch/i386/defconfig	Thu Dec 14 09:25:34 2000
+++ linux/arch/i386/defconfig	Thu Dec 14 09:33:08 2000
@@ -389,6 +389,18 @@
 # CONFIG_SOUND is not set
 
 #
+# Security
+#
+CONFIG_SECURE_STACK=y
+CONFIG_SECURE_STACK_SMART=y
+CONFIG_SECURE_LINK=y
+CONFIG_SECURE_FIFO=y
+# CONFIG_SECURE_PROC is not set
+CONFIG_SECURE_FD_0_1_2=y
+CONFIG_SECURE_RLIMIT_NPROC=y
+# CONFIG_SECURE_SHM is not set
+
+#
 # Kernel hacking
 #
 # CONFIG_MAGIC_SYSRQ is not set
diff -urPX nopatch linux-2.2.18/arch/i386/kernel/head.S linux/arch/i386/kernel/head.S
--- linux-2.2.18/arch/i386/kernel/head.S	Fri Jan 15 09:57:25 1999
+++ linux/arch/i386/kernel/head.S	Thu Dec 14 09:33:08 2000
@@ -8,6 +8,7 @@
  */
 
 .text
+#include <linux/config.h>
 #include <linux/tasks.h>
 #include <linux/linkage.h>
 #include <asm/segment.h>
@@ -530,7 +531,19 @@
 	.quad 0x0000000000000000	/* not used */
 	.quad 0x00cf9a000000ffff	/* 0x10 kernel 4GB code at 0x00000000 */
 	.quad 0x00cf92000000ffff	/* 0x18 kernel 4GB data at 0x00000000 */
+#ifdef CONFIG_SECURE_STACK
+#ifdef CONFIG_1GB
+	.quad 0x00cbfa000000f7ff	/* 0x23 user   3GB-8MB code at 0 */
+#elif defined(CONFIG_2GB)
+	.quad 0x00c7fa000000f7ff	/* 0x23 user   2GB-8MB code at 0 */
+#elif defined(CONFIG_3GB)
+	.quad 0x00c3fa000000f7ff	/* 0x23 user   1GB-8MB code at 0 */
+#else
+#error Unknown max physical memory size requested
+#endif
+#else
 	.quad 0x00cffa000000ffff	/* 0x23 user   4GB code at 0x00000000 */
+#endif
 	.quad 0x00cff2000000ffff	/* 0x2b user   4GB data at 0x00000000 */
 	.quad 0x0000000000000000	/* not used */
 	.quad 0x0000000000000000	/* not used */
diff -urPX nopatch linux-2.2.18/arch/i386/kernel/signal.c linux/arch/i386/kernel/signal.c
--- linux-2.2.18/arch/i386/kernel/signal.c	Tue Jan  4 21:12:11 2000
+++ linux/arch/i386/kernel/signal.c	Thu Dec 14 09:33:08 2000
@@ -438,11 +438,15 @@
 	if (ka->sa.sa_flags & SA_RESTORER) {
 		err |= __put_user(ka->sa.sa_restorer, &frame->pretcode);
 	} else {
+#ifdef CONFIG_SECURE_STACK
+		err |= __put_user(MAGIC_SIGRETURN, &frame->pretcode);
+#else
 		err |= __put_user(frame->retcode, &frame->pretcode);
 		/* This is popl %eax ; movl $,%eax ; int $0x80 */
 		err |= __put_user(0xb858, (short *)(frame->retcode+0));
 		err |= __put_user(__NR_sigreturn, (int *)(frame->retcode+2));
 		err |= __put_user(0x80cd, (short *)(frame->retcode+6));
+#endif
 	}
 
 	if (err)
@@ -513,11 +517,15 @@
 	if (ka->sa.sa_flags & SA_RESTORER) {
 		err |= __put_user(ka->sa.sa_restorer, &frame->pretcode);
 	} else {
+#ifdef CONFIG_SECURE_STACK
+		err |= __put_user(MAGIC_RT_SIGRETURN, &frame->pretcode);
+#else
 		err |= __put_user(frame->retcode, &frame->pretcode);
 		/* This is movl $,%eax ; int $0x80 */
 		err |= __put_user(0xb8, (char *)(frame->retcode+0));
 		err |= __put_user(__NR_rt_sigreturn, (int *)(frame->retcode+1));
 		err |= __put_user(0x80cd, (short *)(frame->retcode+5));
+#endif
 	}
 
 	if (err)
diff -urPX nopatch linux-2.2.18/arch/i386/kernel/traps.c linux/arch/i386/kernel/traps.c
--- linux-2.2.18/arch/i386/kernel/traps.c	Thu Dec 14 09:25:34 2000
+++ linux/arch/i386/kernel/traps.c	Thu Dec 14 09:33:08 2000
@@ -263,13 +263,132 @@
 	force_sig(SIGSEGV, current);
 }
 
+#if defined(CONFIG_SECURE_STACK) && defined(CONFIG_SECURE_STACK_SMART)
+static unsigned long *get_reg(struct pt_regs *regs, unsigned char regnum)
+{
+	switch (regnum) {
+		case 0: return &regs->eax;
+		case 1: return &regs->ecx;
+		case 2: return &regs->edx;
+		case 3: return &regs->ebx;
+		case 4: return &regs->esp;
+		case 5: return &regs->ebp;
+		case 6: return &regs->esi;
+		case 7: return &regs->edi;
+	}
+
+	return NULL;
+}
+#endif
+
 asmlinkage void do_general_protection(struct pt_regs * regs, long error_code)
 {
+#ifdef CONFIG_SECURE_STACK
+	unsigned long addr;
+#ifdef CONFIG_SECURE_STACK_SMART
+	unsigned char insn;
+	int err, count;
+#endif
+#endif
+
 	if (regs->eflags & VM_MASK)
 		goto gp_in_vm86;
 
 	if (!(regs->xcs & 3))
 		goto gp_in_kernel;
+
+#ifdef CONFIG_SECURE_STACK
+/* Check if it was return from a signal handler */
+	if ((regs->xcs & 0xFFFF) == __USER_CS)
+	if (*(unsigned char *)regs->eip == 0xC3)
+	if (!__get_user(addr, (unsigned long *)regs->esp)) {
+		if ((addr & 0xFFFFFFFE) == MAGIC_SIGRETURN) {
+/* Call sys_sigreturn() or sys_rt_sigreturn() to restore the context */
+			regs->esp += 8;
+			__asm__("movl %3,%%esi\n\t"
+				"subl %1,%%esp\n\t"
+				"movl %2,%%ecx\n\t"
+				"movl %%esp,%%edi\n\t"
+				"rep; movsl\n\t"
+				"testl $1,%4\n\t"
+				"jnz 1f\n\t"
+				"call sys_sigreturn\n\t"
+				"leal %3,%%edi\n\t"
+				"jmp 2f\n\t"
+				"1:\n\t"
+				"call sys_rt_sigreturn\n\t"
+				"leal %3,%%edi\n\t"
+				"2:\n\t"
+				"addl %1,%%edi\n\t"
+				"movl %%esp,%%esi\n\t"
+				"movl %2,%%ecx\n\t"
+				"movl (%%edi),%%edi\n\t"
+				"rep; movsl\n\t"
+				"movl %%esi,%%esp"
+			:
+/* %eax is returned separately */
+			"=a" (regs->eax)
+			:
+			"i" (sizeof(*regs)),
+			"i" (sizeof(*regs) >> 2),
+			"m" (regs),
+			"r" (addr)
+			:
+			"cx", "dx", "si", "di", "cc", "memory");
+			return;
+		}
+
+/*
+ * Check if we're returning to the stack area, which is only likely to happen
+ * when attempting to exploit a buffer overflow.
+ */
+		if ((addr & 0xFF800000) == 0xBF800000 ||
+		    (addr >= PAGE_OFFSET - _STK_LIM && addr < PAGE_OFFSET))
+			security_alert("return onto stack running as "
+				"UID %d, EUID %d, process %s:%d",
+				"returns onto stack",
+				current->uid, current->euid,
+				current->comm, current->pid);
+	}
+
+#ifdef CONFIG_SECURE_STACK_SMART
+/* Check if it could have been a trampoline call */
+	if ((regs->xcs & 0xFFFF) == __USER_CS)
+	if (*(unsigned char *)regs->eip == 0xFF)
+	if (!__get_user(insn, (unsigned char *)(regs->eip + 1)))
+	if ((insn & 0xD8) == 0xD0 && insn != 0xD4) {	/* call *%reg */
+/* First, emulate the call */
+		regs->esp -= 4;
+		err = __put_user(regs->eip + 2, (unsigned long *)regs->esp);
+		regs->eip = *get_reg(regs, insn & 7);
+/* Then, start emulating the trampoline itself */
+		count = 0;
+		while (!__get_user(insn, (unsigned char *)regs->eip++))
+		if ((insn & 0xF8) == 0xB8) {		/* movl imm32,%reg */
+/* We only have 8 GP registers, no reason to initialize one twice */
+			if (count++ >= 8) break;
+			err |= __get_user(addr, (unsigned long *)regs->eip);
+			regs->eip += 4;
+			*get_reg(regs, insn & 7) = addr;
+		} else
+		if (insn == 0xFF) {
+			err |= __get_user(insn, (unsigned char *)regs->eip);
+			if ((insn & 0xF8) == 0xE0) {	/* jmp *%reg */
+				regs->eip = *get_reg(regs, insn & 7);
+				if (err) break; else return;
+			}
+			break;
+		} else
+		if (insn == 0xE9) {			/* jmp rel32 */
+			err |= __get_user(addr, (unsigned long *)regs->eip);
+			if (err) break;
+			regs->eip += 4 + addr;
+			return;
+		} else
+			break;
+	}
+#endif
+#endif
 
 	current->tss.error_code = error_code;
 	current->tss.trap_no = 13;
diff -urPX nopatch linux-2.2.18/arch/m68k/config.in linux/arch/m68k/config.in
--- linux-2.2.18/arch/m68k/config.in	Thu Dec 14 09:25:34 2000
+++ linux/arch/m68k/config.in	Thu Dec 14 09:33:08 2000
@@ -462,6 +462,8 @@
   endmenu
 fi
 
+source security/Config.in
+
 mainmenu_option next_comment
 comment 'Kernel hacking'
 
diff -urPX nopatch linux-2.2.18/arch/m68k/defconfig linux/arch/m68k/defconfig
--- linux-2.2.18/arch/m68k/defconfig	Thu Feb 25 21:46:46 1999
+++ linux/arch/m68k/defconfig	Thu Dec 14 09:33:08 2000
@@ -238,6 +238,16 @@
 # CONFIG_DMASOUND is not set
 
 #
+# Security
+#
+CONFIG_SECURE_LINK=y
+CONFIG_SECURE_FIFO=y
+# CONFIG_SECURE_PROC is not set
+CONFIG_SECURE_FD_0_1_2=y
+CONFIG_SECURE_RLIMIT_NPROC=y
+# CONFIG_SECURE_SHM is not set
+
+#
 # Kernel hacking
 #
 CONFIG_SCSI_CONSTANTS=y
diff -urPX nopatch linux-2.2.18/arch/mips/config.in linux/arch/mips/config.in
--- linux-2.2.18/arch/mips/config.in	Thu Jun  8 01:26:42 2000
+++ linux/arch/mips/config.in	Thu Dec 14 09:33:08 2000
@@ -294,6 +294,8 @@
   source drivers/sgi/Config.in
 fi
 
+source security/Config.in
+
 mainmenu_option next_comment
 comment 'Kernel hacking'
 
diff -urPX nopatch linux-2.2.18/arch/mips/defconfig linux/arch/mips/defconfig
--- linux-2.2.18/arch/mips/defconfig	Mon Aug  9 23:04:38 1999
+++ linux/arch/mips/defconfig	Thu Dec 14 09:33:08 2000
@@ -364,6 +364,16 @@
 # CONFIG_SOUND is not set
 
 #
+# Security
+#
+CONFIG_SECURE_LINK=y
+CONFIG_SECURE_FIFO=y
+# CONFIG_SECURE_PROC is not set
+CONFIG_SECURE_FD_0_1_2=y
+CONFIG_SECURE_RLIMIT_NPROC=y
+# CONFIG_SECURE_SHM is not set
+
+#
 # Kernel hacking
 #
 # CONFIG_CROSSCOMPILE is not set
diff -urPX nopatch linux-2.2.18/arch/ppc/config.in linux/arch/ppc/config.in
--- linux-2.2.18/arch/ppc/config.in	Thu Dec 14 09:25:34 2000
+++ linux/arch/ppc/config.in	Thu Dec 14 09:33:08 2000
@@ -195,6 +195,8 @@
 fi
 endmenu
 
+source security/Config.in
+
 mainmenu_option next_comment
 comment 'Sound'
 tristate 'Sound card support' CONFIG_SOUND
diff -urPX nopatch linux-2.2.18/arch/ppc/defconfig linux/arch/ppc/defconfig
--- linux-2.2.18/arch/ppc/defconfig	Mon Sep  4 21:39:16 2000
+++ linux/arch/ppc/defconfig	Thu Dec 14 09:33:08 2000
@@ -494,6 +494,16 @@
 # CONFIG_SOUND_OSS is not set
 
 #
+# Security
+#
+CONFIG_SECURE_LINK=y
+CONFIG_SECURE_FIFO=y
+# CONFIG_SECURE_PROC is not set
+CONFIG_SECURE_FD_0_1_2=y
+CONFIG_SECURE_RLIMIT_NPROC=y
+# CONFIG_SECURE_SHM is not set
+
+#
 # Kernel hacking
 #
 # CONFIG_MAGIC_SYSRQ is not set
diff -urPX nopatch linux-2.2.18/arch/s390/defconfig linux/arch/s390/defconfig
--- linux-2.2.18/arch/s390/defconfig	Thu Dec 14 09:25:34 2000
+++ linux/arch/s390/defconfig	Thu Dec 14 09:33:08 2000
@@ -159,6 +159,16 @@
 # CONFIG_NLS is not set
 
 #
+# Security
+#
+CONFIG_SECURE_LINK=y
+CONFIG_SECURE_FIFO=y
+# CONFIG_SECURE_PROC is not set
+CONFIG_SECURE_FD_0_1_2=y
+CONFIG_SECURE_RLIMIT_NPROC=y
+# CONFIG_SECURE_SHM is not set
+
+#
 # Kernel hacking
 #
 # CONFIG_PROFILE is not set
diff -urPX nopatch linux-2.2.18/arch/sparc/config.in linux/arch/sparc/config.in
--- linux-2.2.18/arch/sparc/config.in	Thu Dec 14 09:25:35 2000
+++ linux/arch/sparc/config.in	Thu Dec 14 09:33:08 2000
@@ -221,6 +221,8 @@
 tristate 'Software watchdog' CONFIG_SOFT_WATCHDOG
 endmenu
 
+source security/Config.in
+
 mainmenu_option next_comment
 comment 'Kernel hacking'
 
diff -urPX nopatch linux-2.2.18/arch/sparc/defconfig linux/arch/sparc/defconfig
--- linux-2.2.18/arch/sparc/defconfig	Thu Dec 14 09:25:35 2000
+++ linux/arch/sparc/defconfig	Thu Dec 14 09:33:08 2000
@@ -333,6 +333,16 @@
 # CONFIG_SOFT_WATCHDOG is not set
 
 #
+# Security
+#
+CONFIG_SECURE_LINK=y
+CONFIG_SECURE_FIFO=y
+# CONFIG_SECURE_PROC is not set
+CONFIG_SECURE_FD_0_1_2=y
+CONFIG_SECURE_RLIMIT_NPROC=y
+# CONFIG_SECURE_SHM is not set
+
+#
 # Kernel hacking
 #
 # CONFIG_MAGIC_SYSRQ is not set
diff -urPX nopatch linux-2.2.18/arch/sparc64/config.in linux/arch/sparc64/config.in
--- linux-2.2.18/arch/sparc64/config.in	Thu Dec 14 09:25:35 2000
+++ linux/arch/sparc64/config.in	Thu Dec 14 09:33:08 2000
@@ -292,6 +292,8 @@
 tristate 'Software watchdog' CONFIG_SOFT_WATCHDOG
 endmenu
 
+source security/Config.in
+
 mainmenu_option next_comment
 comment 'Kernel hacking'
 
diff -urPX nopatch linux-2.2.18/arch/sparc64/defconfig linux/arch/sparc64/defconfig
--- linux-2.2.18/arch/sparc64/defconfig	Thu Dec 14 09:25:35 2000
+++ linux/arch/sparc64/defconfig	Thu Dec 14 09:33:08 2000
@@ -383,6 +383,16 @@
 # CONFIG_NLS_KOI8_R is not set
 
 #
+# Security
+#
+CONFIG_SECURE_LINK=y
+CONFIG_SECURE_FIFO=y
+# CONFIG_SECURE_PROC is not set
+CONFIG_SECURE_FD_0_1_2=y
+CONFIG_SECURE_RLIMIT_NPROC=y
+# CONFIG_SECURE_SHM is not set
+
+#
 # Watchdog
 #
 # CONFIG_SOFT_WATCHDOG is not set
diff -urPX nopatch linux-2.2.18/fs/binfmt_aout.c linux/fs/binfmt_aout.c
--- linux-2.2.18/fs/binfmt_aout.c	Tue Jan  4 21:12:22 2000
+++ linux/fs/binfmt_aout.c	Thu Dec 14 09:33:08 2000
@@ -29,6 +29,8 @@
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 
+#include <linux/config.h>
+
 static int load_aout_binary(struct linux_binprm *, struct pt_regs * regs);
 static int load_aout_library(int fd);
 static int aout_core_dump(long signr, struct pt_regs * regs);
@@ -365,6 +367,9 @@
 	current->mm->mmap = NULL;
 	compute_creds(bprm);
  	current->flags &= ~PF_FORKNOEXEC;
+#ifdef CONFIG_SECURE_STACK
+	if (N_FLAGS(ex) & F_STACKEXEC) current->flags |= PF_STACKEXEC;
+#endif
 #ifdef __sparc__
 	if (N_MAGIC(ex) == NMAGIC) {
 		/* Fuck me plenty... */
diff -urPX nopatch linux-2.2.18/fs/binfmt_elf.c linux/fs/binfmt_elf.c
--- linux-2.2.18/fs/binfmt_elf.c	Thu Dec 14 09:25:47 2000
+++ linux/fs/binfmt_elf.c	Thu Dec 14 09:33:08 2000
@@ -63,7 +63,10 @@
 #define ELF_PAGEOFFSET(_v) ((_v) & (ELF_EXEC_PAGESIZE-1))
 #define ELF_PAGEALIGN(_v) (((_v) + ELF_EXEC_PAGESIZE - 1) & ~(ELF_EXEC_PAGESIZE - 1))
 
-static struct linux_binfmt elf_format = {
+#ifndef CONFIG_SECURE_STACK
+static
+#endif
+struct linux_binfmt elf_format = {
 #ifndef MODULE
 	NULL, NULL, load_elf_binary, load_elf_library, elf_core_dump
 #else
@@ -609,6 +612,9 @@
 	current->mm->end_code = 0;
 	current->mm->mmap = NULL;
 	current->flags &= ~PF_FORKNOEXEC;
+#ifdef CONFIG_SECURE_STACK
+	if (elf_ex.e_flags & EF_STACKEXEC) current->flags |= PF_STACKEXEC;
+#endif
 	elf_entry = (unsigned long) elf_ex.e_entry;
 
 	/* Do this immediately, since STACK_TOP as used in setup_arg_pages
diff -urPX nopatch linux-2.2.18/fs/exec.c linux/fs/exec.c
--- linux-2.2.18/fs/exec.c	Thu Dec 14 09:25:47 2000
+++ linux/fs/exec.c	Thu Dec 14 09:33:09 2000
@@ -39,6 +39,9 @@
 #ifdef CONFIG_KMOD
 #include <linux/kmod.h>
 #endif
+#ifdef CONFIG_SECURE_FD_0_1_2
+#include <linux/major.h>
+#endif
 
 /*
  * Here are the actual binaries that will be accepted:
@@ -467,6 +470,82 @@
 		kfree(oldsig);
 }
 
+#ifdef CONFIG_SECURE_FD_0_1_2
+/*
+ * Make sure fd's 0, 1, and 2 are open to prevent nasty
+ * security problems -- 98/07/01 peak
+ *
+ * Linux 2.2 updates -- 19990829 SD
+ */
+
+static inline int tweak_fd_open_null(struct linux_binprm *bprm)
+{
+	struct inode *i;
+	struct dentry *d;
+	struct file *f;
+
+	if (!(i = get_empty_inode()))
+		return -ENOMEM;
+	if (!(d = dget(d_alloc_root(i, NULL)))) {
+		iput(i);
+		return -ENOMEM;
+	}
+	if (!(f = get_empty_filp())) {
+		dput(d);
+		iput(i);
+		return -ENFILE;
+	}
+
+	i->i_mode = S_IFCHR | S_IRUGO | S_IWUGO;
+	i->i_uid = current->fsuid;
+	i->i_gid = current->fsgid;
+	i->i_rdev = MKDEV(MEM_MAJOR, 3); /* /dev/null */
+	i->i_blksize = PAGE_SIZE;
+	i->i_blocks = 0;
+	i->i_atime = i->i_mtime = i->i_ctime = CURRENT_TIME;
+	i->i_op = &chrdev_inode_operations;
+	i->i_state = I_DIRTY; /* so that mark_inode_dirty() won't touch us */
+	f->f_flags = O_RDWR;
+	f->f_mode = FMODE_READ | FMODE_WRITE;
+	f->f_dentry = d;
+	f->f_pos = 0;
+	f->f_reada = 0;
+	f->f_op = i->i_op->default_file_ops;
+	f->f_op->open(i, f); /* chrdev_open */
+
+	bprm->tweak_fd_null = f;
+
+	return 0;
+}
+
+static int tweak_fd_0_1_2(struct linux_binprm *bprm)
+{
+	int fd, new, retval;
+
+	for (fd = 0; fd <= 2; fd++) {
+		if (current->files->fd[fd]) continue;
+
+		if ((new = get_unused_fd()) != fd) {
+			if (new >= 0) put_unused_fd(new);
+			return -EMFILE;
+		}
+
+		if (bprm->tweak_fd_null)
+		/* fake dup2() */
+			bprm->tweak_fd_null->f_count++;
+		else
+		/* fake open("/dev/null", O_RDWR) */
+		if ((retval = tweak_fd_open_null(bprm)))
+			return retval;
+
+		fd_install(fd, bprm->tweak_fd_null);
+		bprm->tweak_fd_mask |= 1 << fd;
+	}
+
+	return 0;
+}
+#endif
+
 /*
  * These functions flushes out all traces of the currently running executable
  * so that a new one can be started
@@ -529,6 +608,10 @@
 	}
 	current->comm[i] = '\0';
 
+#ifdef CONFIG_SECURE_STACK
+	current->flags &= ~PF_STACKEXEC;
+#endif
+
 	flush_thread();
 
 	if (bprm->e_uid != current->euid || bprm->e_gid != current->egid || 
@@ -540,6 +623,12 @@
 	flush_signal_handlers(current);
 	flush_old_files(current->files);
 
+#ifdef CONFIG_SECURE_FD_0_1_2
+	/* take care of close-on-exec files */
+	if (bprm->priv_change)
+		return tweak_fd_0_1_2(bprm);
+#endif
+
 	return 0;
 
 mmap_failed:
@@ -646,7 +735,8 @@
 		}
 	}
 
-	if (id_change || cap_raised) {
+	bprm->priv_change = id_change || cap_raised;
+	if (bprm->priv_change) {
 		/* We can't suid-execute if we're sharing parts of the executable */
 		/* or if we're being traced (or if suid execs are not allowed)    */
 		/* (current->mm->count > 1 is ok, as we'll get a new mm anyway)   */
@@ -660,6 +750,12 @@
  			if (cap_raised && !capable(CAP_SETPCAP))
   				return -EPERM;
 		}
+
+#ifdef CONFIG_SECURE_FD_0_1_2
+		/* warning: must be done BEFORE binfmt calls open_inode() */
+		if ((retval = tweak_fd_0_1_2(bprm)))
+			return retval;
+#endif
 	}
 
 	memset(bprm->buf,0,sizeof(bprm->buf));
@@ -826,6 +922,19 @@
 	int retval;
 	int i;
 
+#ifdef CONFIG_SECURE_RLIMIT_NPROC
+/*
+ * This check is similar to that done in kernel/fork.c, except that we
+ * are not going to allocate a new task slot here.
+ *
+ * Note that we can only exceed the limit if our UID has changed.
+ */
+	if (current->user)
+	if (atomic_read(&current->user->count) >
+	    current->rlim[RLIMIT_NPROC].rlim_cur)
+		return -EAGAIN;
+#endif
+
 	bprm.p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *);
 	for (i=0 ; i<MAX_ARG_PAGES ; i++)	/* clear page-table */
 		bprm.page[i] = 0;
@@ -851,6 +960,11 @@
 		return bprm.envc;
 	}
 
+#ifdef CONFIG_SECURE_FD_0_1_2
+	bprm.tweak_fd_mask = 0;
+	bprm.tweak_fd_null = NULL;
+#endif
+
 	retval = prepare_binprm(&bprm);
 	
 	if (retval >= 0) {
@@ -874,6 +988,13 @@
 
 	for (i=0 ; i<MAX_ARG_PAGES ; i++)
 		free_page(bprm.page[i]);
+
+#ifdef CONFIG_SECURE_FD_0_1_2
+	/* recover from fd tweaking */
+	for (i = 0; i <= 2; i++)
+	if (bprm.tweak_fd_mask << i)
+		(void)sys_close(i);
+#endif
 
 	return retval;
 }
diff -urPX nopatch linux-2.2.18/fs/namei.c linux/fs/namei.c
--- linux-2.2.18/fs/namei.c	Thu Dec 14 09:25:47 2000
+++ linux/fs/namei.c	Thu Dec 14 12:56:27 2000
@@ -12,6 +12,7 @@
  * lookup logic.
  */
 
+#include <linux/config.h>
 #include <linux/mm.h>
 #include <linux/proc_fs.h>
 #include <linux/smp_lock.h>
@@ -287,6 +288,28 @@
 		if (current->link_count < 5) {
 			struct dentry * result;
 
+#ifdef CONFIG_SECURE_LINK
+			/*
+			 * Don't follow links that we don't own in +t
+			 * directories, unless the link is owned by the
+			 * owner of the directory.
+			 */
+			if (S_ISLNK(inode->i_mode) &&
+			    (base->d_inode->i_mode & S_ISVTX) &&
+			    inode->i_uid != base->d_inode->i_uid &&
+			    current->fsuid != inode->i_uid) {
+				security_alert("not followed symlink of %d.%d "
+					"by UID %d, EUID %d, process %s:%d",
+					"symlinks not followed",
+					inode->i_uid, inode->i_gid,
+					current->uid, current->euid,
+					current->comm, current->pid);
+				dput(dentry);
+				dput(base);
+				return ERR_PTR(-EACCES);
+			}
+#endif
+
 			current->link_count++;
 			/* This eats the base */
 			result = inode->i_op->follow_link(dentry, base, follow);
@@ -680,10 +703,17 @@
 		struct dentry *dir;
 
 		if (dentry->d_inode) {
-			if (!(flag & O_EXCL))
-				goto nocreate;
 			error = -EEXIST;
-			goto exit;
+			if (flag & O_EXCL)
+				goto exit;
+#ifdef CONFIG_SECURE_FIFO
+			if (!S_ISFIFO(dentry->d_inode->i_mode) ||
+			    !dentry->d_inode->i_sb ||
+			    dentry->d_inode->i_sb->s_magic == PROC_SUPER_MAGIC)
+				goto nocreate;
+#else
+			goto nocreate;
+#endif
 		}
 
 		dir = lock_parent(dentry);
@@ -702,6 +732,29 @@
 			goto exit;
 		}
 
+#ifdef CONFIG_SECURE_FIFO
+		/*
+		 * Don't write to FIFOs that we don't own in +t directories,
+		 * unless the FIFO is owned by the owner of the directory.
+		 */
+		if ((inode = dentry->d_inode))
+		if (S_ISFIFO(inode->i_mode) && !(flag & O_EXCL) &&
+		    (dir->d_inode->i_mode & S_ISVTX) &&
+		    inode->i_uid != dir->d_inode->i_uid &&
+		    current->fsuid != inode->i_uid) {
+			if (!permission(inode, acc_mode))
+			security_alert("denied writing FIFO of %d.%d "
+				"by UID %d, EUID %d, process %s:%d",
+				"writes into a FIFO denied",
+				inode->i_uid, inode->i_gid,
+				current->uid, current->euid,
+				current->comm, current->pid);
+			error = -EACCES;
+			unlock_dir(dir);
+			goto exit;
+		}
+#endif
+
 		/*
 		 * Somebody might have created the file while we
 		 * waited for the directory lock.. So we have to
@@ -1174,6 +1227,28 @@
 	inode = old_dentry->d_inode;
 	if (!inode)
 		goto exit_lock;
+
+#ifdef CONFIG_SECURE_LINK
+	/*
+	 * Don't allow users to create hard links to files they don't own,
+	 * unless they could read and write the file or have CAP_FOWNER.
+	 *
+	 * The real UID check is here as a workaround for atd(8) only, to
+	 * be removed one day.
+	 */
+	if (current->fsuid != inode->i_uid &&
+	    (error = permission(inode, MAY_READ | MAY_WRITE)) &&
+	    !capable(CAP_FOWNER) &&
+	    current->uid) {
+		security_alert("denied hard link to %d.%d "
+			"for UID %d, EUID %d, process %s:%d",
+			"hard links denied",
+			inode->i_uid, inode->i_gid,
+			current->uid, current->euid,
+			current->comm, current->pid);
+		goto exit_lock;
+	}
+#endif
 
 	error = may_create(dir->d_inode, new_dentry);
 	if (error)
diff -urPX nopatch linux-2.2.18/fs/proc/array.c linux/fs/proc/array.c
--- linux-2.2.18/fs/proc/array.c	Thu Dec 14 09:25:48 2000
+++ linux/fs/proc/array.c	Thu Dec 14 09:33:09 2000
@@ -1444,11 +1444,14 @@
 	return -EBADF;
 }
 
-static int process_unauthorized(int type, int pid)
+static int process_unauthorized(int type, int pid, struct inode *inode)
 {
 	struct task_struct *p;
 	uid_t euid=0;	/* Save the euid keep the lock short */
 	int ok = 0;
+#ifdef CONFIG_SECURE_PROC
+	gid_t gid;
+#endif
 		
 	read_lock(&tasklist_lock);
 	
@@ -1480,7 +1483,16 @@
 		case PROC_PID_MAPS:
 		case PROC_PID_CMDLINE:
 		case PROC_PID_CPU:
+#ifdef CONFIG_SECURE_PROC
+			gid = 0;
+			if (inode->i_sb->s_root)
+				gid = inode->i_sb->s_root->d_inode->i_gid;
+			if (in_group_p(gid))
+				return 0;
+			ok = 1;
+#else
 			return 0;	
+#endif
 	}
 	if((current->fsuid == euid && ok) || capable(CAP_DAC_OVERRIDE))
 		return 0;
@@ -1540,7 +1552,7 @@
 	start = NULL;
 	dp = (struct proc_dir_entry *) inode->u.generic_ip;
 	
-	if (pid && process_unauthorized(type, pid))
+	if (pid && process_unauthorized(type, pid, inode))
 	{
 		free_page(page);
 		return -EIO;
diff -urPX nopatch linux-2.2.18/fs/proc/base.c linux/fs/proc/base.c
--- linux-2.2.18/fs/proc/base.c	Tue Aug 25 00:02:43 1998
+++ linux/fs/proc/base.c	Thu Dec 14 09:33:09 2000
@@ -69,6 +69,10 @@
 		if (p->dumpable || ino == PROC_PID_INO) {
 			uid = p->euid;
 			gid = p->egid;
+#ifdef CONFIG_SECURE_PROC
+			if (inode->i_sb->s_root)
+				gid = inode->i_sb->s_root->d_inode->i_gid;
+#endif
 		}
 		inode->i_uid = uid;
 		inode->i_gid = gid;
@@ -84,7 +88,12 @@
  */
 struct proc_dir_entry proc_pid = {
 	PROC_PID_INO, 5, "<pid>",
-	S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0,
+#ifdef CONFIG_SECURE_PROC
+	S_IFDIR | S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP,
+#else
+	S_IFDIR | S_IRUGO | S_IXUGO,
+#endif
+	2, 0, 0,
 	0, &proc_base_inode_operations,
 	NULL, proc_pid_fill_inode,
 	NULL, &proc_root, NULL
diff -urPX nopatch linux-2.2.18/fs/proc/inode.c linux/fs/proc/inode.c
--- linux-2.2.18/fs/proc/inode.c	Mon Sep  4 21:39:27 2000
+++ linux/fs/proc/inode.c	Thu Dec 14 09:33:09 2000
@@ -271,6 +271,10 @@
 			inode->i_mode = de->mode;
 			inode->i_uid = de->uid;
 			inode->i_gid = de->gid;
+#ifdef CONFIG_SECURE_PROC
+			if (sb->s_root)
+				inode->i_gid = sb->s_root->d_inode->i_gid;
+#endif
 		}
 		if (de->size)
 			inode->i_size = de->size;
@@ -365,6 +369,10 @@
 	inode->i_mode = 0;
 	inode->i_uid = 0;
 	inode->i_gid = 0;
+#ifdef CONFIG_SECURE_PROC
+	if (inode->i_sb->s_root)
+		inode->i_gid = inode->i_sb->s_root->d_inode->i_gid;
+#endif
 	inode->i_nlink = 1;
 	inode->i_size = 0;
 
@@ -380,7 +388,9 @@
 	ino &= 0x0000ffff;
 	if (ino == PROC_PID_INO || p->dumpable) {
 		inode->i_uid = p->euid;
+#ifndef CONFIG_SECURE_PROC
 		inode->i_gid = p->egid;
+#endif
 	}
 	if (ino & PROC_PID_FD_DIR) {
 		struct file * file;
diff -urPX nopatch linux-2.2.18/fs/proc/proc_tty.c linux/fs/proc/proc_tty.c
--- linux-2.2.18/fs/proc/proc_tty.c	Thu Jun  8 01:26:44 2000
+++ linux/fs/proc/proc_tty.c	Thu Dec 14 09:33:09 2000
@@ -6,6 +6,7 @@
 
 #include <asm/uaccess.h>
 
+#include <linux/config.h>
 #include <linux/init.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
@@ -178,7 +179,11 @@
 	if (!ent)
 		return;
 	proc_tty_ldisc = create_proc_entry("tty/ldisc", S_IFDIR, 0);
+#ifdef CONFIG_SECURE_PROC
+	proc_tty_driver = create_proc_entry("tty/driver", S_IFDIR | S_IRXUG, 0);
+#else
 	proc_tty_driver = create_proc_entry("tty/driver", S_IFDIR, 0);
+#endif
 
 	ent = create_proc_entry("tty/ldiscs", 0, 0);
 	ent->read_proc = tty_ldiscs_read_proc;
diff -urPX nopatch linux-2.2.18/fs/proc/root.c linux/fs/proc/root.c
--- linux-2.2.18/fs/proc/root.c	Thu Dec 14 09:25:48 2000
+++ linux/fs/proc/root.c	Thu Dec 14 09:33:09 2000
@@ -169,7 +169,12 @@
 #ifdef CONFIG_SYSCTL
 struct proc_dir_entry proc_sys_root = {
 	PROC_SYS, 3, "sys",			/* inode, name */
-	S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0,	/* mode, nlink, uid, gid */
+#ifdef CONFIG_SECURE_PROC
+	S_IFDIR | S_IRXUG,			/* mode */
+#else
+	S_IFDIR | S_IRUGO | S_IXUGO,		/* mode */
+#endif
+	2, 0, 0,				/* nlink, uid, gid */
 	0, &proc_dir_inode_operations,		/* size, ops */
 	NULL, NULL,				/* get_info, fill_inode */
 	NULL,					/* next */
@@ -568,12 +573,22 @@
 #ifdef CONFIG_MODULES
 static struct proc_dir_entry proc_root_modules = {
 	PROC_MODULES, 7, "modules",
-	S_IFREG | S_IRUGO, 1, 0, 0,
+#ifdef CONFIG_SECURE_PROC
+	S_IFREG | S_IRUSR,
+#else
+	S_IFREG | S_IRUGO,
+#endif
+	1, 0, 0,
 	0, &proc_array_inode_operations
 };
 static struct proc_dir_entry proc_root_ksyms = {
 	PROC_KSYMS, 5, "ksyms",
-	S_IFREG | S_IRUGO, 1, 0, 0,
+#ifdef CONFIG_SECURE_PROC
+	S_IFREG | S_IRUSR,
+#else
+	S_IFREG | S_IRUGO,
+#endif
+	1, 0, 0,
 	0, &proc_array_inode_operations
 };
 #endif
@@ -685,7 +700,11 @@
 	proc_register(&proc_root, &proc_root_version);
 	proc_register(&proc_root, &proc_root_cpuinfo);
 	proc_register(&proc_root, &proc_root_self);
+#ifdef CONFIG_SECURE_PROC
+	proc_net = create_proc_entry("net", S_IFDIR | S_IRXUG, 0);
+#else
 	proc_net = create_proc_entry("net", S_IFDIR, 0);
+#endif
 	proc_scsi = create_proc_entry("scsi", S_IFDIR, 0);
 #ifdef CONFIG_SYSCTL
 	proc_register(&proc_root, &proc_sys_root);
diff -urPX nopatch linux-2.2.18/include/asm-i386/a.out.h linux/include/asm-i386/a.out.h
--- linux-2.2.18/include/asm-i386/a.out.h	Fri Jun 16 22:33:06 1995
+++ linux/include/asm-i386/a.out.h	Thu Dec 14 11:45:59 2000
@@ -19,7 +19,16 @@
 
 #ifdef __KERNEL__
 
+#include <linux/config.h>
+
+#ifdef CONFIG_SECURE_STACK
+#define STACK_TOP ( \
+	(current->flags & PF_STACKEXEC) \
+	? TASK_SIZE - _STK_LIM \
+	: TASK_SIZE )
+#else
 #define STACK_TOP	TASK_SIZE
+#endif
 
 #endif
 
diff -urPX nopatch linux-2.2.18/include/asm-i386/processor.h linux/include/asm-i386/processor.h
--- linux-2.2.18/include/asm-i386/processor.h	Thu Dec 14 09:25:49 2000
+++ linux/include/asm-i386/processor.h	Thu Dec 14 11:45:59 2000
@@ -11,6 +11,8 @@
 #include <asm/math_emu.h>
 #include <asm/segment.h>
 #include <asm/page.h>
+#include <linux/config.h>
+#include <linux/binfmts.h>
 
 /*
  *  CPU type and hardware bug flags. Kept separately for each CPU.
@@ -163,10 +165,27 @@
  */
 #define TASK_SIZE	(PAGE_OFFSET)
 
+/*
+ * Magic addresses to return to the kernel from signal handlers. These two
+ * should be beyond user code segment limit, adjacent, and MAGIC_SIGRETURN
+ * should be even.
+ */
+#define MAGIC_SIGRETURN		(PAGE_OFFSET + 0xDE0000)
+#define MAGIC_RT_SIGRETURN	(PAGE_OFFSET + 0xDE0001)
+
 /* This decides where the kernel will search for a free chunk of vm
  * space during mmap's.
  */
+#if defined(CONFIG_SECURE_STACK) && defined(CONFIG_BINFMT_ELF)
+extern struct linux_binfmt elf_format;
+#define TASK_UNMAPPED_BASE ( \
+	current->binfmt == &elf_format && \
+	!(current->flags & PF_STACKEXEC) \
+	? 0x00110000UL \
+	: TASK_SIZE / 3 )
+#else
 #define TASK_UNMAPPED_BASE	(TASK_SIZE / 3)
+#endif
 
 /*
  * Size of io_bitmap in longwords: 32 is ports 0-0x3ff.
diff -urPX nopatch linux-2.2.18/include/linux/a.out.h linux/include/linux/a.out.h
--- linux-2.2.18/include/linux/a.out.h	Mon Aug  9 23:04:41 1999
+++ linux/include/linux/a.out.h	Thu Dec 14 11:45:59 2000
@@ -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 -urPX nopatch linux-2.2.18/include/linux/binfmts.h linux/include/linux/binfmts.h
--- linux-2.2.18/include/linux/binfmts.h	Mon Aug  9 23:04:41 1999
+++ linux/include/linux/binfmts.h	Thu Dec 14 11:45:54 2000
@@ -1,6 +1,7 @@
 #ifndef _LINUX_BINFMTS_H
 #define _LINUX_BINFMTS_H
 
+#include <linux/config.h>
 #include <linux/ptrace.h>
 #include <linux/capability.h>
 
@@ -28,6 +29,11 @@
 	int argc, envc;
 	char * filename;	/* Name of binary */
 	unsigned long loader, exec;
+	int priv_change;
+#ifdef CONFIG_SECURE_FD_0_1_2
+	int tweak_fd_mask;
+	struct file *tweak_fd_null;
+#endif
 };
 
 /*
diff -urPX nopatch linux-2.2.18/include/linux/elf.h linux/include/linux/elf.h
--- linux-2.2.18/include/linux/elf.h	Tue Jan  4 21:12:24 2000
+++ linux/include/linux/elf.h	Thu Dec 14 11:50:26 2000
@@ -241,6 +241,8 @@
 #define R_MIPS_LOVENDOR		100
 #define R_MIPS_HIVENDOR		127
 
+/* Constants for the e_flags field */
+#define EF_STACKEXEC	1	/* Executable stack area forced */
 
 /*
  * Sparc ELF relocation types
diff -urPX nopatch linux-2.2.18/include/linux/kernel.h linux/include/linux/kernel.h
--- linux-2.2.18/include/linux/kernel.h	Thu Dec 14 09:25:51 2000
+++ linux/include/linux/kernel.h	Thu Dec 14 11:33:08 2000
@@ -49,8 +49,12 @@
 extern unsigned long simple_strtoul(const char *,char **,unsigned int);
 extern long simple_strtol(const char *,char **,unsigned int);
 extern char *get_options(char *str, int *ints);
-extern int sprintf(char * buf, const char * fmt, ...);
-extern int vsprintf(char *buf, const char *, va_list);
+extern int sprintf(char *buf, const char *fmt, ...)
+	__attribute__ ((format (printf, 2, 3)));
+extern int vsprintf(char *buf, const char *, va_list)
+	__attribute__ ((format (printf, 2, 0)));
+extern int _vsnprintf(char *buf, int n, const char *, va_list)
+	__attribute__ ((format (printf, 3, 0)));
 
 extern int session_of_pgrp(int pgrp);
 
@@ -77,6 +81,26 @@
 	((unsigned char *)&addr)[1], \
 	((unsigned char *)&addr)[2], \
 	((unsigned char *)&addr)[3]
+
+#define security_alert(normal_msg, flood_msg, args...) \
+({ \
+	static unsigned long warning_time = 0, no_flood_yet = 0; \
+	static spinlock_t security_alert_lock = SPIN_LOCK_UNLOCKED; \
+\
+	spin_lock(&security_alert_lock); \
+\
+/* 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 "Security: " normal_msg "\n", ## args); \
+	} else if (no_flood_yet) { \
+		warning_time = jiffies; no_flood_yet = 0; \
+		printk(KERN_ALERT "Security: more " flood_msg \
+			", logging disabled for a minute\n"); \
+	} \
+\
+	spin_unlock(&security_alert_lock); \
+})
 
 #endif /* __KERNEL__ */
 
diff -urPX nopatch linux-2.2.18/include/linux/sched.h linux/include/linux/sched.h
--- linux-2.2.18/include/linux/sched.h	Thu Dec 14 09:25:51 2000
+++ linux/include/linux/sched.h	Thu Dec 14 11:45:59 2000
@@ -225,7 +225,11 @@
  * Right now it is only used to track how many processes a
  * user has, but it has the potential to track memory usage etc.
  */
-struct user_struct;
+struct user_struct {
+	atomic_t count;
+	struct user_struct *next, **pprev;
+	unsigned int uid;
+};
 
 struct task_struct {
 /* these are hardcoded - don't touch */
@@ -352,6 +356,8 @@
 
 #define PF_USEDFPU	0x00100000	/* task used FPU this quantum (SMP) */
 #define PF_DTRACE	0x00200000	/* delayed trace (used on m68k, i386) */
+
+#define PF_STACKEXEC	0x01000000	/* Executable stack area forced */
 
 /*
  * Limit the stack by to some sane default: root can always
diff -urPX nopatch linux-2.2.18/include/linux/stat.h linux/include/linux/stat.h
--- linux-2.2.18/include/linux/stat.h	Mon May 25 21:32:52 1998
+++ linux/include/linux/stat.h	Thu Dec 14 09:33:09 2000
@@ -52,6 +52,7 @@
 #define S_IRUGO		(S_IRUSR|S_IRGRP|S_IROTH)
 #define S_IWUGO		(S_IWUSR|S_IWGRP|S_IWOTH)
 #define S_IXUGO		(S_IXUSR|S_IXGRP|S_IXOTH)
+#define S_IRXUG		(S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP)
 #endif
 
 #endif
diff -urPX nopatch linux-2.2.18/ipc/shm.c linux/ipc/shm.c
--- linux-2.2.18/ipc/shm.c	Thu Jun  8 01:26:44 2000
+++ linux/ipc/shm.c	Thu Dec 14 09:33:09 2000
@@ -6,6 +6,7 @@
  * Fixed the shm swap deallocation (shm_unuse()), August 1998 Andrea Arcangeli.
  */
 
+#include <linux/config.h>
 #include <linux/malloc.h>
 #include <linux/shm.h>
 #include <linux/swap.h>
@@ -576,9 +577,34 @@
 	remove_attach(shp,shmd);  /* remove from shp->attaches */
   	shp->u.shm_lpid = current->pid;
 	shp->u.shm_dtime = CURRENT_TIME;
+#ifdef CONFIG_SECURE_SHM
+	shp->u.shm_perm.mode |= SHM_DEST;
+	if (--shp->u.shm_nattch <= 0)
+#else
 	if (--shp->u.shm_nattch <= 0 && shp->u.shm_perm.mode & SHM_DEST)
+#endif
 		killseg (id);
 }
+
+#ifdef CONFIG_SECURE_SHM
+void shm_exit (void)
+{
+	int id;
+	struct shmid_kernel *shp;
+
+	for (id = 0; id <= max_shmid; id++) {
+		shp = shm_segs[id];
+		if (shp == IPC_UNUSED || shp == IPC_NOID) continue;
+
+		if (shp->u.shm_cpid != current->pid) continue;
+
+		if (shp->u.shm_nattch <= 0) {
+			shp->u.shm_perm.mode |= SHM_DEST;
+			killseg(id);
+		}
+	}
+}
+#endif
 
 /*
  * detach and kill segment if marked destroyed.
diff -urPX nopatch linux-2.2.18/ipc/util.c linux/ipc/util.c
--- linux-2.2.18/ipc/util.c	Tue Jan  5 01:38:48 1999
+++ linux/ipc/util.c	Thu Dec 14 09:33:09 2000
@@ -58,6 +58,13 @@
     return;
 }
 
+#ifdef CONFIG_SECURE_SHM
+void shm_exit (void)
+{
+    return;
+}
+#endif
+
 int shm_swap (int prio, int gfp_mask)
 {
     return 0;
diff -urPX nopatch linux-2.2.18/kernel/exit.c linux/kernel/exit.c
--- linux-2.2.18/kernel/exit.c	Tue Jan  4 21:12:25 2000
+++ linux/kernel/exit.c	Thu Dec 14 09:33:09 2000
@@ -19,6 +19,9 @@
 #include <asm/mmu_context.h>
 
 extern void sem_exit (void);
+#ifdef CONFIG_SECURE_SHM
+extern void shm_exit (void);
+#endif
 extern struct task_struct *child_reaper;
 
 int getrusage(struct task_struct *, int, struct rusage *);
@@ -391,6 +394,9 @@
 	acct_process(code);
 #endif
 	sem_exit();
+#ifdef CONFIG_SECURE_SHM
+	shm_exit();
+#endif
 	__exit_mm(tsk);
 #if CONFIG_AP1000
 	exit_msc(tsk);
diff -urPX nopatch linux-2.2.18/kernel/fork.c linux/kernel/fork.c
--- linux-2.2.18/kernel/fork.c	Wed Oct 27 04:53:42 1999
+++ linux/kernel/fork.c	Thu Dec 14 09:33:09 2000
@@ -45,11 +45,7 @@
  */
 #define UIDHASH_SZ	(PIDHASH_SZ >> 2)
 
-static struct user_struct {
-	atomic_t count;
-	struct user_struct *next, **pprev;
-	unsigned int uid;
-} *uidhash[UIDHASH_SZ];
+static struct user_struct *uidhash[UIDHASH_SZ];
 
 spinlock_t uidhash_lock = SPIN_LOCK_UNLOCKED;
 
diff -urPX nopatch linux-2.2.18/kernel/printk.c linux/kernel/printk.c
--- linux-2.2.18/kernel/printk.c	Thu Dec 14 09:25:52 2000
+++ linux/kernel/printk.c	Thu Dec 14 11:27:43 2000
@@ -14,6 +14,7 @@
  *     manfreds@colorfullife.com
  */
 
+#include <linux/config.h>
 #include <linux/mm.h>
 #include <linux/tty_driver.h>
 #include <linux/smp_lock.h>
@@ -244,8 +245,13 @@
 
 asmlinkage int sys_syslog(int type, char * buf, int len)
 {
+#ifdef CONFIG_SECURE_PROC
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+#else
 	if ((type != 3) && !capable(CAP_SYS_ADMIN))
 		return -EPERM;
+#endif
 	return do_syslog(type, buf, len);
 }
 
@@ -260,7 +266,7 @@
 
 	spin_lock_irqsave(&console_lock, flags);
 	va_start(args, fmt);
-	i = vsprintf(buf + 3, fmt, args); /* hopefully i < sizeof(buf)-4 */
+	i = _vsnprintf(buf + 3, sizeof(buf) - sizeof(buf) / 8 - 3, fmt, args);
 	buf_end = buf + 3 + i;
 	va_end(args);
 	for (p = buf + 3; p < buf_end; p++) {
diff -urPX nopatch linux-2.2.18/lib/vsprintf.c linux/lib/vsprintf.c
--- linux-2.2.18/lib/vsprintf.c	Mon Mar 15 22:19:05 1999
+++ linux/lib/vsprintf.c	Thu Dec 14 11:26:23 2000
@@ -142,7 +142,7 @@
 /* Forward decl. needed for IP address printing stuff... */
 int sprintf(char * buf, const char *fmt, ...);
 
-int vsprintf(char *buf, const char *fmt, va_list args)
+int _vsnprintf(char *buf, int n, const char *fmt, va_list args)
 {
 	int len;
 	unsigned long num;
@@ -157,7 +157,7 @@
 				   number of chars for from string */
 	int qualifier;		/* 'h', 'l', or 'L' for integer fields */
 
-	for (str=buf ; *fmt ; ++fmt) {
+	for (str = buf; *fmt && (n == -1 || str - buf < n); ++fmt) {
 		if (*fmt != '%') {
 			*str++ = *fmt;
 			continue;
@@ -231,6 +231,12 @@
 
 			len = strnlen(s, precision);
 
+			if (n != -1 && len >= n - (str - buf)) {
+				len = n - 1 - (str - buf);
+				if (len <= 0) break;
+				if (len < field_width) field_width = len;
+			}
+
 			if (!(flags & LEFT))
 				while (len < field_width--)
 					*str++ = ' ';
@@ -304,6 +310,11 @@
 	}
 	*str = '\0';
 	return str-buf;
+}
+
+int vsprintf(char *buf, const char *fmt, va_list args)
+{
+	return _vsnprintf(buf, -1, fmt, args);
 }
 
 int sprintf(char * buf, const char *fmt, ...)
diff -urPX nopatch linux-2.2.18/security/Common.in linux/security/Common.in
--- linux-2.2.18/security/Common.in	Thu Jan  1 03:00:00 1970
+++ linux/security/Common.in	Thu Dec 14 09:33:09 2000
@@ -0,0 +1,12 @@
+#
+# Security options common to all architectures
+#
+
+bool 'Restricted links in /tmp' CONFIG_SECURE_LINK
+bool 'Restricted FIFOs in /tmp' CONFIG_SECURE_FIFO
+bool 'Restricted /proc' CONFIG_SECURE_PROC
+bool 'Special handling of fd 0, 1, and 2' CONFIG_SECURE_FD_0_1_2
+bool 'Enforce RLIMIT_NPROC on execve(2)' CONFIG_SECURE_RLIMIT_NPROC
+if [ "$CONFIG_SYSVIPC" = "y" ]; then
+	bool 'Destroy shared memory segments not in use' CONFIG_SECURE_SHM
+fi
diff -urPX nopatch linux-2.2.18/security/Config.in linux/security/Config.in
--- linux-2.2.18/security/Config.in	Thu Jan  1 03:00:00 1970
+++ linux/security/Config.in	Thu Dec 14 09:33:09 2000
@@ -0,0 +1,9 @@
+#
+# Security options
+#
+mainmenu_option next_comment
+comment 'Security options'
+
+source security/Common.in
+
+endmenu
