lkml.org 
[lkml]   [2020]   [May]   [27]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    /
    Date
    From
    SubjectRe: [PATCH V7 03/15] kprobes: Add symbols for kprobe insn pages
    On Tue, 12 May 2020 15:19:10 +0300
    Adrian Hunter <adrian.hunter@intel.com> wrote:

    > Symbols are needed for tools to describe instruction addresses. Pages
    > allocated for kprobe's purposes need symbols to be created for them.
    > Add such symbols to be visible via /proc/kallsyms.
    >
    > Note: kprobe insn pages are not used if ftrace is configured. To see the
    > effect of this patch, the kernel must be configured with:

    Note, if you put a probe inside the function body, kprobe_insn_pages is
    used even if ftrace is configured.
    (Ftrace is used only for the function entry)

    >
    > # CONFIG_FUNCTION_TRACER is not set
    > CONFIG_KPROBES=y
    >
    > and for optimised kprobes:
    >
    > CONFIG_OPTPROBES=y
    >
    > Example on x86:
    >
    > # perf probe __schedule
    > Added new event:
    > probe:__schedule (on __schedule)
    > # cat /proc/kallsyms | grep '\[__builtin__kprobes\]'
    > ffffffffc00d4000 t kprobe_insn_page [__builtin__kprobes]
    > ffffffffc00d6000 t kprobe_optinsn_page [__builtin__kprobes]
    >
    > Note: This patch adds "__builtin__kprobes" as a module name in
    > /proc/kallsyms for symbols for pages allocated for kprobes' purposes, even
    > though "__builtin__kprobes" is not a module.

    Anyway, except for the Peter's sparc64 issue, the code is good to me.

    Acked-by: Masami Hiramatsu <mhiramat@kernel.org>

    Thank you,

    >
    > Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
    > Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
    > ---
    > include/linux/kprobes.h | 15 ++++++++++++++
    > kernel/kallsyms.c | 37 +++++++++++++++++++++++++++++----
    > kernel/kprobes.c | 45 +++++++++++++++++++++++++++++++++++++++++
    > 3 files changed, 93 insertions(+), 4 deletions(-)
    >
    > diff --git a/include/linux/kprobes.h b/include/linux/kprobes.h
    > index 04bdaf01112c..62d682f47b5e 100644
    > --- a/include/linux/kprobes.h
    > +++ b/include/linux/kprobes.h
    > @@ -242,6 +242,7 @@ struct kprobe_insn_cache {
    > struct mutex mutex;
    > void *(*alloc)(void); /* allocate insn page */
    > void (*free)(void *); /* free insn page */
    > + const char *sym; /* symbol for insn pages */
    > struct list_head pages; /* list of kprobe_insn_page */
    > size_t insn_size; /* size of instruction slot */
    > int nr_garbage;
    > @@ -272,6 +273,8 @@ static inline bool is_kprobe_##__name##_slot(unsigned long addr) \
    > { \
    > return __is_insn_slot_addr(&kprobe_##__name##_slots, addr); \
    > }
    > +#define KPROBE_INSN_PAGE_SYM "kprobe_insn_page"
    > +#define KPROBE_OPTINSN_PAGE_SYM "kprobe_optinsn_page"
    > #else /* __ARCH_WANT_KPROBES_INSN_SLOT */
    > #define DEFINE_INSN_CACHE_OPS(__name) \
    > static inline bool is_kprobe_##__name##_slot(unsigned long addr) \
    > @@ -373,6 +376,13 @@ void dump_kprobe(struct kprobe *kp);
    > void *alloc_insn_page(void);
    > void free_insn_page(void *page);
    >
    > +int kprobe_get_kallsym(unsigned int symnum, unsigned long *value, char *type,
    > + char *sym);
    > +int kprobe_cache_get_kallsym(struct kprobe_insn_cache *c, unsigned int *symnum,
    > + unsigned long *value, char *type, char *sym);
    > +
    > +int arch_kprobe_get_kallsym(unsigned int *symnum, unsigned long *value,
    > + char *type, char *sym);
    > #else /* !CONFIG_KPROBES: */
    >
    > static inline int kprobes_built_in(void)
    > @@ -435,6 +445,11 @@ static inline bool within_kprobe_blacklist(unsigned long addr)
    > {
    > return true;
    > }
    > +static inline int kprobe_get_kallsym(unsigned int symnum, unsigned long *value,
    > + char *type, char *sym)
    > +{
    > + return -ERANGE;
    > +}
    > #endif /* CONFIG_KPROBES */
    > static inline int disable_kretprobe(struct kretprobe *rp)
    > {
    > diff --git a/kernel/kallsyms.c b/kernel/kallsyms.c
    > index 16c8c605f4b0..c6cc293c0e67 100644
    > --- a/kernel/kallsyms.c
    > +++ b/kernel/kallsyms.c
    > @@ -24,6 +24,7 @@
    > #include <linux/slab.h>
    > #include <linux/filter.h>
    > #include <linux/ftrace.h>
    > +#include <linux/kprobes.h>
    > #include <linux/compiler.h>
    >
    > /*
    > @@ -437,6 +438,7 @@ struct kallsym_iter {
    > loff_t pos_arch_end;
    > loff_t pos_mod_end;
    > loff_t pos_ftrace_mod_end;
    > + loff_t pos_bpf_end;
    > unsigned long value;
    > unsigned int nameoff; /* If iterating in core kernel symbols. */
    > char type;
    > @@ -496,11 +498,33 @@ static int get_ksymbol_ftrace_mod(struct kallsym_iter *iter)
    >
    > static int get_ksymbol_bpf(struct kallsym_iter *iter)
    > {
    > + int ret;
    > +
    > strlcpy(iter->module_name, "bpf", MODULE_NAME_LEN);
    > iter->exported = 0;
    > - return bpf_get_kallsym(iter->pos - iter->pos_ftrace_mod_end,
    > - &iter->value, &iter->type,
    > - iter->name) < 0 ? 0 : 1;
    > + ret = bpf_get_kallsym(iter->pos - iter->pos_ftrace_mod_end,
    > + &iter->value, &iter->type,
    > + iter->name);
    > + if (ret < 0) {
    > + iter->pos_bpf_end = iter->pos;
    > + return 0;
    > + }
    > +
    > + return 1;
    > +}
    > +
    > +/*
    > + * This uses "__builtin__kprobes" as a module name for symbols for pages
    > + * allocated for kprobes' purposes, even though "__builtin__kprobes" is not a
    > + * module.
    > + */
    > +static int get_ksymbol_kprobe(struct kallsym_iter *iter)
    > +{
    > + strlcpy(iter->module_name, "__builtin__kprobes", MODULE_NAME_LEN);
    > + iter->exported = 0;
    > + return kprobe_get_kallsym(iter->pos - iter->pos_bpf_end,
    > + &iter->value, &iter->type,
    > + iter->name) < 0 ? 0 : 1;
    > }
    >
    > /* Returns space to next name. */
    > @@ -527,6 +551,7 @@ static void reset_iter(struct kallsym_iter *iter, loff_t new_pos)
    > iter->pos_arch_end = 0;
    > iter->pos_mod_end = 0;
    > iter->pos_ftrace_mod_end = 0;
    > + iter->pos_bpf_end = 0;
    > }
    > }
    >
    > @@ -551,7 +576,11 @@ static int update_iter_mod(struct kallsym_iter *iter, loff_t pos)
    > get_ksymbol_ftrace_mod(iter))
    > return 1;
    >
    > - return get_ksymbol_bpf(iter);
    > + if ((!iter->pos_bpf_end || iter->pos_bpf_end > pos) &&
    > + get_ksymbol_bpf(iter))
    > + return 1;
    > +
    > + return get_ksymbol_kprobe(iter);
    > }
    >
    > /* Returns false if pos at or past end of file. */
    > diff --git a/kernel/kprobes.c b/kernel/kprobes.c
    > index 2625c241ac00..229d1b596690 100644
    > --- a/kernel/kprobes.c
    > +++ b/kernel/kprobes.c
    > @@ -118,6 +118,7 @@ struct kprobe_insn_cache kprobe_insn_slots = {
    > .mutex = __MUTEX_INITIALIZER(kprobe_insn_slots.mutex),
    > .alloc = alloc_insn_page,
    > .free = free_insn_page,
    > + .sym = KPROBE_INSN_PAGE_SYM,
    > .pages = LIST_HEAD_INIT(kprobe_insn_slots.pages),
    > .insn_size = MAX_INSN_SIZE,
    > .nr_garbage = 0,
    > @@ -296,6 +297,7 @@ struct kprobe_insn_cache kprobe_optinsn_slots = {
    > .mutex = __MUTEX_INITIALIZER(kprobe_optinsn_slots.mutex),
    > .alloc = alloc_insn_page,
    > .free = free_insn_page,
    > + .sym = KPROBE_OPTINSN_PAGE_SYM,
    > .pages = LIST_HEAD_INIT(kprobe_optinsn_slots.pages),
    > /* .insn_size is initialized later */
    > .nr_garbage = 0,
    > @@ -2179,6 +2181,49 @@ int kprobe_add_area_blacklist(unsigned long start, unsigned long end)
    > return 0;
    > }
    >
    > +int kprobe_cache_get_kallsym(struct kprobe_insn_cache *c, unsigned int *symnum,
    > + unsigned long *value, char *type, char *sym)
    > +{
    > + struct kprobe_insn_page *kip;
    > + int ret = -ERANGE;
    > +
    > + rcu_read_lock();
    > + list_for_each_entry_rcu(kip, &c->pages, list) {
    > + if ((*symnum)--)
    > + continue;
    > + strlcpy(sym, c->sym, KSYM_NAME_LEN);
    > + *type = 't';
    > + *value = (unsigned long)kip->insns;
    > + ret = 0;
    > + break;
    > + }
    > + rcu_read_unlock();
    > +
    > + return ret;
    > +}
    > +
    > +int __weak arch_kprobe_get_kallsym(unsigned int *symnum, unsigned long *value,
    > + char *type, char *sym)
    > +{
    > + return -ERANGE;
    > +}
    > +
    > +int kprobe_get_kallsym(unsigned int symnum, unsigned long *value, char *type,
    > + char *sym)
    > +{
    > +#ifdef __ARCH_WANT_KPROBES_INSN_SLOT
    > + if (!kprobe_cache_get_kallsym(&kprobe_insn_slots, &symnum, value, type, sym))
    > + return 0;
    > +#ifdef CONFIG_OPTPROBES
    > + if (!kprobe_cache_get_kallsym(&kprobe_optinsn_slots, &symnum, value, type, sym))
    > + return 0;
    > +#endif
    > +#endif
    > + if (!arch_kprobe_get_kallsym(&symnum, value, type, sym))
    > + return 0;
    > + return -ERANGE;
    > +}
    > +
    > int __init __weak arch_populate_kprobe_blacklist(void)
    > {
    > return 0;
    > --
    > 2.17.1
    >


    --
    Masami Hiramatsu <mhiramat@kernel.org>

    \
     
     \ /
      Last update: 2020-05-28 02:25    [W:3.096 / U:0.420 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site