All of lore.kernel.org
 help / color / mirror / Atom feed
From: Masami Hiramatsu <mhiramat@redhat.com>
To: Steven Rostedt <rostedt@goodmis.org>
Cc: Ingo Molnar <mingo@elte.hu>, lkml <linux-kernel@vger.kernel.org>,
	systemtap <systemtap@sources.redhat.com>,
	kvm <kvm@vger.kernel.org>,
	Ananth N Mavinakayanahalli <ananth@in.ibm.com>,
	Jim Keniston <jkenisto@us.ibm.com>
Subject: Re: [PATCH -tip v5 2/7] kprobes: checks probe address is instruction boudary on x86
Date: Mon, 11 May 2009 11:01:01 -0400	[thread overview]
Message-ID: <4A083DAD.8000009@redhat.com> (raw)
In-Reply-To: <alpine.DEB.2.00.0905111011060.14976@gandalf.stny.rr.com>

Steven Rostedt wrote:
> On Fri, 8 May 2009, Masami Hiramatsu wrote:
> 
>> Ensure safeness of inserting kprobes by checking whether the specified
>> address is at the first byte of a instruction on x86.
>> This is done by decoding probed function from its head to the probe point.
>>
>> Signed-off-by: Masami Hiramatsu <mhiramat@redhat.com>
>> Cc: Ananth N Mavinakayanahalli <ananth@in.ibm.com>
>> Cc: Jim Keniston <jkenisto@us.ibm.com>
>> Cc: Ingo Molnar <mingo@elte.hu>
>> ---
>>
>>  arch/x86/kernel/kprobes.c |   54 +++++++++++++++++++++++++++++++++++++++++++++
>>  1 files changed, 54 insertions(+), 0 deletions(-)
>>
>> diff --git a/arch/x86/kernel/kprobes.c b/arch/x86/kernel/kprobes.c
>> index 7b5169d..3d5e85f 100644
>> --- a/arch/x86/kernel/kprobes.c
>> +++ b/arch/x86/kernel/kprobes.c
>> @@ -48,12 +48,14 @@
>>  #include <linux/preempt.h>
>>  #include <linux/module.h>
>>  #include <linux/kdebug.h>
>> +#include <linux/kallsyms.h>
>>  
>>  #include <asm/cacheflush.h>
>>  #include <asm/desc.h>
>>  #include <asm/pgtable.h>
>>  #include <asm/uaccess.h>
>>  #include <asm/alternative.h>
>> +#include <asm/insn.h>
>>  
>>  void jprobe_return_end(void);
>>  
>> @@ -244,6 +246,56 @@ retry:
>>  	}
>>  }
>>  
>> +/* Recover the probed instruction at addr for further analysis. */
>> +static int recover_probed_instruction(kprobe_opcode_t *buf, unsigned long addr)
>> +{
>> +	struct kprobe *kp;
>> +	kp = get_kprobe((void *)addr);
>> +	if (!kp)
>> +		return -EINVAL;
>> +
> 
> I'm just doing a casual scan of the patch set.

Thank you!

> 
>> +	/*
>> +	 * Don't use p->ainsn.insn, which could be modified -- e.g.,
> 
> This comment talks about "p", what's that? It's not used in this function.

oops, this should be kp.

> 
>> +	 * by fix_riprel().
>> +	 */
>> +	memcpy(buf, kp->addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t));
>> +	buf[0] = kp->opcode;
> 
> Why is it OK to copy addr to "buf" and then rewrite the first character of 
> buf?  Does it have something to do with the above "p"?

Yes, each kprobe copied probed instruction to kp->ainsn.insn,
which is an executable buffer for single stepping.
So, basically, kp->ainsn.insn has an original instruction.
However, RIP-relative instruction can not do single-stepping
at different place, fix_riprel() tweaks the displacement of
that instruction. In that case, we can't recover the instruction
from the kp->ainsn.insn.

On the other hand, kp->opcode has a copy of the first byte of
the probed instruction, which is overwritten by int3. And
the instruction at kp->addr is not modified by kprobes except
for the first byte, we can recover the original instruction
from it and kp->opcode.

