提交 3a4664aa 编写于 作者: O Oleg Nesterov

uprobes/x86: Xol should send SIGTRAP if X86_EFLAGS_TF was set

arch_uprobe_disable_step() correctly preserves X86_EFLAGS_TF and
returns to user-mode. But this means the application gets SIGTRAP
only after the next insn.

This means that UPROBE_CLEAR_TF logic is not really right. _enable
should only record the state of X86_EFLAGS_TF, and _disable should
check it separately from UPROBE_FIX_SETF.

Remove arch_uprobe_task->restore_flags, add ->saved_tf instead, and
change enable/disable accordingly. This assumes that the probed insn
was not trapped, see the next patch.

arch_uprobe_skip_sstep() logic has the same problem, change it to
check X86_EFLAGS_TF and send SIGTRAP as well. We will cleanup this
all after we fold enable/disable_step into pre/post_hol hooks.

Note: send_sig(SIGTRAP) is not actually right, we need send_sigtrap().
But this needs more changes, handle_swbp() does the same and this is
equally wrong.
Signed-off-by: NOleg Nesterov <oleg@redhat.com>
Acked-by: NSrikar Dronamraju <srikar@linux.vnet.ibm.com>
上级 9bd1190a
...@@ -46,8 +46,7 @@ struct arch_uprobe_task { ...@@ -46,8 +46,7 @@ struct arch_uprobe_task {
#ifdef CONFIG_X86_64 #ifdef CONFIG_X86_64
unsigned long saved_scratch_register; unsigned long saved_scratch_register;
#endif #endif
#define UPROBE_CLEAR_TF (1 << 0) unsigned int saved_tf;
unsigned int restore_flags;
}; };
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);
......
...@@ -653,7 +653,7 @@ void arch_uprobe_abort_xol(struct arch_uprobe *auprobe, struct pt_regs *regs) ...@@ -653,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;
...@@ -681,16 +681,21 @@ bool arch_uprobe_skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs) ...@@ -681,16 +681,21 @@ 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) void arch_uprobe_enable_step(struct arch_uprobe *auprobe)
{ {
struct task_struct *task = current; struct task_struct *task = current;
struct arch_uprobe_task *autask = &task->utask->autask; struct arch_uprobe_task *autask = &task->utask->autask;
struct pt_regs *regs = task_pt_regs(task); struct pt_regs *regs = task_pt_regs(task);
autask->restore_flags = 0; autask->saved_tf = !!(regs->flags & X86_EFLAGS_TF);
if (!(regs->flags & X86_EFLAGS_TF) &&
!(auprobe->fixups & UPROBE_FIX_SETF))
autask->restore_flags |= UPROBE_CLEAR_TF;
regs->flags |= X86_EFLAGS_TF; regs->flags |= X86_EFLAGS_TF;
if (test_tsk_thread_flag(task, TIF_BLOCKSTEP)) if (test_tsk_thread_flag(task, TIF_BLOCKSTEP))
...@@ -707,6 +712,8 @@ void arch_uprobe_disable_step(struct arch_uprobe *auprobe) ...@@ -707,6 +712,8 @@ void arch_uprobe_disable_step(struct arch_uprobe *auprobe)
* SIGTRAP if we do not clear TF. We need to examine the opcode to * SIGTRAP if we do not clear TF. We need to examine the opcode to
* make it right. * make it right.
*/ */
if (autask->restore_flags & UPROBE_CLEAR_TF) if (autask->saved_tf)
send_sig(SIGTRAP, task, 0);
else if (!(auprobe->fixups & UPROBE_FIX_SETF))
regs->flags &= ~X86_EFLAGS_TF; regs->flags &= ~X86_EFLAGS_TF;
} }
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册