Loading arch/x86/include/asm/processor.h +2 −0 Original line number Original line Diff line number Diff line Loading @@ -759,6 +759,8 @@ static inline void update_debugctlmsr(unsigned long debugctlmsr) wrmsrl(MSR_IA32_DEBUGCTLMSR, debugctlmsr); wrmsrl(MSR_IA32_DEBUGCTLMSR, debugctlmsr); } } extern void set_task_blockstep(struct task_struct *task, bool on); /* /* * from system description table in BIOS. Mostly for MCA use, but * from system description table in BIOS. Mostly for MCA use, but * others may find it useful: * others may find it useful: Loading arch/x86/include/asm/uprobes.h +2 −1 Original line number Original line Diff line number Diff line Loading @@ -42,10 +42,11 @@ struct arch_uprobe { }; }; struct arch_uprobe_task { struct arch_uprobe_task { unsigned long saved_trap_nr; #ifdef CONFIG_X86_64 #ifdef CONFIG_X86_64 unsigned long saved_scratch_register; unsigned long saved_scratch_register; #endif #endif unsigned int saved_trap_nr; unsigned int saved_tf; }; }; extern int arch_uprobe_analyze_insn(struct arch_uprobe *aup, struct mm_struct *mm, unsigned long addr); extern int arch_uprobe_analyze_insn(struct arch_uprobe *aup, struct mm_struct *mm, unsigned long addr); Loading arch/x86/kernel/step.c +33 −20 Original line number Original line Diff line number Diff line Loading @@ -157,6 +157,33 @@ static int enable_single_step(struct task_struct *child) return 1; return 1; } } void set_task_blockstep(struct task_struct *task, bool on) { unsigned long debugctl; /* * Ensure irq/preemption can't change debugctl in between. * Note also that both TIF_BLOCKSTEP and debugctl should * be changed atomically wrt preemption. * FIXME: this means that set/clear TIF_BLOCKSTEP is simply * wrong if task != current, SIGKILL can wakeup the stopped * tracee and set/clear can play with the running task, this * can confuse the next __switch_to_xtra(). */ local_irq_disable(); debugctl = get_debugctlmsr(); if (on) { debugctl |= DEBUGCTLMSR_BTF; set_tsk_thread_flag(task, TIF_BLOCKSTEP); } else { debugctl &= ~DEBUGCTLMSR_BTF; clear_tsk_thread_flag(task, TIF_BLOCKSTEP); } if (task == current) update_debugctlmsr(debugctl); local_irq_enable(); } /* /* * Enable single or block step. * Enable single or block step. */ */ Loading @@ -169,19 +196,10 @@ static void enable_step(struct task_struct *child, bool block) * So no one should try to use debugger block stepping in a program * So no one should try to use debugger block stepping in a program * that uses user-mode single stepping itself. * that uses user-mode single stepping itself. */ */ if (enable_single_step(child) && block) { if (enable_single_step(child) && block) unsigned long debugctl = get_debugctlmsr(); set_task_blockstep(child, true); else if (test_tsk_thread_flag(child, TIF_BLOCKSTEP)) debugctl |= DEBUGCTLMSR_BTF; set_task_blockstep(child, false); update_debugctlmsr(debugctl); set_tsk_thread_flag(child, TIF_BLOCKSTEP); } else if (test_tsk_thread_flag(child, TIF_BLOCKSTEP)) { unsigned long debugctl = get_debugctlmsr(); debugctl &= ~DEBUGCTLMSR_BTF; update_debugctlmsr(debugctl); clear_tsk_thread_flag(child, TIF_BLOCKSTEP); } } } void user_enable_single_step(struct task_struct *child) void user_enable_single_step(struct task_struct *child) Loading @@ -199,13 +217,8 @@ void user_disable_single_step(struct task_struct *child) /* /* * Make sure block stepping (BTF) is disabled. * Make sure block stepping (BTF) is disabled. */ */ if (test_tsk_thread_flag(child, TIF_BLOCKSTEP)) { if (test_tsk_thread_flag(child, TIF_BLOCKSTEP)) unsigned long debugctl = get_debugctlmsr(); set_task_blockstep(child, false); debugctl &= ~DEBUGCTLMSR_BTF; update_debugctlmsr(debugctl); clear_tsk_thread_flag(child, TIF_BLOCKSTEP); } /* Always clear TIF_SINGLESTEP... */ /* Always clear TIF_SINGLESTEP... */ clear_tsk_thread_flag(child, TIF_SINGLESTEP); clear_tsk_thread_flag(child, TIF_SINGLESTEP); Loading arch/x86/kernel/uprobes.c +51 −1 Original line number Original line Diff line number Diff line Loading @@ -41,6 +41,9 @@ /* Adjust the return address of a call insn */ /* Adjust the return address of a call insn */ #define UPROBE_FIX_CALL 0x2 #define UPROBE_FIX_CALL 0x2 /* Instruction will modify TF, don't change it */ #define UPROBE_FIX_SETF 0x4 #define UPROBE_FIX_RIP_AX 0x8000 #define UPROBE_FIX_RIP_AX 0x8000 #define UPROBE_FIX_RIP_CX 0x4000 #define UPROBE_FIX_RIP_CX 0x4000 Loading Loading @@ -239,6 +242,10 @@ static void prepare_fixups(struct arch_uprobe *auprobe, struct insn *insn) insn_get_opcode(insn); /* should be a nop */ insn_get_opcode(insn); /* should be a nop */ switch (OPCODE1(insn)) { switch (OPCODE1(insn)) { case 0x9d: /* popf */ auprobe->fixups |= UPROBE_FIX_SETF; break; case 0xc3: /* ret/lret */ case 0xc3: /* ret/lret */ case 0xcb: case 0xcb: case 0xc2: case 0xc2: Loading Loading @@ -646,7 +653,7 @@ void arch_uprobe_abort_xol(struct arch_uprobe *auprobe, struct pt_regs *regs) * Skip these instructions as per the currently known x86 ISA. * Skip these instructions as per the currently known x86 ISA. * 0x66* { 0x90 | 0x0f 0x1f | 0x0f 0x19 | 0x87 0xc0 } * 0x66* { 0x90 | 0x0f 0x1f | 0x0f 0x19 | 0x87 0xc0 } */ */ bool arch_uprobe_skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs) static bool __skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs) { { int i; int i; Loading @@ -673,3 +680,46 @@ bool arch_uprobe_skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs) } } return false; return false; } } bool arch_uprobe_skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs) { bool ret = __skip_sstep(auprobe, regs); if (ret && (regs->flags & X86_EFLAGS_TF)) send_sig(SIGTRAP, current, 0); return ret; } void arch_uprobe_enable_step(struct arch_uprobe *auprobe) { struct task_struct *task = current; struct arch_uprobe_task *autask = &task->utask->autask; struct pt_regs *regs = task_pt_regs(task); autask->saved_tf = !!(regs->flags & X86_EFLAGS_TF); regs->flags |= X86_EFLAGS_TF; if (test_tsk_thread_flag(task, TIF_BLOCKSTEP)) set_task_blockstep(task, false); } void arch_uprobe_disable_step(struct arch_uprobe *auprobe) { struct task_struct *task = current; struct arch_uprobe_task *autask = &task->utask->autask; bool trapped = (task->utask->state == UTASK_SSTEP_TRAPPED); struct pt_regs *regs = task_pt_regs(task); /* * The state of TIF_BLOCKSTEP was not saved so we can get an extra * SIGTRAP if we do not clear TF. We need to examine the opcode to * make it right. */ if (unlikely(trapped)) { if (!autask->saved_tf) regs->flags &= ~X86_EFLAGS_TF; } else { if (autask->saved_tf) send_sig(SIGTRAP, task, 0); else if (!(auprobe->fixups & UPROBE_FIX_SETF)) regs->flags &= ~X86_EFLAGS_TF; } } include/linux/sched.h +2 −1 Original line number Original line Diff line number Diff line Loading @@ -446,7 +446,8 @@ extern int get_dumpable(struct mm_struct *mm); #define MMF_VM_HUGEPAGE 17 /* set when VM_HUGEPAGE is set on vma */ #define MMF_VM_HUGEPAGE 17 /* set when VM_HUGEPAGE is set on vma */ #define MMF_EXE_FILE_CHANGED 18 /* see prctl_set_mm_exe_file() */ #define MMF_EXE_FILE_CHANGED 18 /* see prctl_set_mm_exe_file() */ #define MMF_HAS_UPROBES 19 /* might have uprobes */ #define MMF_HAS_UPROBES 19 /* has uprobes */ #define MMF_RECALC_UPROBES 20 /* MMF_HAS_UPROBES can be wrong */ #define MMF_INIT_MASK (MMF_DUMPABLE_MASK | MMF_DUMP_FILTER_MASK) #define MMF_INIT_MASK (MMF_DUMPABLE_MASK | MMF_DUMP_FILTER_MASK) Loading Loading
arch/x86/include/asm/processor.h +2 −0 Original line number Original line Diff line number Diff line Loading @@ -759,6 +759,8 @@ static inline void update_debugctlmsr(unsigned long debugctlmsr) wrmsrl(MSR_IA32_DEBUGCTLMSR, debugctlmsr); wrmsrl(MSR_IA32_DEBUGCTLMSR, debugctlmsr); } } extern void set_task_blockstep(struct task_struct *task, bool on); /* /* * from system description table in BIOS. Mostly for MCA use, but * from system description table in BIOS. Mostly for MCA use, but * others may find it useful: * others may find it useful: Loading
arch/x86/include/asm/uprobes.h +2 −1 Original line number Original line Diff line number Diff line Loading @@ -42,10 +42,11 @@ struct arch_uprobe { }; }; struct arch_uprobe_task { struct arch_uprobe_task { unsigned long saved_trap_nr; #ifdef CONFIG_X86_64 #ifdef CONFIG_X86_64 unsigned long saved_scratch_register; unsigned long saved_scratch_register; #endif #endif unsigned int saved_trap_nr; unsigned int saved_tf; }; }; extern int arch_uprobe_analyze_insn(struct arch_uprobe *aup, struct mm_struct *mm, unsigned long addr); extern int arch_uprobe_analyze_insn(struct arch_uprobe *aup, struct mm_struct *mm, unsigned long addr); Loading
arch/x86/kernel/step.c +33 −20 Original line number Original line Diff line number Diff line Loading @@ -157,6 +157,33 @@ static int enable_single_step(struct task_struct *child) return 1; return 1; } } void set_task_blockstep(struct task_struct *task, bool on) { unsigned long debugctl; /* * Ensure irq/preemption can't change debugctl in between. * Note also that both TIF_BLOCKSTEP and debugctl should * be changed atomically wrt preemption. * FIXME: this means that set/clear TIF_BLOCKSTEP is simply * wrong if task != current, SIGKILL can wakeup the stopped * tracee and set/clear can play with the running task, this * can confuse the next __switch_to_xtra(). */ local_irq_disable(); debugctl = get_debugctlmsr(); if (on) { debugctl |= DEBUGCTLMSR_BTF; set_tsk_thread_flag(task, TIF_BLOCKSTEP); } else { debugctl &= ~DEBUGCTLMSR_BTF; clear_tsk_thread_flag(task, TIF_BLOCKSTEP); } if (task == current) update_debugctlmsr(debugctl); local_irq_enable(); } /* /* * Enable single or block step. * Enable single or block step. */ */ Loading @@ -169,19 +196,10 @@ static void enable_step(struct task_struct *child, bool block) * So no one should try to use debugger block stepping in a program * So no one should try to use debugger block stepping in a program * that uses user-mode single stepping itself. * that uses user-mode single stepping itself. */ */ if (enable_single_step(child) && block) { if (enable_single_step(child) && block) unsigned long debugctl = get_debugctlmsr(); set_task_blockstep(child, true); else if (test_tsk_thread_flag(child, TIF_BLOCKSTEP)) debugctl |= DEBUGCTLMSR_BTF; set_task_blockstep(child, false); update_debugctlmsr(debugctl); set_tsk_thread_flag(child, TIF_BLOCKSTEP); } else if (test_tsk_thread_flag(child, TIF_BLOCKSTEP)) { unsigned long debugctl = get_debugctlmsr(); debugctl &= ~DEBUGCTLMSR_BTF; update_debugctlmsr(debugctl); clear_tsk_thread_flag(child, TIF_BLOCKSTEP); } } } void user_enable_single_step(struct task_struct *child) void user_enable_single_step(struct task_struct *child) Loading @@ -199,13 +217,8 @@ void user_disable_single_step(struct task_struct *child) /* /* * Make sure block stepping (BTF) is disabled. * Make sure block stepping (BTF) is disabled. */ */ if (test_tsk_thread_flag(child, TIF_BLOCKSTEP)) { if (test_tsk_thread_flag(child, TIF_BLOCKSTEP)) unsigned long debugctl = get_debugctlmsr(); set_task_blockstep(child, false); debugctl &= ~DEBUGCTLMSR_BTF; update_debugctlmsr(debugctl); clear_tsk_thread_flag(child, TIF_BLOCKSTEP); } /* Always clear TIF_SINGLESTEP... */ /* Always clear TIF_SINGLESTEP... */ clear_tsk_thread_flag(child, TIF_SINGLESTEP); clear_tsk_thread_flag(child, TIF_SINGLESTEP); Loading
arch/x86/kernel/uprobes.c +51 −1 Original line number Original line Diff line number Diff line Loading @@ -41,6 +41,9 @@ /* Adjust the return address of a call insn */ /* Adjust the return address of a call insn */ #define UPROBE_FIX_CALL 0x2 #define UPROBE_FIX_CALL 0x2 /* Instruction will modify TF, don't change it */ #define UPROBE_FIX_SETF 0x4 #define UPROBE_FIX_RIP_AX 0x8000 #define UPROBE_FIX_RIP_AX 0x8000 #define UPROBE_FIX_RIP_CX 0x4000 #define UPROBE_FIX_RIP_CX 0x4000 Loading Loading @@ -239,6 +242,10 @@ static void prepare_fixups(struct arch_uprobe *auprobe, struct insn *insn) insn_get_opcode(insn); /* should be a nop */ insn_get_opcode(insn); /* should be a nop */ switch (OPCODE1(insn)) { switch (OPCODE1(insn)) { case 0x9d: /* popf */ auprobe->fixups |= UPROBE_FIX_SETF; break; case 0xc3: /* ret/lret */ case 0xc3: /* ret/lret */ case 0xcb: case 0xcb: case 0xc2: case 0xc2: Loading Loading @@ -646,7 +653,7 @@ void arch_uprobe_abort_xol(struct arch_uprobe *auprobe, struct pt_regs *regs) * Skip these instructions as per the currently known x86 ISA. * Skip these instructions as per the currently known x86 ISA. * 0x66* { 0x90 | 0x0f 0x1f | 0x0f 0x19 | 0x87 0xc0 } * 0x66* { 0x90 | 0x0f 0x1f | 0x0f 0x19 | 0x87 0xc0 } */ */ bool arch_uprobe_skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs) static bool __skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs) { { int i; int i; Loading @@ -673,3 +680,46 @@ bool arch_uprobe_skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs) } } return false; return false; } } bool arch_uprobe_skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs) { bool ret = __skip_sstep(auprobe, regs); if (ret && (regs->flags & X86_EFLAGS_TF)) send_sig(SIGTRAP, current, 0); return ret; } void arch_uprobe_enable_step(struct arch_uprobe *auprobe) { struct task_struct *task = current; struct arch_uprobe_task *autask = &task->utask->autask; struct pt_regs *regs = task_pt_regs(task); autask->saved_tf = !!(regs->flags & X86_EFLAGS_TF); regs->flags |= X86_EFLAGS_TF; if (test_tsk_thread_flag(task, TIF_BLOCKSTEP)) set_task_blockstep(task, false); } void arch_uprobe_disable_step(struct arch_uprobe *auprobe) { struct task_struct *task = current; struct arch_uprobe_task *autask = &task->utask->autask; bool trapped = (task->utask->state == UTASK_SSTEP_TRAPPED); struct pt_regs *regs = task_pt_regs(task); /* * The state of TIF_BLOCKSTEP was not saved so we can get an extra * SIGTRAP if we do not clear TF. We need to examine the opcode to * make it right. */ if (unlikely(trapped)) { if (!autask->saved_tf) regs->flags &= ~X86_EFLAGS_TF; } else { if (autask->saved_tf) send_sig(SIGTRAP, task, 0); else if (!(auprobe->fixups & UPROBE_FIX_SETF)) regs->flags &= ~X86_EFLAGS_TF; } }
include/linux/sched.h +2 −1 Original line number Original line Diff line number Diff line Loading @@ -446,7 +446,8 @@ extern int get_dumpable(struct mm_struct *mm); #define MMF_VM_HUGEPAGE 17 /* set when VM_HUGEPAGE is set on vma */ #define MMF_VM_HUGEPAGE 17 /* set when VM_HUGEPAGE is set on vma */ #define MMF_EXE_FILE_CHANGED 18 /* see prctl_set_mm_exe_file() */ #define MMF_EXE_FILE_CHANGED 18 /* see prctl_set_mm_exe_file() */ #define MMF_HAS_UPROBES 19 /* might have uprobes */ #define MMF_HAS_UPROBES 19 /* has uprobes */ #define MMF_RECALC_UPROBES 20 /* MMF_HAS_UPROBES can be wrong */ #define MMF_INIT_MASK (MMF_DUMPABLE_MASK | MMF_DUMP_FILTER_MASK) #define MMF_INIT_MASK (MMF_DUMPABLE_MASK | MMF_DUMP_FILTER_MASK) Loading