From: Josh Poimboeuf <jpoimboe@xxxxxxxxxx> get_segment_base() will be used by the unwind_user code, so make it global and rename it to segment_base_address() so it doesn't conflict with a KVM function of the same name. As the function is no longer specific to perf, move it to ptrace.c as that seems to be a better location for a generic function like this. Also add a lockdep_assert_irqs_disabled() to make sure it's always called with interrupts disabled. Signed-off-by: Josh Poimboeuf <jpoimboe@xxxxxxxxxx> Signed-off-by: Steven Rostedt (Google) <rostedt@xxxxxxxxxxx> --- arch/x86/events/core.c | 44 ++++------------------------------- arch/x86/include/asm/ptrace.h | 2 ++ arch/x86/kernel/ptrace.c | 38 ++++++++++++++++++++++++++++++ 3 files changed, 45 insertions(+), 39 deletions(-) diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c index 7610f26dfbd9..2f2ec84f2a14 100644 --- a/arch/x86/events/core.c +++ b/arch/x86/events/core.c @@ -43,6 +43,7 @@ #include <asm/ldt.h> #include <asm/unwind.h> #include <asm/uprobes.h> +#include <asm/ptrace.h> #include <asm/ibt.h> #include "perf_event.h" @@ -2808,41 +2809,6 @@ valid_user_frame(const void __user *fp, unsigned long size) return __access_ok(fp, size); } -static unsigned long get_segment_base(unsigned int segment) -{ - struct desc_struct *desc; - unsigned int idx = segment >> 3; - - if ((segment & SEGMENT_TI_MASK) == SEGMENT_LDT) { -#ifdef CONFIG_MODIFY_LDT_SYSCALL - struct ldt_struct *ldt; - - /* - * If we're not in a valid context with a real (not just lazy) - * user mm, then don't even try. - */ - if (!nmi_uaccess_okay()) - return 0; - - /* IRQs are off, so this synchronizes with smp_store_release */ - ldt = smp_load_acquire(¤t->mm->context.ldt); - if (!ldt || idx >= ldt->nr_entries) - return 0; - - desc = &ldt->entries[idx]; -#else - return 0; -#endif - } else { - if (idx >= GDT_ENTRIES) - return 0; - - desc = raw_cpu_ptr(gdt_page.gdt) + idx; - } - - return get_desc_base(desc); -} - #ifdef CONFIG_UPROBES /* * Heuristic-based check if uprobe is installed at the function entry. @@ -2899,8 +2865,8 @@ perf_callchain_user32(struct pt_regs *regs, struct perf_callchain_entry_ctx *ent if (user_64bit_mode(regs)) return 0; - cs_base = get_segment_base(regs->cs); - ss_base = get_segment_base(regs->ss); + cs_base = segment_base_address(regs->cs); + ss_base = segment_base_address(regs->ss); fp = compat_ptr(ss_base + regs->bp); pagefault_disable(); @@ -3019,11 +2985,11 @@ static unsigned long code_segment_base(struct pt_regs *regs) return 0x10 * regs->cs; if (user_mode(regs) && regs->cs != __USER_CS) - return get_segment_base(regs->cs); + return segment_base_address(regs->cs); #else if (user_mode(regs) && !user_64bit_mode(regs) && regs->cs != __USER32_CS) - return get_segment_base(regs->cs); + return segment_base_address(regs->cs); #endif return 0; } diff --git a/arch/x86/include/asm/ptrace.h b/arch/x86/include/asm/ptrace.h index 50f75467f73d..59357ec98e52 100644 --- a/arch/x86/include/asm/ptrace.h +++ b/arch/x86/include/asm/ptrace.h @@ -314,6 +314,8 @@ static __always_inline bool regs_irqs_disabled(struct pt_regs *regs) return !(regs->flags & X86_EFLAGS_IF); } +unsigned long segment_base_address(unsigned int segment); + /* Query offset/name of register from its name/offset */ extern int regs_query_register_offset(const char *name); extern const char *regs_query_register_name(unsigned int offset); diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c index 095f04bdabdc..81353a09701b 100644 --- a/arch/x86/kernel/ptrace.c +++ b/arch/x86/kernel/ptrace.c @@ -41,6 +41,7 @@ #include <asm/syscall.h> #include <asm/fsgsbase.h> #include <asm/io_bitmap.h> +#include <asm/mmu_context.h> #include "tls.h" @@ -339,6 +340,43 @@ static int set_segment_reg(struct task_struct *task, #endif /* CONFIG_X86_32 */ +unsigned long segment_base_address(unsigned int segment) +{ + struct desc_struct *desc; + unsigned int idx = segment >> 3; + + lockdep_assert_irqs_disabled(); + + if ((segment & SEGMENT_TI_MASK) == SEGMENT_LDT) { +#ifdef CONFIG_MODIFY_LDT_SYSCALL + struct ldt_struct *ldt; + + /* + * If we're not in a valid context with a real (not just lazy) + * user mm, then don't even try. + */ + if (!nmi_uaccess_okay()) + return 0; + + /* IRQs are off, so this synchronizes with smp_store_release */ + ldt = smp_load_acquire(¤t->mm->context.ldt); + if (!ldt || idx >= ldt->nr_entries) + return 0; + + desc = &ldt->entries[idx]; +#else + return 0; +#endif + } else { + if (idx >= GDT_ENTRIES) + return 0; + + desc = raw_cpu_ptr(gdt_page.gdt) + idx; + } + + return get_desc_base(desc); +} + static unsigned long get_flags(struct task_struct *task) { unsigned long retval = task_pt_regs(task)->flags; -- 2.47.2