From 21528454f6dd18231ae20102f98aa8f51b6ec1b9 Mon Sep 17 00:00:00 2001 From: Chuck Ebbert <76306.1226@compuserve.com> Date: Fri, 23 Jun 2006 02:04:23 -0700 Subject: [PATCH] i386: let usermode execute the "enter" instruction The i386 page fault handler does not allow enough slack when checking for userspace access below the current stack pointer. This prevents use of the enter instruction by user code. Fix this by allowing enough slack for "enter $65535,$31" to execute. Problem reported by Tomasz Malesinski Tested using this program, based on the original from Tomasz: .file "ovflow.S" .version "01.01" gcc2_compiled.: .section .rodata .LC0: .string "asdf\n" .text .align 4 .globl main .type main,@function main: nest_level=0 .rept 30 enter $0,$nest_level nest_level=nest_level+1 .endr enter $65535,$30 enter $65535,$31 addl $-12,%esp pushl $.LC0 call printf addl $16,%esp .L2: .rept 32 leave .endr ret .Lfe1: .size main,.Lfe1-main .ident "GCC: (GNU) 2.95.4 20011002 (Debian prerelease)" Signed-off-by: Chuck Ebbert <76306.1226@compuserve.com> Cc: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/i386/mm/fault.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'arch/i386/mm/fault.c') diff --git a/arch/i386/mm/fault.c b/arch/i386/mm/fault.c index 7f0fcf219a2..f38085ff3c3 100644 --- a/arch/i386/mm/fault.c +++ b/arch/i386/mm/fault.c @@ -380,12 +380,12 @@ fastcall void __kprobes do_page_fault(struct pt_regs *regs, goto bad_area; if (error_code & 4) { /* - * accessing the stack below %esp is always a bug. - * The "+ 32" is there due to some instructions (like - * pusha) doing post-decrement on the stack and that - * doesn't show up until later.. + * Accessing the stack below %esp is always a bug. + * The large cushion allows instructions like enter + * and pusha to work. ("enter $65535,$31" pushes + * 32 pointers and then decrements %esp by 65535.) */ - if (address + 32 < regs->esp) + if (address + 65536 + 32 * sizeof(unsigned long) < regs->esp) goto bad_area; } if (expand_stack(vma, address)) -- cgit v1.2.3-70-g09d2 From 19964fecf25c17f865dec07ae242b1a40ea93f16 Mon Sep 17 00:00:00 2001 From: Chuck Ebbert <76306.1226@compuserve.com> Date: Fri, 23 Jun 2006 02:04:29 -0700 Subject: [PATCH] i386: fix get_segment_eip() with vm86 segments We need to check for vm86 mode first before looking at selector privilege bits. Segment limit is always base + 64k and only the low 16 bits of EIP are significant in vm86 mode. Signed-off-by: Chuck Ebbert <76306.1226@compuserve.com> Cc: Andi Kleen Cc: Zachary Amsden Cc: Rohit Seth Acked-by: Ananth N Mavinakayanahalli Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/i386/mm/fault.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'arch/i386/mm/fault.c') diff --git a/arch/i386/mm/fault.c b/arch/i386/mm/fault.c index f38085ff3c3..bd6fe96cc16 100644 --- a/arch/i386/mm/fault.c +++ b/arch/i386/mm/fault.c @@ -77,12 +77,15 @@ static inline unsigned long get_segment_eip(struct pt_regs *regs, unsigned seg = regs->xcs & 0xffff; u32 seg_ar, seg_limit, base, *desc; + /* Unlikely, but must come before segment checks. */ + if (unlikely(regs->eflags & VM_MASK)) { + base = seg << 4; + *eip_limit = base + 0xffff; + return base + (eip & 0xffff); + } + /* The standard kernel/user address space limit. */ *eip_limit = (seg & 3) ? USER_DS.seg : KERNEL_DS.seg; - - /* Unlikely, but must come before segment checks. */ - if (unlikely((regs->eflags & VM_MASK) != 0)) - return eip + (seg << 4); /* By far the most common cases. */ if (likely(seg == __USER_CS || seg == __KERNEL_CS)) -- cgit v1.2.3-70-g09d2