Linux kernel patch to remove stack exec permission
Sat, 12 Apr 1997 13:03:07 -0300 (GMT)


There seemed to be no patch for Linux kernel to remove execute permission
from the stack (to prevent most buffer overflow exploits), so I decided to
make one, I include it at the end of this message. I heard some rumours that
GCC assumes stack frame to be executable when dealing with nested functions,
but I couldn't reproduce that. I'm running this patched kernel for a day now,
and everything (well, except for the exploits) seems to work fine. However,
some programs may depend on the stack being executable... I'd like to hear
any reports of this.

The patch is for Linux 2.0.30 (should work on others also), x86 only.
Originally user code, data and stack segments were mapped to the same memory,
and had the same limit. I decreased the code segment's limit, so it doesn't
cover the actual stack space (since the stack grows down). Actually, I
created a new descriptor instead, leaving the old one with its original
limit, since that still allows to execute some code on the stack when needed,
by using old code segment selector. For example, the kernel itself needs that
ability to return from signal handlers.

Note that the BSS and malloc()ed areas are still executable. Some buffer
overflows are still exploitable, by making the program put the shellcode
somewhere else in its memory space, not on the stack, and overwriting the
return address to point to that area. Also, some programs may already have
a suitable code in them, and not require an external shellcode at all. So
this patch only prevents most overflows from being exploitable, not all of

diff -u --recursive /extra/linux-2.0.30/arch/i386/kernel/head.S linux/arch/i386/kernel/head.S
--- /extra/linux-2.0.30/arch/i386/kernel/head.S Sat Apr 12 10:41:59 1997
+++ linux/arch/i386/kernel/head.S Sat Apr 12 10:44:58 1997
@@ -402,7 +402,7 @@
.quad 0xc0c392000000ffff /* 0x18 kernel 1GB data at 0xC0000000 */
.quad 0x00cbfa000000ffff /* 0x23 user 3GB code at 0x00000000 */
.quad 0x00cbf2000000ffff /* 0x2b user 3GB data at 0x00000000 */
- .quad 0x0000000000000000 /* not used */
+ .quad 0x00cafa000000ffff /* 0x33 user 2.75GB code */
.quad 0x0000000000000000 /* not used */
.fill 2*NR_TASKS,8,0 /* space for LDT's and TSS's etc */
diff -u --recursive /extra/linux-2.0.30/arch/i386/kernel/signal.c linux/arch/i386/kernel/signal.c
--- /extra/linux-2.0.30/arch/i386/kernel/signal.c Sat Apr 12 10:41:59 1997
+++ linux/arch/i386/kernel/signal.c Sat Apr 12 10:44:58 1997
@@ -214,7 +214,7 @@
/* 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->cs = USER_HUGE_CS; regs->ss = USER_DS;
regs->ds = USER_DS; regs->es = USER_DS;
regs->gs = USER_DS; regs->fs = USER_DS;
regs->eflags &= ~TF_MASK;
diff -u --recursive /extra/linux-2.0.30/include/asm-i386/segment.h linux/include/asm-i386/segment.h
--- /extra/linux-2.0.30/include/asm-i386/segment.h Sat Apr 12 10:41:37 1997
+++ linux/include/asm-i386/segment.h Sat Apr 12 10:44:58 1997
@@ -4,7 +4,8 @@
#define KERNEL_CS 0x10
#define KERNEL_DS 0x18

-#define USER_CS 0x23
+#define USER_HUGE_CS 0x23
+#define USER_CS 0x33
#define USER_DS 0x2B

#ifndef __ASSEMBLY__

Solar Designer