From: Oleg Nesterov <oleg@redhat.com>
To: Ingo Molnar <mingo@elte.hu>,
Srikar Dronamraju <srikar@linux.vnet.ibm.com>
Cc: Ananth N Mavinakayanahalli <ananth@in.ibm.com>,
Anton Arapov <aarapov@redhat.com>,
David Long <dave.long@linaro.org>,
Denys Vlasenko <dvlasenk@redhat.com>,
"Frank Ch. Eigler" <fche@redhat.com>,
Jim Keniston <jkenisto@us.ibm.com>,
Jonathan Lebon <jlebon@redhat.com>,
Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>,
linux-kernel@vger.kernel.org
Subject: [RFC PATCH 4/6] uprobes/x86: Emulate rip-relative call's
Date: Sun, 6 Apr 2014 22:16:28 +0200 [thread overview]
Message-ID: <20140406201628.GA507@redhat.com> (raw)
In-Reply-To: <20140406201524.GA32694@redhat.com>
0xe8. Anything else?
Emulating of rip-relative call is trivial, we only need to additionally
push the ret-address. If this fails, we execute this instruction out of
line and this should trigger the trap, the probed application should die
or the same insn will be restarted if a signal handler expands the stack.
We do not even need ->post_xol() for this case.
But there is a corner (and almost theoretical) case: another thread can
expand the stack right before we execute this insn out of line. In this
case it hit the same problem we are trying to solve. So we simply turn
the probed insn into "call 1f; 1:" and add ->post_xol() which restores
->sp and restarts.
Many thanks to Jonathan who finally found the standalone reproducer,
otherwise I would never resolve the "random SIGSEGV's under systemtap"
bug-report. Now that the problem is clear we can write the simplified
test-case:
void probe_func(void), callee(void);
int failed = 1;
asm (
".text\n"
".align 4096\n"
".globl probe_func\n"
"probe_func:\n"
"call callee\n"
"ret"
);
/*
* This assumes that:
*
* - &probe_func = 0x401000 + a_bit, aligned = 0x402000
*
* - xol_vma->vm_start = TASK_SIZE_MAX - PAGE_SIZE = 0x7fffffffe000
* as xol_add_vma() asks; the 1st slot = 0x7fffffffe080
*
* so we can target the non-canonical address from xol_vma using
* the simple math below, 100 * 4096 is just the random offset
*/
asm (".org . + 0x800000000000 - 0x7fffffffe080 - 5 - 1 + 100 * 4096\n");
void callee(void)
{
failed = 0;
}
int main(void)
{
probe_func();
return failed;
}
It SIGSEGV's if you probe "probe_func" (although it's not very reliable,
randomize_va_space/etc can change the placement of xol area).
Reported-by: Jonathan Lebon <jlebon@redhat.com>
Signed-off-by: Oleg Nesterov <oleg@redhat.com>
---
arch/x86/include/asm/uprobes.h | 1 +
arch/x86/kernel/uprobes.c | 69 ++++++++++++++++++++++++++++++++++------
2 files changed, 60 insertions(+), 10 deletions(-)
diff --git a/arch/x86/include/asm/uprobes.h b/arch/x86/include/asm/uprobes.h
index cca62c5..9528117 100644
--- a/arch/x86/include/asm/uprobes.h
+++ b/arch/x86/include/asm/uprobes.h
@@ -51,6 +51,7 @@ struct arch_uprobe {
struct {
s32 disp;
u8 ilen;
+ u8 opc1;
} ttt;
};
};
diff --git a/arch/x86/kernel/uprobes.c b/arch/x86/kernel/uprobes.c
index 3bcc121..9283024 100644
--- a/arch/x86/kernel/uprobes.c
+++ b/arch/x86/kernel/uprobes.c
@@ -461,33 +461,85 @@ static struct uprobe_xol_ops default_xol_ops = {
.post_xol = default_post_xol_op,
};
+static bool ttt_is_call(struct arch_uprobe *auprobe)
+{
+ return auprobe->ttt.opc1 == 0xe8;
+}
+
static bool ttt_emulate_op(struct arch_uprobe *auprobe, struct pt_regs *regs)
{
- regs->ip += auprobe->ttt.ilen + auprobe->ttt.disp;
+ unsigned long new_ip = regs->ip += auprobe->ttt.ilen;
+
+ if (ttt_is_call(auprobe)) {
+ unsigned long new_sp = regs->sp - sizeof_long();
+ if (copy_to_user((void __user *)new_sp, &new_ip, sizeof_long()))
+ return false;
+ regs->sp = new_sp;
+ }
+
+ regs->ip = new_ip + auprobe->ttt.disp;
return true;
}
+static int ttt_post_xol_op(struct arch_uprobe *auprobe, struct pt_regs *regs)
+{
+ BUG_ON(!ttt_is_call(auprobe));
+ /*
+ * We can only get here if ttt_emulate_op() failed to push the return
+ * address _and_ another thread expanded our stack before the (mangled)
+ * "call" insn was executed out-of-line. Just restore ->sp and restart.
+ * We could also restore ->ip and try to call ttt_emulate_op() again.
+ */
+ regs->sp += sizeof_long();
+ return -ERESTART;
+}
+
+static void ttt_clear_displacement(struct arch_uprobe *auprobe, struct insn *insn)
+{
+ /*
+ * Turn this insn into "call 1f; 1:", this is what we will execute
+ * out-of-line if ->emulate() fails.
+ *
+ * In the likely case this will lead to arch_uprobe_abort_xol(), but
+ * see the comment in ->emulate(). So we need to ensure that the new
+ * ->ip can't fall into non-canonical area and trigger #GP.
+ *
+ * We could turn it into (say) "pushf", but then we would need to
+ * divorce ->insn[] and ->ixol[]. We need to preserve the 1st byte
+ * of ->insn[] for set_orig_insn().
+ */
+ memset(auprobe->insn + insn_offset_displacement(insn),
+ 0, insn->moffset1.nbytes);
+}
+
static struct uprobe_xol_ops ttt_xol_ops = {
.emulate = ttt_emulate_op,
+ .post_xol = ttt_post_xol_op,
};
static int ttt_setup_xol_ops(struct arch_uprobe *auprobe, struct insn *insn)
{
+ u8 opc1 = OPCODE1(insn);
+
+ /* has the side-effect of processing the entire instruction */
+ insn_get_length(insn);
+ if (WARN_ON_ONCE(!insn_complete(insn)))
+ return -ENOEXEC;
- switch (OPCODE1(insn)) {
+ switch (opc1) {
case 0xeb: /* jmp 8 */
case 0xe9: /* jmp 32 */
case 0x90: /* prefix* + nop; same as jmp with .disp = 0 */
break;
+
+ case 0xe8: /* call relative */
+ ttt_clear_displacement(auprobe, insn);
+ auprobe->ttt.opc1 = opc1;
+ break;
default:
return -ENOSYS;
}
- /* has the side-effect of processing the entire instruction */
- insn_get_length(insn);
- if (WARN_ON_ONCE(!insn_complete(insn)))
- return -ENOEXEC;
-
auprobe->ttt.ilen = insn->length;
auprobe->ttt.disp = insn->moffset1.value;
/* so far we assume that it fits into ->moffset1 */
@@ -534,9 +586,6 @@ int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe, struct mm_struct *mm,
case 0xca:
fix_ip = false;
break;
- case 0xe8: /* call relative - Fix return addr */
- fix_call = true;
- break;
case 0x9a: /* call absolute - Fix return addr, not ip */
fix_call = true;
fix_ip = false;
--
1.5.5.1
next prev parent reply other threads:[~2014-04-06 20:16 UTC|newest]
Thread overview: 79+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-04-04 18:50 [PATCH v2 0/9] uprobes/x86: preparations to fix the reprel jmp/call handling Oleg Nesterov
2014-04-04 18:51 ` [PATCH v2 1/9] uprobes: Kill UPROBE_SKIP_SSTEP and can_skip_sstep() Oleg Nesterov
2014-04-04 18:51 ` [PATCH v2 2/9] uprobes/x86: Fold prepare_fixups() into arch_uprobe_analyze_insn() Oleg Nesterov
2014-04-04 18:51 ` [PATCH v2 3/9] uprobes/x86: Kill the "ia32_compat" check in handle_riprel_insn(), remove "mm" arg Oleg Nesterov
2014-04-04 18:51 ` [PATCH v2 4/9] uprobes/x86: Gather "riprel" functions together Oleg Nesterov
2014-04-04 18:51 ` [PATCH v2 5/9] uprobes/x86: move the UPROBE_FIX_{RIP,IP,CALL} code at the end of pre/post hooks Oleg Nesterov
2014-04-04 18:51 ` [PATCH v2 6/9] uprobes/x86: Introduce uprobe_xol_ops and arch_uprobe->ops Oleg Nesterov
2014-04-08 9:10 ` Masami Hiramatsu
2014-04-08 16:10 ` Oleg Nesterov
2014-04-08 18:10 ` Oleg Nesterov
2014-04-09 12:58 ` Masami Hiramatsu
2014-04-09 16:55 ` Oleg Nesterov
2014-04-10 13:58 ` Masami Hiramatsu
2014-04-04 18:51 ` [PATCH v2 7/9] uprobes/x86: Conditionalize the usage of handle_riprel_insn() Oleg Nesterov
2014-04-04 18:51 ` [PATCH v2 8/9] uprobes/x86: Send SIGILL if arch_uprobe_post_xol() fails Oleg Nesterov
2014-04-04 18:51 ` [PATCH v2 9/9] uprobes/x86: Teach arch_uprobe_post_xol() to restart if possible Oleg Nesterov
2014-04-04 21:56 ` Jim Keniston
2014-04-05 12:46 ` Oleg Nesterov
2014-04-04 19:32 ` [PATCH v2 0/9] uprobes/x86: preparations to fix the reprel jmp/call handling Oleg Nesterov
2014-04-04 19:52 ` Oleg Nesterov
2014-04-04 23:44 ` Jim Keniston
2014-04-06 20:15 ` [RFC PATCH 0/6] uprobes/x86: " Oleg Nesterov
2014-04-06 20:16 ` [RFC PATCH 1/6] uprobes/x86: Emulate unconditional rip-relative jmp's Oleg Nesterov
2014-04-08 20:36 ` Jim Keniston
2014-04-09 14:47 ` Oleg Nesterov
2014-04-06 20:16 ` [RFC PATCH 2/6] uprobes/x86: Emulate nop's using ops->emulate() Oleg Nesterov
2014-04-06 20:16 ` [RFC PATCH 3/6] uprobes/x86: Introduce sizeof_long(), cleanup adjust_ret_addr() and arch_uretprobe_hijack_return_addr() Oleg Nesterov
2014-04-07 20:34 ` Jim Keniston
2014-04-07 20:42 ` Jim Keniston
2014-04-06 20:16 ` Oleg Nesterov [this message]
2014-04-08 22:26 ` [RFC PATCH 4/6] uprobes/x86: Emulate rip-relative call's Jim Keniston
2014-04-09 15:43 ` Oleg Nesterov
2014-04-09 21:25 ` Jim Keniston
2014-04-10 4:05 ` Jim Keniston
2014-04-10 13:41 ` Denys Vlasenko
2014-04-10 13:57 ` Masami Hiramatsu
2014-04-10 14:20 ` Denys Vlasenko
2014-04-11 3:03 ` Masami Hiramatsu
2014-04-11 12:23 ` Denys Vlasenko
2014-04-14 14:22 ` Masami Hiramatsu
2014-04-18 15:17 ` Denys Vlasenko
2014-04-10 14:28 ` Oleg Nesterov
2014-04-10 17:00 ` Oleg Nesterov
2014-04-11 2:38 ` Masami Hiramatsu
2014-04-11 1:29 ` Masami Hiramatsu
2014-04-10 14:18 ` Oleg Nesterov
2014-04-10 14:30 ` Denys Vlasenko
2014-04-10 17:02 ` Denys Vlasenko
2014-04-14 5:14 ` Masami Hiramatsu
2014-04-14 12:24 ` Denys Vlasenko
2014-04-14 14:05 ` Masami Hiramatsu
2014-04-06 20:16 ` [RFC PATCH 5/6] uprobes/x86: Emulate rip-relative conditional "short" jmp's Oleg Nesterov
2014-04-07 14:27 ` [RFC PATCH v2 " Oleg Nesterov
2014-04-07 16:41 ` Oleg Nesterov
2014-04-08 22:53 ` Jim Keniston
2014-04-09 16:42 ` Oleg Nesterov
2014-04-06 20:16 ` [RFC PATCH 6/6] uprobes/x86: Emulate rip-relative conditional "near" jmp's Oleg Nesterov
2014-04-07 14:28 ` Oleg Nesterov
2014-04-08 23:07 ` Jim Keniston
2014-04-09 16:50 ` Oleg Nesterov
2014-04-07 18:54 ` [RFC PATCH 0/6] uprobes/x86: fix the reprel jmp/call handling Jim Keniston
2014-04-08 11:43 ` Masami Hiramatsu
2014-04-08 16:28 ` Oleg Nesterov
2014-04-08 19:26 ` Oleg Nesterov
2014-04-09 19:44 ` [RFC PATCH v2 " Oleg Nesterov
2014-04-09 19:44 ` [RFC PATCH v2 1/6] uprobes/x86: Introduce sizeof_long(), cleanup adjust_ret_addr() and arch_uretprobe_hijack_return_addr() Oleg Nesterov
2014-04-09 19:44 ` [RFC PATCH v2 2/6] uprobes/x86: Emulate unconditional rip-relative jmp's Oleg Nesterov
2014-04-10 12:37 ` Denys Vlasenko
2014-04-10 13:47 ` Oleg Nesterov
2014-04-09 19:44 ` [RFC PATCH v2 3/6] uprobes/x86: Emulate nop's using ops->emulate() Oleg Nesterov
2014-04-09 19:44 ` [RFC PATCH v2 4/6] uprobes/x86: Emulate rip-relative call's Oleg Nesterov
2014-04-10 12:53 ` Denys Vlasenko
2014-04-10 13:15 ` Masami Hiramatsu
2014-04-10 13:41 ` Oleg Nesterov
2014-04-09 19:44 ` [RFC PATCH v2 5/6] uprobes/x86: Emulate rip-relative conditional "short" jmp's Oleg Nesterov
2014-04-09 19:44 ` [RFC PATCH v2 6/6] uprobes/x86: Emulate rip-relative conditional "near" jmp's Oleg Nesterov
2014-04-10 12:49 ` Denys Vlasenko
2014-04-09 21:34 ` [RFC PATCH v2 0/6] uprobes/x86: fix the reprel jmp/call handling Jim Keniston
2014-04-10 12:28 ` Denys Vlasenko
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20140406201628.GA507@redhat.com \
--to=oleg@redhat.com \
--cc=aarapov@redhat.com \
--cc=ananth@in.ibm.com \
--cc=dave.long@linaro.org \
--cc=dvlasenk@redhat.com \
--cc=fche@redhat.com \
--cc=jkenisto@us.ibm.com \
--cc=jlebon@redhat.com \
--cc=linux-kernel@vger.kernel.org \
--cc=masami.hiramatsu.pt@hitachi.com \
--cc=mingo@elte.hu \
--cc=srikar@linux.vnet.ibm.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).