> I don't mean to be critical here, but I've been doing "Mother Day" 
> activities all weekend and for some reason that was also the best time for 
> everyone to Cc me on patches. I'm way behind in my email, and it would be 
> nice if the comments described why things that "look" wrong are not.
> 
> 
>> +	return 0;
>> +}
>> +
>> +/* Dummy buffers for kallsyms_lookup */
>> +static char __dummy_buf[KSYM_NAME_LEN];
>> +
>> +/* Check if paddr is at an instruction boundary */
>> +static int __kprobes can_probe(unsigned long paddr)
>> +{
>> +	int ret;
>> +	unsigned long addr, offset = 0;
>> +	struct insn insn;
>> +	kprobe_opcode_t buf[MAX_INSN_SIZE];
>> +
>> +	/* Lookup symbol including addr */
> 
> The above comment is very close to a "add one to i" for i++ type of 
> comment.

Agreed.

> 
>> +	if (!kallsyms_lookup(paddr, NULL, &offset, NULL, __dummy_buf))
>> +		return 0;
>> +
>> +	/* Decode instructions */
>> +	addr = paddr - offset;
>> +	while (addr < paddr) {
>> +		insn_init_kernel(&insn, (void *)addr);
>> +		insn_get_opcode(&insn);
>> +		if (OPCODE1(&insn) == BREAKPOINT_INSTRUCTION) {
>> +			ret = recover_probed_instruction(buf, addr);
> 
> Oh, the above puts back the original op code. That is why it is OK?

Oops, no. I have to use get_kprobe() instead. Thanks!

> 
> I'd comment that a little bit more. Just so that reviewers have an easier 
> idea of what is happening.
> 
>> +			if (ret)
>> +				return 0;
>> +			insn_init_kernel(&insn, buf);
> 
> insn_init_kernel? Is that like a text poke or something?

it's a wrapper of insn_init() which initialize struct insn.

Thank you,

>> +		}
>> +		insn_get_length(&insn);
>> +		addr += insn.length;
>> +	}
>> +
>> +	return (addr == paddr);
>> +}
>> +
>>  /*
>>   * Returns non-zero if opcode modifies the interrupt flag.
>>   */
>> @@ -359,6 +411,8 @@ static void __kprobes arch_copy_kprobe(struct kprobe *p)
>>  
>>  int __kprobes arch_prepare_kprobe(struct kprobe *p)
>>  {
>> +	if (!can_probe((unsigned long)p->addr))
>> +		return -EILSEQ;
>>  	/* insn: must be on special executable page on x86. */
>>  	p->ainsn.insn = get_insn_slot();
> 
> Oh look, I found the phantom "p"!
> 
> -- Steve
> 
>>  	if (!p->ainsn.insn)
>>
>>
>> -- 
>> Masami Hiramatsu
>>
>> Software Engineer
>> Hitachi Computer Products (America) Inc.
>> Software Solutions Division
>>
>> e-mail: mhiramat@redhat.com
>>

-- 
Masami Hiramatsu

Software Engineer
Hitachi Computer Products (America) Inc.
Software Solutions Division

e-mail: mhiramat@redhat.com


WARNING: multiple messages have this Message-ID (diff)
From: Masami Hiramatsu <mhiramat@redhat.com>
To: Steven Rostedt <rostedt@goodmis.org>
Cc: Ingo Molnar <mingo@elte.hu>, lkml <linux-kernel@vger.kernel.org>,
	        systemtap <systemtap@sources.redhat.com>,
	kvm <kvm@vger.kernel.org>,
	        Ananth N Mavinakayanahalli <ananth@in.ibm.com>,
	        Jim Keniston <jkenisto@us.ibm.com>
Subject: Re: [PATCH -tip v5 2/7] kprobes: checks probe address is instruction  boudary on x86
Date: Mon, 11 May 2009 11:01:01 -0400	[thread overview]
Message-ID: <4A083DAD.8000009@redhat.com> (raw)
In-Reply-To: <alpine.DEB.2.00.0905111011060.14976@gandalf.stny.rr.com>

Steven Rostedt wrote:
> On Fri, 8 May 2009, Masami Hiramatsu wrote:
> 
>> Ensure safeness of inserting kprobes by checking whether the specified
>> address is at the first byte of a instruction on x86.
>> This is done by decoding probed function from its head to the probe point.
>>
>> Signed-off-by: Masami Hiramatsu <mhiramat@redhat.com>
>> Cc: Ananth N Mavinakayanahalli <ananth@in.ibm.com>
>> Cc: Jim Keniston <jkenisto@us.ibm.com>
>> Cc: Ingo Molnar <mingo@elte.hu>
>> ---
>>
>>  arch/x86/kernel/kprobes.c |   54 +++++++++++++++++++++++++++++++++++++++++++++
>>  1 files changed, 54 insertions(+), 0 deletions(-)
>>
>> diff --git a/arch/x86/kernel/kprobes.c b/arch/x86/kernel/kprobes.c
>> index 7b5169d..3d5e85f 100644
>> --- a/arch/x86/kernel/kprobes.c
>> +++ b/arch/x86/kernel/kprobes.c
>> @@ -48,12 +48,14 @@
>>  #include <linux/preempt.h>
>>  #include <linux/module.h>
>>  #include <linux/kdebug.h>
>> +#include <linux/kallsyms.h>
>>  
>>  #include <asm/cacheflush.h>
>>  #include <asm/desc.h>
>>  #include <asm/pgtable.h>
>>  #include <asm/uaccess.h>
>>  #include <asm/alternative.h>
>> +#include <asm/insn.h>
>>  
>>  void jprobe_return_end(void);
>>  
>> @@ -244,6 +246,56 @@ retry:
>>  	}
>>  }
>>  
>> +/* Recover the probed instruction at addr for further analysis. */
>> +static int recover_probed_instruction(kprobe_opcode_t *buf, unsigned long addr)
>> +{
>> +	struct kprobe *kp;
>> +	kp = get_kprobe((void *)addr);
>> +	if (!kp)
>> +		return -EINVAL;
>> +
> 
> I'm just doing a casual scan of the patch set.

Thank you!

> 
>> +	/*
>> +	 * Don't use p->ainsn.insn, which could be modified -- e.g.,
> 
> This comment talks about "p", what's that? It's not used in this function.

oops, this should be kp.

> 
>> +	 * by fix_riprel().
>> +	 */
>> +	memcpy(buf, kp->addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t));
>> +	buf[0] = kp->opcode;
> 
> Why is it OK to copy addr to "buf" and then rewrite the first character of 
> buf?  Does it have something to do with the above "p"?

