x86: i386-show-unhandled-signals-v3
authorMasoud Asgharifard Sharbiani <masouds@google.com>
Sun, 22 Jul 2007 09:12:28 +0000 (11:12 +0200)
committerLinus Torvalds <torvalds@woody.linux-foundation.org>
Sun, 22 Jul 2007 18:03:37 +0000 (11:03 -0700)
This patch makes the i386 behave the same way that x86_64 does when a
segfault happens.  A line gets printed to the kernel log so that tools
that need to check for failures can behave more uniformly between
debug.show_unhandled_signals sysctl variable to 0 (or by doing echo 0 >
/proc/sys/debug/exception-trace)

Also, all of the lines being printed are now using printk_ratelimit() to
deny the ability of DoS from a local user with a program like the
following:

main()
{
       while (1)
               if (!fork()) *(int *)0 = 0;
}

This new revision also includes the fix that Andrew did which got rid of
new sysctl that was added to the system in earlier versions of this.
Also, 'show-unhandled-signals' sysctl has been renamed back to the old
'exception-trace' to avoid breakage of people's scripts.

AK: Enabling by default for i386 will be likely controversal, but let's see what happens
AK: Really folks, before complaining just fix your segfaults
AK: I bet this will find a lot of silent issues

Signed-off-by: Masoud Sharbiani <masouds@google.com>
Signed-off-by: Andi Kleen <ak@suse.de>
[ Personally, I've found the complaints useful on x86-64, so I'm all for
  this. That said, I wonder if we could do it more prettily..   -Linus ]
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
arch/i386/kernel/signal.c
arch/i386/kernel/traps.c
arch/i386/mm/fault.c
arch/x86_64/kernel/signal.c
arch/x86_64/kernel/traps.c
arch/x86_64/mm/fault.c
arch/x86_64/mm/init.c
include/asm-x86_64/proto.h
include/linux/signal.h
kernel/signal.c
kernel/sysctl.c

index d574e38f0f774e67896ad8cfbd8420faca9f9ec9..f5dd85656c1890eb93f8d25fc68fb2d97132e917 100644 (file)
@@ -199,6 +199,13 @@ asmlinkage int sys_sigreturn(unsigned long __unused)
        return eax;
 
 badframe:
+       if (show_unhandled_signals && printk_ratelimit())
+               printk("%s%s[%d] bad frame in sigreturn frame:%p eip:%lx"
+                      " esp:%lx oeax:%lx\n",
+                   current->pid > 1 ? KERN_INFO : KERN_EMERG,
+                   current->comm, current->pid, frame, regs->eip,
+                   regs->esp, regs->orig_eax);
+
        force_sig(SIGSEGV, current);
        return 0;
 }      
index 57772a18c39470061cdfcec35467cacb54948825..438949da3b634d63e40503da9baba34fe00e130b 100644 (file)
@@ -618,6 +618,13 @@ fastcall void __kprobes do_general_protection(struct pt_regs * regs,
 
        current->thread.error_code = error_code;
        current->thread.trap_no = 13;
+       if (show_unhandled_signals && unhandled_signal(current, SIGSEGV) &&
+           printk_ratelimit())
+               printk(KERN_INFO
+                   "%s[%d] general protection eip:%lx esp:%lx error:%lx\n",
+                   current->comm, current->pid,
+                   regs->eip, regs->esp, error_code);
+
        force_sig(SIGSEGV, current);
        return;
 
index e92a10124935c006a22a55775b0aee755b2b08c3..01ffdd4964f08e9bec86c5ae759da9f5cbe8270a 100644 (file)
@@ -283,6 +283,8 @@ static inline int vmalloc_fault(unsigned long address)
        return 0;
 }
 
