All of lore.kernel.org
 help / color / mirror / Atom feed
From: Rusty Russell <rusty@rustcorp.com.au>
To: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>,
	Ingo Molnar <mingo@kernel.org>
Cc: Pratyush Anand <panand@redhat.com>,
	Ananth N Mavinakayanahalli <ananth@in.ibm.com>,
	Linux Kernel Mailing List <linux-kernel@vger.kernel.org>,
	Ingo Molnar <mingo@redhat.com>, Rob Landley <rob@landley.net>,
	"H. Peter Anvin" <hpa@zytor.com>,
	Thomas Gleixner <tglx@linutronix.de>,
	"David S. Miller" <davem@davemloft.net>
Subject: Re: [PATCH tip/master 1/3] kprobes: Support blacklist functions in module
Date: Thu, 16 Jul 2015 21:04:29 +0930	[thread overview]
Message-ID: <87k2u0mj3u.fsf@rustcorp.com.au> (raw)
In-Reply-To: <20150716071055.14218.64129.stgit@localhost.localdomain>

Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> writes:
> To blacklist the functions in a module (e.g. user-defined
> kprobe handler and the functions invoked from it), expand
> blacklist support for modules.
> With this change, users can use NOKPROBE_SYMBOL() macro in
> their own modules.

Looks great, thanks!

Acked-by: Rusty Russell <rusty@rustcorp.com.au>

> Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
> Cc: Ananth N Mavinakayanahalli <ananth@in.ibm.com>
> Cc: "David S. Miller" <davem@davemloft.net>
> Cc: Rob Landley <rob@landley.net>
> Cc: Rusty Russell <rusty@rustcorp.com.au>
> ---
>  Documentation/kprobes.txt |    8 ++++++
>  include/linux/module.h    |    4 +++
>  kernel/kprobes.c          |   64 ++++++++++++++++++++++++++++++++++++++-------
>  kernel/module.c           |    6 ++++
>  4 files changed, 72 insertions(+), 10 deletions(-)
>
> diff --git a/Documentation/kprobes.txt b/Documentation/kprobes.txt
> index 1f9b3e2..b5a698f 100644
> --- a/Documentation/kprobes.txt
> +++ b/Documentation/kprobes.txt
> @@ -513,6 +513,14 @@ int enable_jprobe(struct jprobe *jp);
>  Enables *probe which has been disabled by disable_*probe(). You must specify
>  the probe which has been registered.
>  
> +4.9 NOKPROBE_SYMBOL()
> +
> +#include <linux/kprobes.h>
> +NOKPROBE_SYMBOL(FUNCTION);
> +
> +Protects given FUNCTION from other kprobes. This is useful for handler
> +functions and functions called from the handlers.
> +
>  5. Kprobes Features and Limitations
>  
>  Kprobes allows multiple probes at the same address.  Currently,
> diff --git a/include/linux/module.h b/include/linux/module.h
> index d67b193..0827e34 100644
> --- a/include/linux/module.h
> +++ b/include/linux/module.h
> @@ -352,6 +352,10 @@ struct module {
>  	void __percpu *percpu;
>  	unsigned int percpu_size;
>  #endif
> +#ifdef CONFIG_KPROBES
> +	unsigned int num_kprobe_blacklist;
> +	unsigned long  *kprobe_blacklist;
> +#endif
>  
>  #ifdef CONFIG_TRACEPOINTS
>  	unsigned int num_tracepoints;
> diff --git a/kernel/kprobes.c b/kernel/kprobes.c
> index c90e417..53951c3 100644
> --- a/kernel/kprobes.c
> +++ b/kernel/kprobes.c
> @@ -88,6 +88,7 @@ static raw_spinlock_t *kretprobe_table_lock_ptr(unsigned long hash)
>  
>  /* Blacklist -- list of struct kprobe_blacklist_entry */
>  static LIST_HEAD(kprobe_blacklist);
> +static DEFINE_MUTEX(kprobe_blacklist_mutex);
>  
>  #ifdef __ARCH_WANT_KPROBES_INSN_SLOT
>  /*
> @@ -1332,22 +1333,27 @@ bool __weak arch_within_kprobe_blacklist(unsigned long addr)
>  	       addr < (unsigned long)__kprobes_text_end;
>  }
>  
> -static bool within_kprobe_blacklist(unsigned long addr)
> +static struct kprobe_blacklist_entry *find_blacklist_entry(unsigned long addr)
>  {
>  	struct kprobe_blacklist_entry *ent;
>  
> +	list_for_each_entry(ent, &kprobe_blacklist, list) {
> +		if (addr >= ent->start_addr && addr < ent->end_addr)
> +			return ent;
> +	}
> +
> +	return NULL;
> +}
> +
> +static bool within_kprobe_blacklist(unsigned long addr)
> +{
>  	if (arch_within_kprobe_blacklist(addr))
>  		return true;
>  	/*
>  	 * If there exists a kprobe_blacklist, verify and
>  	 * fail any probe registration in the prohibited area
>  	 */
> -	list_for_each_entry(ent, &kprobe_blacklist, list) {
> -		if (addr >= ent->start_addr && addr < ent->end_addr)
> -			return true;
> -	}
> -
> -	return false;
> +	return !!find_blacklist_entry(addr);
>  }
>  
>  /*
> @@ -1437,6 +1443,8 @@ static int check_kprobe_address_safe(struct kprobe *p,
>  	ret = arch_check_ftrace_location(p);
>  	if (ret)
>  		return ret;
> +
> +	mutex_lock(&kprobe_blacklist_mutex);
>  	jump_label_lock();
>  	preempt_disable();
>  
> @@ -1474,6 +1482,7 @@ static int check_kprobe_address_safe(struct kprobe *p,
>  out:
>  	preempt_enable();
>  	jump_label_unlock();
> +	mutex_unlock(&kprobe_blacklist_mutex);
>  
>  	return ret;
>  }
> @@ -2054,13 +2063,13 @@ NOKPROBE_SYMBOL(dump_kprobe);
>   * since a kprobe need not necessarily be at the beginning
>   * of a function.
>   */
> -static int __init populate_kprobe_blacklist(unsigned long *start,
> -					     unsigned long *end)
> +static int populate_kprobe_blacklist(unsigned long *start, unsigned long *end)
>  {
>  	unsigned long *iter;
>  	struct kprobe_blacklist_entry *ent;
>  	unsigned long entry, offset = 0, size = 0;
>  
> +	mutex_lock(&kprobe_blacklist_mutex);
>  	for (iter = start; iter < end; iter++) {
>  		entry = arch_deref_entry_point((void *)*iter);
>  
> @@ -2079,9 +2088,28 @@ static int __init populate_kprobe_blacklist(unsigned long *start,
>  		INIT_LIST_HEAD(&ent->list);
>  		list_add_tail(&ent->list, &kprobe_blacklist);
>  	}
> +	mutex_unlock(&kprobe_blacklist_mutex);
> +
>  	return 0;
>  }
>  
> +/* Shrink the blacklist */
> +static void shrink_kprobe_blacklist(unsigned long *start, unsigned long *end)
> +{
> +	struct kprobe_blacklist_entry *ent;
> +	unsigned long *iter;
> +
> +	mutex_lock(&kprobe_blacklist_mutex);
> +	for (iter = start; iter < end; iter++) {
> +		ent = find_blacklist_entry(*iter);
> +		if (!ent)
> +			continue;
> +		list_del(&ent->list);
> +		kfree(ent);
> +	}
> +	mutex_unlock(&kprobe_blacklist_mutex);
> +}
> +
>  /* Module notifier call back, checking kprobes on the module */
>  static int kprobes_module_callback(struct notifier_block *nb,
>  				   unsigned long val, void *data)
> @@ -2092,6 +2120,16 @@ static int kprobes_module_callback(struct notifier_block *nb,
>  	unsigned int i;
>  	int checkcore = (val == MODULE_STATE_GOING);
>  
> +	/* Add/remove module blacklist */
> +	if (val == MODULE_STATE_COMING)
> +		populate_kprobe_blacklist(mod->kprobe_blacklist,
> +					  mod->kprobe_blacklist +
> +					  mod->num_kprobe_blacklist);
> +	else if (val == MODULE_STATE_GOING)
> +		shrink_kprobe_blacklist(mod->kprobe_blacklist,
> +					mod->kprobe_blacklist +
> +					mod->num_kprobe_blacklist);
> +
>  	if (val != MODULE_STATE_GOING && val != MODULE_STATE_LIVE)
>  		return NOTIFY_DONE;
>  
> @@ -2278,6 +2316,7 @@ static const struct file_operations debugfs_kprobes_operations = {
>  /* kprobes/blacklist -- shows which functions can not be probed */
>  static void *kprobe_blacklist_seq_start(struct seq_file *m, loff_t *pos)
>  {
> +	mutex_lock(&kprobe_blacklist_mutex);
>  	return seq_list_start(&kprobe_blacklist, *pos);
>  }
>  
> @@ -2286,6 +2325,11 @@ static void *kprobe_blacklist_seq_next(struct seq_file *m, void *v, loff_t *pos)
>  	return seq_list_next(v, &kprobe_blacklist, pos);
>  }
>  
> +static void kprobe_blacklist_seq_stop(struct seq_file *m, void *v)
> +{
> +	mutex_unlock(&kprobe_blacklist_mutex);
> +}
> +
>  static int kprobe_blacklist_seq_show(struct seq_file *m, void *v)
>  {
>  	struct kprobe_blacklist_entry *ent =
> @@ -2299,7 +2343,7 @@ static int kprobe_blacklist_seq_show(struct seq_file *m, void *v)
>  static const struct seq_operations kprobe_blacklist_seq_ops = {
>  	.start = kprobe_blacklist_seq_start,
>  	.next  = kprobe_blacklist_seq_next,
> -	.stop  = kprobe_seq_stop,	/* Reuse void function */
> +	.stop  = kprobe_blacklist_seq_stop,
>  	.show  = kprobe_blacklist_seq_show,
>  };
>  
> diff --git a/kernel/module.c b/kernel/module.c
> index 4d2b82e..c3a593c 100644
> --- a/kernel/module.c
> +++ b/kernel/module.c
> @@ -57,6 +57,7 @@
>  #include <linux/percpu.h>
>  #include <linux/kmemleak.h>
>  #include <linux/jump_label.h>
> +#include <linux/kprobes.h>
>  #include <linux/pfn.h>
>  #include <linux/bsearch.h>
>  #include <uapi/linux/module.h>
> @@ -2937,6 +2938,11 @@ static int find_module_sections(struct module *mod, struct load_info *info)
>  					     sizeof(*mod->ftrace_callsites),
>  					     &mod->num_ftrace_callsites);
>  #endif
> +#ifdef CONFIG_KPROBES
> +	mod->kprobe_blacklist = section_objs(info, "_kprobe_blacklist",
> +					     sizeof(*mod->kprobe_blacklist),
> +					     &mod->num_kprobe_blacklist);
> +#endif
>  
>  	mod->extable = section_objs(info, "__ex_table",
>  				    sizeof(*mod->extable), &mod->num_exentries);
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/

  reply	other threads:[~2015-07-16 11:35 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-07-16  7:10 [PATCH tip/master 0/3] kprobes blacklist enhancement Masami Hiramatsu
2015-07-16  7:10 ` [PATCH tip/master 1/3] kprobes: Support blacklist functions in module Masami Hiramatsu
2015-07-16 11:34   ` Rusty Russell [this message]
2015-07-17 12:10   ` Ingo Molnar
2015-07-19  3:15     ` Masami Hiramatsu
2015-07-21  7:48       ` Ingo Molnar
2015-07-21 10:19         ` Masami Hiramatsu
2015-07-16  7:10 ` [PATCH tip/master 2/3] kprobes: Use NOKPROBE_SYMBOL() in sample modules Masami Hiramatsu
2015-07-16  7:10 ` [PATCH tip/master 3/3] kprobes/x86: Use kprobe_blacklist for .kprobes.text and .entry.text 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=87k2u0mj3u.fsf@rustcorp.com.au \
    --to=rusty@rustcorp.com.au \
    --cc=ananth@in.ibm.com \
    --cc=davem@davemloft.net \
    --cc=hpa@zytor.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=masami.hiramatsu.pt@hitachi.com \
    --cc=mingo@kernel.org \
    --cc=mingo@redhat.com \
    --cc=panand@redhat.com \
    --cc=rob@landley.net \
    --cc=tglx@linutronix.de \
    /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.