Loading arch/x86/oprofile/backtrace.c +47 −9 Original line number Diff line number Diff line Loading @@ -11,10 +11,12 @@ #include <linux/oprofile.h> #include <linux/sched.h> #include <linux/mm.h> #include <linux/compat.h> #include <linux/highmem.h> #include <asm/ptrace.h> #include <asm/uaccess.h> #include <asm/stacktrace.h> #include <linux/compat.h> static int backtrace_stack(void *data, char *name) { Loading @@ -36,17 +38,53 @@ static struct stacktrace_ops backtrace_ops = { .walk_stack = print_context_stack, }; /* from arch/x86/kernel/cpu/perf_event.c: */ /* * best effort, GUP based copy_from_user() that assumes IRQ or NMI context */ static unsigned long copy_from_user_nmi(void *to, const void __user *from, unsigned long n) { unsigned long offset, addr = (unsigned long)from; unsigned long size, len = 0; struct page *page; void *map; int ret; do { ret = __get_user_pages_fast(addr, 1, 0, &page); if (!ret) break; offset = addr & (PAGE_SIZE - 1); size = min(PAGE_SIZE - offset, n - len); map = kmap_atomic(page); memcpy(to, map+offset, size); kunmap_atomic(map); put_page(page); len += size; to += size; addr += size; } while (len < n); return len; } #ifdef CONFIG_COMPAT static struct stack_frame_ia32 * dump_user_backtrace_32(struct stack_frame_ia32 *head) { /* Also check accessibility of one struct frame_head beyond: */ struct stack_frame_ia32 bufhead[2]; struct stack_frame_ia32 *fp; unsigned long bytes; /* Also check accessibility of one struct frame_head beyond */ if (!access_ok(VERIFY_READ, head, sizeof(bufhead))) return NULL; if (__copy_from_user_inatomic(bufhead, head, sizeof(bufhead))) bytes = copy_from_user_nmi(bufhead, head, sizeof(bufhead)); if (bytes != sizeof(bufhead)) return NULL; fp = (struct stack_frame_ia32 *) compat_ptr(bufhead[0].next_frame); Loading Loading @@ -87,12 +125,12 @@ x86_backtrace_32(struct pt_regs * const regs, unsigned int depth) static struct stack_frame *dump_user_backtrace(struct stack_frame *head) { /* Also check accessibility of one struct frame_head beyond: */ struct stack_frame bufhead[2]; unsigned long bytes; /* Also check accessibility of one struct stack_frame beyond */ if (!access_ok(VERIFY_READ, head, sizeof(bufhead))) return NULL; if (__copy_from_user_inatomic(bufhead, head, sizeof(bufhead))) bytes = copy_from_user_nmi(bufhead, head, sizeof(bufhead)); if (bytes != sizeof(bufhead)) return NULL; oprofile_add_trace(bufhead[0].return_address); Loading arch/x86/oprofile/nmi_int.c +10 −4 Original line number Diff line number Diff line Loading @@ -112,8 +112,10 @@ static void nmi_cpu_start(void *dummy) static int nmi_start(void) { get_online_cpus(); on_each_cpu(nmi_cpu_start, NULL, 1); ctr_running = 1; /* make ctr_running visible to the nmi handler: */ smp_mb(); on_each_cpu(nmi_cpu_start, NULL, 1); put_online_cpus(); return 0; } Loading Loading @@ -504,15 +506,18 @@ static int nmi_setup(void) nmi_enabled = 0; ctr_running = 0; barrier(); /* make variables visible to the nmi handler: */ smp_mb(); err = register_die_notifier(&profile_exceptions_nb); if (err) goto fail; get_online_cpus(); register_cpu_notifier(&oprofile_cpu_nb); on_each_cpu(nmi_cpu_setup, NULL, 1); nmi_enabled = 1; /* make nmi_enabled visible to the nmi handler: */ smp_mb(); on_each_cpu(nmi_cpu_setup, NULL, 1); put_online_cpus(); return 0; Loading @@ -531,7 +536,8 @@ static void nmi_shutdown(void) nmi_enabled = 0; ctr_running = 0; put_online_cpus(); barrier(); /* make variables visible to the nmi handler: */ smp_mb(); unregister_die_notifier(&profile_exceptions_nb); msrs = &get_cpu_var(cpu_msrs); model->shutdown(msrs); Loading Loading
arch/x86/oprofile/backtrace.c +47 −9 Original line number Diff line number Diff line Loading @@ -11,10 +11,12 @@ #include <linux/oprofile.h> #include <linux/sched.h> #include <linux/mm.h> #include <linux/compat.h> #include <linux/highmem.h> #include <asm/ptrace.h> #include <asm/uaccess.h> #include <asm/stacktrace.h> #include <linux/compat.h> static int backtrace_stack(void *data, char *name) { Loading @@ -36,17 +38,53 @@ static struct stacktrace_ops backtrace_ops = { .walk_stack = print_context_stack, }; /* from arch/x86/kernel/cpu/perf_event.c: */ /* * best effort, GUP based copy_from_user() that assumes IRQ or NMI context */ static unsigned long copy_from_user_nmi(void *to, const void __user *from, unsigned long n) { unsigned long offset, addr = (unsigned long)from; unsigned long size, len = 0; struct page *page; void *map; int ret; do { ret = __get_user_pages_fast(addr, 1, 0, &page); if (!ret) break; offset = addr & (PAGE_SIZE - 1); size = min(PAGE_SIZE - offset, n - len); map = kmap_atomic(page); memcpy(to, map+offset, size); kunmap_atomic(map); put_page(page); len += size; to += size; addr += size; } while (len < n); return len; } #ifdef CONFIG_COMPAT static struct stack_frame_ia32 * dump_user_backtrace_32(struct stack_frame_ia32 *head) { /* Also check accessibility of one struct frame_head beyond: */ struct stack_frame_ia32 bufhead[2]; struct stack_frame_ia32 *fp; unsigned long bytes; /* Also check accessibility of one struct frame_head beyond */ if (!access_ok(VERIFY_READ, head, sizeof(bufhead))) return NULL; if (__copy_from_user_inatomic(bufhead, head, sizeof(bufhead))) bytes = copy_from_user_nmi(bufhead, head, sizeof(bufhead)); if (bytes != sizeof(bufhead)) return NULL; fp = (struct stack_frame_ia32 *) compat_ptr(bufhead[0].next_frame); Loading Loading @@ -87,12 +125,12 @@ x86_backtrace_32(struct pt_regs * const regs, unsigned int depth) static struct stack_frame *dump_user_backtrace(struct stack_frame *head) { /* Also check accessibility of one struct frame_head beyond: */ struct stack_frame bufhead[2]; unsigned long bytes; /* Also check accessibility of one struct stack_frame beyond */ if (!access_ok(VERIFY_READ, head, sizeof(bufhead))) return NULL; if (__copy_from_user_inatomic(bufhead, head, sizeof(bufhead))) bytes = copy_from_user_nmi(bufhead, head, sizeof(bufhead)); if (bytes != sizeof(bufhead)) return NULL; oprofile_add_trace(bufhead[0].return_address); Loading
arch/x86/oprofile/nmi_int.c +10 −4 Original line number Diff line number Diff line Loading @@ -112,8 +112,10 @@ static void nmi_cpu_start(void *dummy) static int nmi_start(void) { get_online_cpus(); on_each_cpu(nmi_cpu_start, NULL, 1); ctr_running = 1; /* make ctr_running visible to the nmi handler: */ smp_mb(); on_each_cpu(nmi_cpu_start, NULL, 1); put_online_cpus(); return 0; } Loading Loading @@ -504,15 +506,18 @@ static int nmi_setup(void) nmi_enabled = 0; ctr_running = 0; barrier(); /* make variables visible to the nmi handler: */ smp_mb(); err = register_die_notifier(&profile_exceptions_nb); if (err) goto fail; get_online_cpus(); register_cpu_notifier(&oprofile_cpu_nb); on_each_cpu(nmi_cpu_setup, NULL, 1); nmi_enabled = 1; /* make nmi_enabled visible to the nmi handler: */ smp_mb(); on_each_cpu(nmi_cpu_setup, NULL, 1); put_online_cpus(); return 0; Loading @@ -531,7 +536,8 @@ static void nmi_shutdown(void) nmi_enabled = 0; ctr_running = 0; put_online_cpus(); barrier(); /* make variables visible to the nmi handler: */ smp_mb(); unregister_die_notifier(&profile_exceptions_nb); msrs = &get_cpu_var(cpu_msrs); model->shutdown(msrs); Loading