+int show_unhandled_signals = 1;
+
 /*
  * This routine handles page faults.  It determines the address,
  * and the problem, and then passes it off to one of the appropriate
@@ -469,6 +471,14 @@ bad_area_nosemaphore:
                if (is_prefetch(regs, address, error_code))
                        return;
 
+               if (show_unhandled_signals && unhandled_signal(tsk, SIGSEGV) &&
+                   printk_ratelimit()) {
+                       printk("%s%s[%d]: segfault at %08lx eip %08lx "
+                           "esp %08lx error %lx\n",
+                           tsk->pid > 1 ? KERN_INFO : KERN_EMERG,
+                           tsk->comm, tsk->pid, address, regs->eip,
+                           regs->esp, error_code);
+               }
                tsk->thread.cr2 = address;
                /* Kernel addresses are always protection faults */
                tsk->thread.error_code = error_code | (address >= TASK_SIZE);
index 4886afcd628746c2f78b0516754de3e47eadad50..739175b01e06ee9553760729c5b8e6dbd6bf89cb 100644 (file)
@@ -487,7 +487,7 @@ do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags)
 void signal_fault(struct pt_regs *regs, void __user *frame, char *where)
 { 
        struct task_struct *me = current; 
-       if (exception_trace)
+       if (show_unhandled_signals && printk_ratelimit())
                printk("%s[%d] bad frame in %s frame:%p rip:%lx rsp:%lx orax:%lx\n",
               me->comm,me->pid,where,frame,regs->rip,regs->rsp,regs->orig_rax); 
 
index 8713ad4a4db14ca350a00a5eee55a9cc365a7373..03888420775d03320f0cea3c40989e100fea3e7c 100644 (file)
@@ -584,7 +584,8 @@ static void __kprobes do_trap(int trapnr, int signr, char *str,
                tsk->thread.error_code = error_code;
                tsk->thread.trap_no = trapnr;
 
-               if (exception_trace && unhandled_signal(tsk, signr))
+               if (show_unhandled_signals && unhandled_signal(tsk, signr) &&
+                   printk_ratelimit())
                        printk(KERN_INFO
                               "%s[%d] trap %s rip:%lx rsp:%lx error:%lx\n",
                               tsk->comm, tsk->pid, str,
@@ -688,7 +689,8 @@ asmlinkage void __kprobes do_general_protection(struct pt_regs * regs,
                tsk->thread.error_code = error_code;
                tsk->thread.trap_no = 13;
 
-               if (exception_trace && unhandled_signal(tsk, SIGSEGV))
+               if (show_unhandled_signals && unhandled_signal(tsk, SIGSEGV) &&
+                   printk_ratelimit())
                        printk(KERN_INFO
                       "%s[%d] general protection rip:%lx rsp:%lx error:%lx\n",
                               tsk->comm, tsk->pid,
index 2074bddd4f04eea21a6dd9d6a8b848bf95a22be2..5e9ac70c135ed491c56b7af9500f4e02b677b346 100644 (file)
@@ -221,16 +221,6 @@ static int is_errata93(struct pt_regs *regs, unsigned long address)
        return 0;
 } 
 
-int unhandled_signal(struct task_struct *tsk, int sig)
-{
-       if (is_init(tsk))
-               return 1;
-       if (tsk->ptrace & PT_PTRACED)
-               return 0;
-       return (tsk->sighand->action[sig-1].sa.sa_handler == SIG_IGN) ||
-               (tsk->sighand->action[sig-1].sa.sa_handler == SIG_DFL);
-}
-
 static noinline void pgtable_bad(unsigned long address, struct pt_regs *regs,
                                 unsigned long error_code)
 {
@@ -302,7 +292,7 @@ static int vmalloc_fault(unsigned long address)
 }
 
 static int page_fault_trace;
-int exception_trace = 1;
+int show_unhandled_signals = 1;
 
 /*
  * This routine handles page faults.  It determines the address,
@@ -494,7 +484,8 @@ bad_area_nosemaphore:
                    (address >> 32))
                        return;
 
-               if (exception_trace && unhandled_signal(tsk, SIGSEGV)) {
+               if (show_unhandled_signals && unhandled_signal(tsk, SIGSEGV) &&
+                   printk_ratelimit()) {
                        printk(
                       "%s%s[%d]: segfault at %016lx rip %016lx rsp %016lx error %lx\n",
                                        tsk->pid > 1 ? KERN_INFO : KERN_EMERG,
index 381c2ecd407e3b08137b2f1d7cb4ac6afa1d62ce..88678e82e23da984a8f554ef1de1677b474b0cbe 100644 (file)
@@ -697,39 +697,6 @@ int kern_addr_valid(unsigned long addr)
        return pfn_valid(pte_pfn(*pte));
 }
 
-#ifdef CONFIG_SYSCTL
-#include <linux/sysctl.h>
-
-static ctl_table debug_table2[] = {
-       {
-               .ctl_name       = 99,
-               .procname       = "exception-trace",
-               .data           = &exception_trace,
-               .maxlen         = sizeof(int),
-               .mode           = 0644,
-               .proc_handler   = proc_dointvec
-       },
-       {}
-}; 
-
-static ctl_table debug_root_table2[] = { 
-       {
-               .ctl_name = CTL_DEBUG,
-               .procname = "debug",
-               .mode = 0555,
-               .child = debug_table2
-       },
-       {}
-}; 
-
-static __init int x8664_sysctl_init(void)
-{ 
-       register_sysctl_table(debug_root_table2);
-       return 0;
-}
-__initcall(x8664_sysctl_init);
-#endif
-
 /* A pseudo VMA to allow ptrace access for the vsyscall page.  This only
    covers the 64bit vsyscall page now. 32bit has a real VMA now and does
    not need special handling anymore. */
index d6e3225549c0a820bcefa529e4b39739644fbfb9..31f20ad65876b25f588e6c2e7e693fff23eb19b0 100644 (file)
@@ -75,8 +75,6 @@ extern void setup_node_bootmem(int nodeid, unsigned long start, unsigned long en
 extern void early_quirks(void);
 extern void check_efer(void);
 
-extern int unhandled_signal(struct task_struct *tsk, int sig);
-
 extern void select_idle_routine(const struct cpuinfo_x86 *c);
 
 extern unsigned long table_start, table_end;
index ea91abe740da0b76810b19a522b9d814f0e8aa6e..0ae338866240dee807f7f35a5f8280ebe1aa15b2 100644 (file)
@@ -237,12 +237,15 @@ extern int group_send_sig_info(int sig, struct siginfo *info, struct task_struct
 extern int __group_send_sig_info(int, struct siginfo *, struct task_struct *);
 extern long do_sigpending(void __user *, unsigned long);
 extern int sigprocmask(int, sigset_t *, sigset_t *);
+extern int show_unhandled_signals;
 
 struct pt_regs;
 extern int get_signal_to_deliver(siginfo_t *info, struct k_sigaction *return_ka, struct pt_regs *regs, void *cookie);
 
 extern struct kmem_cache *sighand_cachep;
 
+int unhandled_signal(struct task_struct *tsk, int sig);
+
 /*
  * In POSIX a signal is sent either to a specific thread (Linux task)
  * or to the process as a whole (Linux thread group).  How the signal
index 39d122753bac93eb7cfa62d0f2e2e451a4908dd5..ef8156a6aad519014c030f62e856302dacf045e7 100644 (file)
@@ -255,6 +255,16 @@ flush_signal_handlers(struct task_struct *t, int force_default)
        }
 }
 
+int unhandled_signal(struct task_struct *tsk, int sig)
+{
+       if (is_init(tsk))
+               return 1;
+       if (tsk->ptrace & PT_PTRACED)
+               return 0;
+       return (tsk->sighand->action[sig-1].sa.sa_handler == SIG_IGN) ||
+               (tsk->sighand->action[sig-1].sa.sa_handler == SIG_DFL);
+}
+
 
 /* Notify the system that a driver wants to block all signals for this
  * process, and wants to be notified if any signals at all were to be
index 222299844ad1b5a495b5796f1898f95174157632..ddebf3f2affe937d8a9ccb694de85dc9d567f1fb 100644 (file)
@@ -1203,6 +1203,16 @@ static ctl_table fs_table[] = {
 };
 
 static ctl_table debug_table[] = {
+#ifdef CONFIG_X86
+       {
+               .ctl_name       = CTL_UNNUMBERED,
+               .procname       = "exception-trace",
+               .data           = &show_unhandled_signals,
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec
+       },
+#endif
        { .ctl_name = 0 }
 };