lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <1343735548-18101-2-git-send-email-bigeasy@linutronix.de>
Date:	Tue, 31 Jul 2012 13:52:28 +0200
From:	Sebastian Andrzej Siewior <bigeasy@...utronix.de>
To:	linux-kernel@...r.kernel.org
Cc:	oleg@...hat.com, ananth@...ibm.com, a.p.zijlstra@...llo.nl,
	mingo@...hat.com, srikar@...ux.vnet.ibm.com, roland@...k.frob.com,
	Sebastian Andrzej Siewior <bigeasy@...utronix.de>
Subject: [PATCH 2/2] x86/uprobes: implement x86 specific arch_uprobe_*_step

The arch specific implementation enables single stepping directly by
setting the trap flag. "Single-Step on branches" is always disabled
since only one opcode has to be executed.

The disable call removes the trap flag unless it was there before. It
does not touch the flags register if the executed instruction was
"popf". It does not take into account various prefixes like "lock popf"
or "repz popf".
SIGTRAP is sent to the process in case it was traced so the debugger
knows once we advanced by one opcode. This isn't done in case we have to
restore the BTF flag. In case the BTF flag is set, we should look at the
opcode and send SIGTRAP depending on the jump/flag status. For now we
wait for the next exception/jump to be taken.

Signed-off-by: Sebastian Andrzej Siewior <bigeasy@...utronix.de>
---
 arch/x86/include/asm/uprobes.h |    3 ++
 arch/x86/kernel/uprobes.c      |   60 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 63 insertions(+)

diff --git a/arch/x86/include/asm/uprobes.h b/arch/x86/include/asm/uprobes.h
index f3971bb..47f4cf1 100644
--- a/arch/x86/include/asm/uprobes.h
+++ b/arch/x86/include/asm/uprobes.h
@@ -46,6 +46,9 @@ struct arch_uprobe_task {
 #ifdef CONFIG_X86_64
 	unsigned long			saved_scratch_register;
 #endif
+#define UPROBE_CLEAR_TF			(1 << 0)
+#define UPROBE_SET_BTF			(1 << 1)
+	unsigned int			restore_flags;
 };
 
 extern int  arch_uprobe_analyze_insn(struct arch_uprobe *aup, struct mm_struct *mm, unsigned long addr);
diff --git a/arch/x86/kernel/uprobes.c b/arch/x86/kernel/uprobes.c
index 36fd420..6eec3e4 100644
--- a/arch/x86/kernel/uprobes.c
+++ b/arch/x86/kernel/uprobes.c
@@ -673,3 +673,63 @@ bool arch_uprobe_skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs)
 	}
 	return false;
 }
+
+static int insn_is_popf(const u8 *insn)
+{
+	/* popf */
+	if (insn[0] == 0x9d)
+		return 1;
+	return 0;
+}
+
+void arch_uprobe_enable_step(struct task_struct *child,
+		struct arch_uprobe *auprobe)
+{
+	struct uprobe_task	*utask		= child->utask;
+	struct arch_uprobe_task	*autask		= &utask->autask;
+	struct pt_regs		*regs		= task_pt_regs(child);
+	unsigned long		debugctl;
+
+	autask->restore_flags = 0;
+	if (!(regs->flags & X86_EFLAGS_TF) &&
+			!insn_is_popf(auprobe->insn)) {
+		autask->restore_flags |= UPROBE_CLEAR_TF;
+
+		debugctl = get_debugctlmsr();
+		if (debugctl & DEBUGCTLMSR_BTF) {
+			autask->restore_flags |= UPROBE_SET_BTF;
+			debugctl &= ~DEBUGCTLMSR_BTF;
+			update_debugctlmsr(debugctl);
+		}
+	}
+	regs->flags |= X86_EFLAGS_TF;
+}
+
+void arch_uprobe_disable_step(struct task_struct *child,
+		struct arch_uprobe *auprobe)
+{
+	struct uprobe_task *utask	= child->utask;
+	struct arch_uprobe_task	*autask		= &utask->autask;
+	struct pt_regs *regs		= task_pt_regs(child);
+
+	/*
+	 * Disable the single step flag if it was set by us. Notify the debugger
+	 * via SIGTRAP in case it was already there so it learns that we
+	 * advanced by an opcode unless the debugger is waiting for the next
+	 * jump to be taken. This logic gets it wrong if the uprobe was set
+	 * on jump instruction that would raise an exception.
+	 */
+	if (autask->restore_flags & UPROBE_CLEAR_TF) {
+		regs->flags &= ~X86_EFLAGS_TF;
+	} else {
+		if (autask->restore_flags & UPROBE_SET_BTF) {
+			unsigned long	debugctl;
+
+			debugctl = get_debugctlmsr();
+			debugctl |= DEBUGCTLMSR_BTF;
+			update_debugctlmsr(debugctl);
+		} else {
+			send_sig(SIGTRAP, current, 0);
+		}
+	}
+}
-- 
1.7.10.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