All of lore.kernel.org
 help / color / mirror / Atom feed
From: Joe Lawrence <joe.lawrence@redhat.com>
To: Masami Hiramatsu <mhiramat@kernel.org>
Cc: Steven Rostedt <rostedt@goodmis.org>,
	Ingo Molnar <mingo@kernel.org>,
	Josh Poimboeuf <jpoimboe@redhat.com>,
	live-patching@vger.kernel.org, linux-kernel@vger.kernel.org,
	"Naveen N . Rao" <naveen.n.rao@linux.ibm.com>,
	Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>,
	"David S . Miller" <davem@davemloft.net>
Subject: Re: [PATCH] kprobes: Allow kprobes coexist with livepatch
Date: Thu, 25 Jul 2019 22:07:52 -0400	[thread overview]
Message-ID: <20190726020752.GA6388@redhat.com> (raw)
In-Reply-To: <156403587671.30117.5233558741694155985.stgit@devnote2>

On Thu, Jul 25, 2019 at 03:24:37PM +0900, Masami Hiramatsu wrote:
> Allow kprobes which do not modify regs->ip, coexist with livepatch
> by dropping FTRACE_OPS_FL_IPMODIFY from ftrace_ops.
> 
> User who wants to modify regs->ip (e.g. function fault injection)
> must set a dummy post_handler to its kprobes when registering.
> However, if such regs->ip modifying kprobes is set on a function,
> that function can not be livepatched.
> 
> Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
> ---
>  kernel/kprobes.c |   56 +++++++++++++++++++++++++++++++++++++++---------------
>  1 file changed, 40 insertions(+), 16 deletions(-)
> 
> diff --git a/kernel/kprobes.c b/kernel/kprobes.c
> index 9873fc627d61..29065380dad0 100644
> --- a/kernel/kprobes.c
> +++ b/kernel/kprobes.c
> @@ -961,9 +961,16 @@ static struct kprobe *alloc_aggr_kprobe(struct kprobe *p)
>  
>  #ifdef CONFIG_KPROBES_ON_FTRACE
>  static struct ftrace_ops kprobe_ftrace_ops __read_mostly = {
> +	.func = kprobe_ftrace_handler,
> +	.flags = FTRACE_OPS_FL_SAVE_REGS,
> +};
> +
> +static struct ftrace_ops kprobe_ipmodify_ops __read_mostly = {
>  	.func = kprobe_ftrace_handler,
>  	.flags = FTRACE_OPS_FL_SAVE_REGS | FTRACE_OPS_FL_IPMODIFY,
>  };
> +
> +static int kprobe_ipmodify_enabled;
>  static int kprobe_ftrace_enabled;
>  
>  /* Must ensure p->addr is really on ftrace */
> @@ -976,58 +983,75 @@ static int prepare_kprobe(struct kprobe *p)
>  }
>  
>  /* Caller must lock kprobe_mutex */
> -static int arm_kprobe_ftrace(struct kprobe *p)
> +static int __arm_kprobe_ftrace(struct kprobe *p, struct ftrace_ops *ops,
> +			       int *cnt)
>  {
>  	int ret = 0;
>  
> -	ret = ftrace_set_filter_ip(&kprobe_ftrace_ops,
> -				   (unsigned long)p->addr, 0, 0);
> +	ret = ftrace_set_filter_ip(ops, (unsigned long)p->addr, 0, 0);
>  	if (ret) {
>  		pr_debug("Failed to arm kprobe-ftrace at %pS (%d)\n",
>  			 p->addr, ret);
>  		return ret;
>  	}
>  
> -	if (kprobe_ftrace_enabled == 0) {
> -		ret = register_ftrace_function(&kprobe_ftrace_ops);
> +	if (*cnt == 0) {
> +		ret = register_ftrace_function(ops);
>  		if (ret) {
>  			pr_debug("Failed to init kprobe-ftrace (%d)\n", ret);
>  			goto err_ftrace;
>  		}
>  	}
>  
> -	kprobe_ftrace_enabled++;
> +	(*cnt)++;
>  	return ret;
>  
>  err_ftrace:
>  	/*
> -	 * Note: Since kprobe_ftrace_ops has IPMODIFY set, and ftrace requires a
> -	 * non-empty filter_hash for IPMODIFY ops, we're safe from an accidental
> -	 * empty filter_hash which would undesirably trace all functions.
> +	 * At this point, sinec ops is not registered, we should be sefe from
> +	 * registering empty filter.
>  	 */
> -	ftrace_set_filter_ip(&kprobe_ftrace_ops, (unsigned long)p->addr, 1, 0);
> +	ftrace_set_filter_ip(ops, (unsigned long)p->addr, 1, 0);
>  	return ret;
>  }
>  
> +static int arm_kprobe_ftrace(struct kprobe *p)
> +{
> +	bool ipmodify = (p->post_handler != NULL);
> +
> +	return __arm_kprobe_ftrace(p,
> +		ipmodify ? &kprobe_ipmodify_ops : &kprobe_ftrace_ops,
> +		ipmodify ? &kprobe_ipmodify_enabled : &kprobe_ftrace_enabled);
> +}
> +
>  /* Caller must lock kprobe_mutex */
> -static int disarm_kprobe_ftrace(struct kprobe *p)
> +static int __disarm_kprobe_ftrace(struct kprobe *p, struct ftrace_ops *ops,
> +				  int *cnt)
>  {
>  	int ret = 0;
>  
> -	if (kprobe_ftrace_enabled == 1) {
> -		ret = unregister_ftrace_function(&kprobe_ftrace_ops);
> +	if (*cnt == 1) {
> +		ret = unregister_ftrace_function(ops);
>  		if (WARN(ret < 0, "Failed to unregister kprobe-ftrace (%d)\n", ret))
>  			return ret;
>  	}
>  
> -	kprobe_ftrace_enabled--;
> +	(*cnt)--;
>  
> -	ret = ftrace_set_filter_ip(&kprobe_ftrace_ops,
> -			   (unsigned long)p->addr, 1, 0);
> +	ret = ftrace_set_filter_ip(ops, (unsigned long)p->addr, 1, 0);
>  	WARN_ONCE(ret < 0, "Failed to disarm kprobe-ftrace at %pS (%d)\n",
>  		  p->addr, ret);
>  	return ret;
>  }
> +
> +static int disarm_kprobe_ftrace(struct kprobe *p)
> +{
> +	bool ipmodify = (p->post_handler != NULL);
> +
> +	return __disarm_kprobe_ftrace(p,
> +		ipmodify ? &kprobe_ipmodify_ops : &kprobe_ftrace_ops,
> +		ipmodify ? &kprobe_ipmodify_enabled : &kprobe_ftrace_enabled);
> +}
>  #else	/* !CONFIG_KPROBES_ON_FTRACE */
>  #define prepare_kprobe(p)	arch_prepare_kprobe(p)
>  #define arm_kprobe_ftrace(p)	(-ENODEV)
> 

Thanks for the quick patch, Masami!

I gave it a spin and here are my new testing results:


perf probe, then livepatch
--------------------------

% perf probe --add cmdline_proc_show
Added new event:
  probe:cmdline_proc_show (on cmdline_proc_show)

You can now use it in all perf tools, such as:

        perf record -e probe:cmdline_proc_show -aR sleep 1

% perf record -e probe:cmdline_proc_show -aR sleep 30 &
[1] 980

% insmod samples/livepatch/livepatch-sample.ko

% cat /proc/cmdline 
this has been live patched

% fg
perf record -e probe:cmdline_proc_show -aR sleep 30
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.177 MB perf.data (2 samples) ]

% perf script
          insmod   983 [000]   157.126556: probe:cmdline_proc_show: (ffffffff9bf74890)
             cat   985 [000]   162.304028: probe:cmdline_proc_show: (ffffffff9bf74890)


livepatch, then perf probe
--------------------------

% insmod samples/livepatch/livepatch-sample.ko

% cat /proc/cmdline 
this has been live patched

% perf record -e probe:cmdline_proc_show -aR sleep 30
event syntax error: 'probe:cmdline_proc_show'
                     \___ unknown tracepoint

Error:  File /sys/kernel/debug/tracing/events/probe/cmdline_proc_show not found.
Hint:   Perhaps this kernel misses some CONFIG_ setting to enable this feature?.

Run 'perf list' for a list of valid events

 Usage: perf record [<options>] [<command>]
    or: perf record [<options>] -- <command> [<options>]

    -e, --event <event>   event selector. use 'perf list' to list available events


These results reflect my underestanding of FTRACE_OPS_FL_IPMODIFY in
light of your changes, so feel free to add my:

Acked-by: Joe Lawrence <joe.lawrence@redhat.com>

-- Joe

  parent reply	other threads:[~2019-07-26  2:08 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-07-25  6:24 [PATCH] kprobes: Allow kprobes coexist with livepatch Masami Hiramatsu
2019-07-25 13:33 ` Steven Rostedt
2019-07-26  2:07 ` Joe Lawrence [this message]
2019-07-26 16:14   ` Steven Rostedt
2019-07-26 17:38     ` Joe Lawrence
2019-07-26 18:06       ` Steven Rostedt
2019-07-27  9:41       ` Masami Hiramatsu

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=20190726020752.GA6388@redhat.com \
    --to=joe.lawrence@redhat.com \
    --cc=anil.s.keshavamurthy@intel.com \
    --cc=davem@davemloft.net \
    --cc=jpoimboe@redhat.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=live-patching@vger.kernel.org \
    --cc=mhiramat@kernel.org \
    --cc=mingo@kernel.org \
    --cc=naveen.n.rao@linux.ibm.com \
    --cc=rostedt@goodmis.org \
    /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.