[patch 3/3]: fix BAD_SYSCALL_EXIT lockup

From: Stas Sergeev
Date: Tue Apr 12 2005 - 20:37:29 EST


Hello.

CONFIG_TRAP_BAD_SYSCALL_EXITS forgets to do
GET_THREAD_INFO(%ebp) before accessing the
TI_preempt_count(%ebp). This leads to an
accesses to the random addresses and kills
the machine. Also "int $3" does nothing good
by itself (it would just Oops AFAICS). And
it is misplaced, too. Obviously it never worked.

The attached patch moves the check to the
right place (to the syscall_exit path) and
replaces the "int $3" by the call to the
helper function that only prints some debug
info and doesn't crash the system.
This fully solves the reported problem.

Signed-off-by: Stas Sergeev <stsp@xxxxxxxx>

--- linux/arch/i386/kernel/entry.S 2005-04-12 09:47:38.000000000 +0400
+++ linux/arch/i386/kernel/entry.S 2005-04-12 11:51:49.000000000 +0400
@@ -253,24 +253,15 @@
cli # make sure we don't miss an interrupt
# setting need_resched or sigpending
# between sampling and the iret
+#ifdef CONFIG_TRAP_BAD_SYSCALL_EXITS
+ movl %esp, %eax # pt_regs pointer
+ call sys_call_exit
+#endif
movl TI_flags(%ebp), %ecx
testw $_TIF_ALLWORK_MASK, %cx # current->work
jne syscall_exit_work

restore_all:
-#ifdef CONFIG_TRAP_BAD_SYSCALL_EXITS
- movl EFLAGS(%esp), %eax # mix EFLAGS and CS
- movb CS(%esp), %al
- testl $(VM_MASK | 3), %eax
- jz resume_kernelX # returning to kernel or vm86-space
-
- cmpl $0,TI_preempt_count(%ebp) # non-zero preempt_count ?
- jz resume_kernelX
-
- int $3
-
-resume_kernelX:
-#endif
movl EFLAGS(%esp), %eax # mix EFLAGS, SS and CS
movb OLDSS(%esp), %ah
movb CS(%esp), %al
--- linux/arch/i386/kernel/kgdb_stub.c 2005-04-12 09:47:38.000000000 +0400
+++ linux/arch/i386/kernel/kgdb_stub.c 2005-04-12 13:23:57.000000000 +0400
@@ -2135,18 +2135,16 @@
#endif
#undef regs
#ifdef CONFIG_TRAP_BAD_SYSCALL_EXITS
-asmlinkage void
-bad_sys_call_exit(int stuff)
+fastcall void sys_call_exit(struct pt_regs *regs)
{
- struct pt_regs *regs = (struct pt_regs *) &stuff;
- printk("Sys call %d return with %x preempt_count\n",
- (int) regs->orig_eax, preempt_count());
+ if (preempt_count())
+ printk("Sys call %d return with %x preempt_count\n",
+ (int) regs->orig_eax, preempt_count());
}
#endif
#ifdef CONFIG_STACK_OVERFLOW_TEST
#include <asm/kgdb.h>
-asmlinkage void
-stack_overflow(void)
+fastcall void stack_overflow(void)
{
#ifdef BREAKPOINT
BREAKPOINT;