Yes, each kprobe copied probed instruction to kp->ainsn.insn,
which is an executable buffer for single stepping.
So, basically, kp->ainsn.insn has an original instruction.
However, RIP-relative instruction can not do single-stepping
at different place, fix_riprel() tweaks the displacement of
that instruction. In that case, we can't recover the instruction
from the kp->ainsn.insn.

On the other hand, kp->opcode has a copy of the first byte of
the probed instruction, which is overwritten by int3. And
the instruction at kp->addr is not modified by kprobes except
for the first byte, we can recover the original instruction
from it and kp->opcode.

> I don't mean to be critical here, but I've been doing "Mother Day" 
> activities all weekend and for some reason that was also the best time for 
> everyone to Cc me on patches. I'm way behind in my email, and it would be 
> nice if the comments described why things that "look" wrong are not.
> 
> 
>> +	return 0;
>> +}
>> +
>> +/* Dummy buffers for kallsyms_lookup */
>> +static char __dummy_buf[KSYM_NAME_LEN];
>> +
>> +/* Check if paddr is at an instruction boundary */
>> +static int __kprobes can_probe(unsigned long paddr)
>> +{
>> +	int ret;
>> +	unsigned long addr, offset = 0;
>> +	struct insn insn;
>> +	kprobe_opcode_t buf[MAX_INSN_SIZE];
>> +
>> +	/* Lookup symbol including addr */
> 
> The above comment is very close to a "add one to i" for i++ type of 
> comment.

Agreed.

> 
>> +	if (!kallsyms_lookup(paddr, NULL, &offset, NULL, __dummy_buf))
>> +		return 0;
>> +
>> +	/* Decode instructions */
>> +	addr = paddr - offset;
>> +	while (addr < paddr) {
>> +		insn_init_kernel(&insn, (void *)addr);
>> +		insn_get_opcode(&insn);
>> +		if (OPCODE1(&insn) == BREAKPOINT_INSTRUCTION) {
>> +			ret = recover_probed_instruction(buf, addr);
> 
> Oh, the above puts back the original op code. That is why it is OK?

Oops, no. I have to use get_kprobe() instead. Thanks!

> 
> I'd comment that a little bit more. Just so that reviewers have an easier 
> idea of what is happening.
> 
>> +			if (ret)
>> +				return 0;
>> +			insn_init_kernel(&insn, buf);
> 
> insn_init_kernel? Is that like a text poke or something?

it's a wrapper of insn_init() which initialize struct insn.

Thank you,

>> +		}
>> +		insn_get_length(&insn);
>> +		addr += insn.length;
>> +	}
>> +
>> +	return (addr == paddr);
>> +}
>> +
>>  /*
>>   * Returns non-zero if opcode modifies the interrupt flag.
>>   */
>> @@ -359,6 +411,8 @@ static void __kprobes arch_copy_kprobe(struct kprobe *p)
>>  
>>  int __kprobes arch_prepare_kprobe(struct kprobe *p)
>>  {
>> +	if (!can_probe((unsigned long)p->addr))
>> +		return -EILSEQ;
>>  	/* insn: must be on special executable page on x86. */
>>  	p->ainsn.insn = get_insn_slot();
> 
> Oh look, I found the phantom "p"!
> 
> -- Steve
> 
>>  	if (!p->ainsn.insn)
>>
>>
>> -- 
>> Masami Hiramatsu
>>
>> Software Engineer
>> Hitachi Computer Products (America) Inc.
>> Software Solutions Division
>>
>> e-mail: mhiramat@redhat.com
>>

-- 
Masami Hiramatsu

Software Engineer
Hitachi Computer Products (America) Inc.
Software Solutions Division

e-mail: mhiramat@redhat.com

  reply	other threads:[~2009-05-11 15:00 UTC|newest]

Thread overview: 57+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-05-09  0:48 [PATCH -tip v5 0/7] tracing: kprobe-based event tracer and x86 instruction decoder Masami Hiramatsu
2009-05-09  0:48 ` Masami Hiramatsu
2009-05-09  0:48 ` [PATCH -tip v5 1/7] x86: instruction decorder API Masami Hiramatsu
2009-05-11  9:27   ` Christoph Hellwig
2009-05-11  9:27     ` Christoph Hellwig
2009-05-11 14:36     ` Masami Hiramatsu
2009-05-11 14:36       ` Masami Hiramatsu
2009-05-13  8:23   ` Gleb Natapov
2009-05-13  8:23     ` Gleb Natapov
2009-05-13  9:35     ` Przemysław Pawełczyk
2009-05-13  9:43       ` Gleb Natapov
2009-05-13  9:43         ` Gleb Natapov
2009-05-13 14:35         ` Masami Hiramatsu
2009-05-13 14:35           ` Masami Hiramatsu
2009-05-13 15:20           ` Gleb Natapov
2009-05-09  0:48 ` [PATCH -tip v5 2/7] kprobes: checks probe address is instruction boudary on x86 Masami Hiramatsu
2009-05-09  0:48   ` Masami Hiramatsu
2009-05-11 14:20   ` Steven Rostedt
2009-05-11 15:01     ` Masami Hiramatsu [this message]
2009-05-11 15:01       ` Masami Hiramatsu
2009-05-11 15:14       ` Masami Hiramatsu
2009-05-11 15:14         ` Masami Hiramatsu
2009-05-11 15:22       ` Steven Rostedt
2009-05-11 18:21         ` Masami Hiramatsu
2009-05-11 18:21           ` Masami Hiramatsu
2009-05-09  0:48 ` [PATCH -tip v5 3/7] kprobes: cleanup fix_riprel() using insn decoder " Masami Hiramatsu
2009-05-09  0:48   ` Masami Hiramatsu
2009-05-09  0:48 ` [PATCH -tip v5 4/7] tracing: add kprobe-based event tracer Masami Hiramatsu
2009-05-09 16:36   ` Frédéric Weisbecker
2009-05-09 16:36     ` Frédéric Weisbecker
2009-05-09 17:33     ` Masami Hiramatsu
2009-05-11 21:26       ` Frederic Weisbecker
2009-05-11  9:32   ` Christoph Hellwig
2009-05-11 10:53     ` Ingo Molnar
2009-05-11 10:53       ` Ingo Molnar
2009-05-11 15:28     ` Frank Ch. Eigler
2009-05-11 15:28       ` Frank Ch. Eigler
2009-05-09  0:49 ` [PATCH -tip v5 5/7] x86: fix kernel_trap_sp() Masami Hiramatsu
2009-05-11  9:28   ` Christoph Hellwig
2009-05-11 13:48     ` Masami Hiramatsu
2009-05-11 13:48       ` Masami Hiramatsu
2009-05-09  0:49 ` [PATCH -tip v5 6/7] x86: add pt_regs register and stack access APIs Masami Hiramatsu
2009-05-09  0:49 ` [PATCH -tip v5 7/7] tracing: add arguments support on kprobe-based event tracer Masami Hiramatsu
2009-05-11 14:35   ` Steven Rostedt
2009-05-11 14:35     ` Steven Rostedt
2009-05-09  4:43 ` [PATCH -tip v5 0/7] tracing: kprobe-based event tracer and x86 instruction decoder Ingo Molnar
2009-05-09  4:43   ` Ingo Molnar
2009-05-11 14:40   ` Masami Hiramatsu
2009-05-11 14:56     ` Steven Rostedt
2009-05-11 20:05       ` Masami Hiramatsu
2009-05-11 20:05         ` Masami Hiramatsu
2009-05-11 21:47         ` Ingo Molnar
2009-05-11 21:47           ` Ingo Molnar
2009-05-12 22:03   ` Masami Hiramatsu
2009-05-12 22:03     ` Masami Hiramatsu
2009-05-13 13:21     ` Ingo Molnar
2009-05-13 13:21       ` Ingo Molnar

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=4A083DAD.8000009@redhat.com \
    --to=mhiramat@redhat.com \
    --cc=ananth@in.ibm.com \
    --cc=jkenisto@us.ibm.com \
    --cc=kvm@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mingo@elte.hu \
    --cc=rostedt@goodmis.org \
    --cc=systemtap@sources.redhat.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.