public inbox for bpf@vger.kernel.org
 help / color / mirror / Atom feed
From: Jiri Olsa <olsajiri@gmail.com>
To: Viktor Malik <vmalik@redhat.com>
Cc: bpf@vger.kernel.org, Alexei Starovoitov <ast@kernel.org>,
	Daniel Borkmann <daniel@iogearbox.net>,
	John Fastabend <john.fastabend@gmail.com>,
	Andrii Nakryiko <andrii@kernel.org>,
	Martin KaFai Lau <martin.lau@linux.dev>,
	Song Liu <song@kernel.org>, Yonghong Song <yhs@fb.com>,
	KP Singh <kpsingh@kernel.org>,
	Stanislav Fomichev <sdf@google.com>, Hao Luo <haoluo@google.com>,
	Luis Chamberlain <mcgrof@kernel.org>
Subject: Re: [PATCH bpf-next v6 1/2] bpf: Fix attaching fentry/fexit/fmod_ret/lsm to modules
Date: Thu, 16 Feb 2023 14:50:26 +0100	[thread overview]
Message-ID: <Y+40os27pQ8det/o@krava> (raw)
In-Reply-To: <e627742ab86ed28632bc9b6c56ef65d7f98eadbc.1676542796.git.vmalik@redhat.com>

On Thu, Feb 16, 2023 at 11:32:41AM +0100, Viktor Malik wrote:
> This resolves two problems with attachment of fentry/fexit/fmod_ret/lsm
> to functions located in modules:
> 
> 1. The verifier tries to find the address to attach to in kallsyms. This
>    is always done by searching the entire kallsyms, not respecting the
>    module in which the function is located. Such approach causes an
>    incorrect attachment address to be computed if the function to attach
>    to is shadowed by a function of the same name located earlier in
>    kallsyms.
> 
> 2. If the address to attach to is located in a module, the module
>    reference is only acquired in register_fentry. If the module is
>    unloaded between the place where the address is found
>    (bpf_check_attach_target in the verifier) and register_fentry, it is
>    possible that another module is loaded to the same address which may
>    lead to potential errors.
> 
> Since the attachment must contain the BTF of the program to attach to,
> we extract the module from it and search for the function address in the
> correct module (resolving problem no. 1). Then, the module reference is
> taken directly in bpf_check_attach_target and stored in the bpf program
> (in bpf_prog_aux). The reference is only released when the program is
> unloaded (resolving problem no. 2).
> 
> Signed-off-by: Viktor Malik <vmalik@redhat.com>
> ---
>  include/linux/bpf.h      |  1 +
>  kernel/bpf/syscall.c     |  2 ++
>  kernel/bpf/trampoline.c  | 27 ---------------------------
>  kernel/bpf/verifier.c    | 20 +++++++++++++++++++-
>  kernel/module/internal.h |  5 +++++
>  5 files changed, 27 insertions(+), 28 deletions(-)
> 
> diff --git a/include/linux/bpf.h b/include/linux/bpf.h
> index 4385418118f6..2aadc78fe3c1 100644
> --- a/include/linux/bpf.h
> +++ b/include/linux/bpf.h
> @@ -1330,6 +1330,7 @@ struct bpf_prog_aux {
>  	 * main prog always has linfo_idx == 0
>  	 */
>  	u32 linfo_idx;
> +	struct module *mod;
>  	u32 num_exentries;
>  	struct exception_table_entry *extable;
>  	union {
> diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
> index cda8d00f3762..5b8227e08182 100644
> --- a/kernel/bpf/syscall.c
> +++ b/kernel/bpf/syscall.c
> @@ -2064,6 +2064,8 @@ static void bpf_prog_put_deferred(struct work_struct *work)
>  	prog = aux->prog;
>  	perf_event_bpf_event(prog, PERF_BPF_EVENT_PROG_UNLOAD, 0);
>  	bpf_audit_prog(prog, BPF_AUDIT_UNLOAD);
> +	if (aux->mod)
> +		module_put(aux->mod);

you can call just module_put, there's != NULL check inside

also should we call it from __bpf_prog_put_noref instead
to cover bpf_prog_load error path?

>  	bpf_prog_free_id(prog);
>  	__bpf_prog_put_noref(prog, true);
>  }
> diff --git a/kernel/bpf/trampoline.c b/kernel/bpf/trampoline.c
> index d0ed7d6f5eec..ebb20bf252c7 100644
> --- a/kernel/bpf/trampoline.c
> +++ b/kernel/bpf/trampoline.c
> @@ -172,26 +172,6 @@ static struct bpf_trampoline *bpf_trampoline_lookup(u64 key)
>  	return tr;
>  }
>  
> -static int bpf_trampoline_module_get(struct bpf_trampoline *tr)
> -{
> -	struct module *mod;
> -	int err = 0;
> -
> -	preempt_disable();
> -	mod = __module_text_address((unsigned long) tr->func.addr);
> -	if (mod && !try_module_get(mod))
> -		err = -ENOENT;
> -	preempt_enable();
> -	tr->mod = mod;
> -	return err;
> -}
> -
> -static void bpf_trampoline_module_put(struct bpf_trampoline *tr)
> -{
> -	module_put(tr->mod);
> -	tr->mod = NULL;
> -}
> -
>  static int unregister_fentry(struct bpf_trampoline *tr, void *old_addr)
>  {
>  	void *ip = tr->func.addr;
> @@ -202,8 +182,6 @@ static int unregister_fentry(struct bpf_trampoline *tr, void *old_addr)
>  	else
>  		ret = bpf_arch_text_poke(ip, BPF_MOD_CALL, old_addr, NULL);
>  
> -	if (!ret)
> -		bpf_trampoline_module_put(tr);
>  	return ret;
>  }
>  
> @@ -238,9 +216,6 @@ static int register_fentry(struct bpf_trampoline *tr, void *new_addr)
>  		tr->func.ftrace_managed = true;
>  	}
>  
> -	if (bpf_trampoline_module_get(tr))
> -		return -ENOENT;
> -
>  	if (tr->func.ftrace_managed) {
>  		ftrace_set_filter_ip(tr->fops, (unsigned long)ip, 0, 1);
>  		ret = register_ftrace_direct_multi(tr->fops, (long)new_addr);
> @@ -248,8 +223,6 @@ static int register_fentry(struct bpf_trampoline *tr, void *new_addr)
>  		ret = bpf_arch_text_poke(ip, BPF_MOD_CALL, NULL, new_addr);
>  	}
>  
> -	if (ret)
> -		bpf_trampoline_module_put(tr);
>  	return ret;
>  }
>  
> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> index 388245e8826e..6a19bd450558 100644
> --- a/kernel/bpf/verifier.c
> +++ b/kernel/bpf/verifier.c
> @@ -24,6 +24,7 @@
>  #include <linux/bpf_lsm.h>
>  #include <linux/btf_ids.h>
>  #include <linux/poison.h>
> +#include "../module/internal.h"
>  
>  #include "disasm.h"
>  
> @@ -16868,6 +16869,7 @@ int bpf_check_attach_target(struct bpf_verifier_log *log,
>  	const char *tname;
>  	struct btf *btf;
>  	long addr = 0;
> +	struct module *mod = NULL;
>  
>  	if (!btf_id) {
>  		bpf_log(log, "Tracing programs must provide btf_id\n");
> @@ -17041,7 +17043,17 @@ int bpf_check_attach_target(struct bpf_verifier_log *log,
>  			else
>  				addr = (long) tgt_prog->aux->func[subprog]->bpf_func;
>  		} else {
> -			addr = kallsyms_lookup_name(tname);
> +			if (btf_is_module(btf)) {
> +				preempt_disable();

btf_try_get_module takes mutex, so you can't preempt_disable in here,
I got this when running the test:

[  691.916989][ T2585] BUG: sleeping function called from invalid context at kernel/locking/mutex.c:580

> +				mod = btf_try_get_module(btf);
> +				if (mod)
> +					addr = find_kallsyms_symbol_value(mod, tname);
> +				else
> +					addr = 0;
> +				preempt_enable();
> +			} else {
> +				addr = kallsyms_lookup_name(tname);
> +			}
>  			if (!addr) {
>  				bpf_log(log,
>  					"The address of function %s cannot be found\n",
> @@ -17105,6 +17117,12 @@ int bpf_check_attach_target(struct bpf_verifier_log *log,
>  	tgt_info->tgt_addr = addr;
>  	tgt_info->tgt_name = tname;
>  	tgt_info->tgt_type = t;
> +	if (mod) {
> +		if (!prog->aux->mod)
> +			prog->aux->mod = mod;

can this actually happen? would it be better to have bpf_check_attach_target
just to take take the module ref and return it in tgt_info->tgt_mod and it'd
be up to caller to decide what to do with that

thanks,
jirka

> +		else
> +			module_put(mod);
> +	}
>  	return 0;
>  }
>  
> diff --git a/kernel/module/internal.h b/kernel/module/internal.h
> index 2e2bf236f558..5cb103a46018 100644
> --- a/kernel/module/internal.h
> +++ b/kernel/module/internal.h
> @@ -256,6 +256,11 @@ static inline bool sect_empty(const Elf_Shdr *sect)
>  static inline void init_build_id(struct module *mod, const struct load_info *info) { }
>  static inline void layout_symtab(struct module *mod, struct load_info *info) { }
>  static inline void add_kallsyms(struct module *mod, const struct load_info *info) { }
> +static inline unsigned long find_kallsyms_symbol_value(struct module *mod
> +						       const char *name)
> +{
> +	return 0;
> +}
>  #endif /* CONFIG_KALLSYMS */
>  
>  #ifdef CONFIG_SYSFS
> -- 
> 2.39.1
> 

  reply	other threads:[~2023-02-16 13:50 UTC|newest]

Thread overview: 20+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-02-16 10:32 [PATCH bpf-next v6 0/2] Fix attaching fentry/fexit/fmod_ret/lsm to modules Viktor Malik
2023-02-16 10:32 ` [PATCH bpf-next v6 1/2] bpf: " Viktor Malik
2023-02-16 13:50   ` Jiri Olsa [this message]
2023-02-16 14:45     ` Viktor Malik
2023-02-16 15:50       ` Jiri Olsa
2023-03-22  9:49         ` Artem Savkov
2023-03-22 12:14           ` Jiri Olsa
2023-03-22 16:03             ` Alexei Starovoitov
2023-03-23 14:00               ` Jiri Olsa
2023-03-30  7:29                 ` Jiri Olsa
2023-03-30 12:26                   ` Leizhen (ThunderTown)
2023-03-30 20:59                     ` Jiri Olsa
2023-03-31  8:31                       ` Petr Mladek
2023-03-31  9:15                         ` Leizhen (ThunderTown)
2023-03-31 11:08                           ` Petr Mladek
2023-03-31 21:25                             ` Jiri Olsa
2023-04-03  1:46                               ` Leizhen (ThunderTown)
2023-04-03  8:46                                 ` Petr Mladek
2023-02-16 10:32 ` [PATCH bpf-next v6 2/2] bpf/selftests: Test fentry attachment to shadowed functions Viktor Malik
2023-02-16 23:55   ` Andrii Nakryiko

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=Y+40os27pQ8det/o@krava \
    --to=olsajiri@gmail.com \
    --cc=andrii@kernel.org \
    --cc=ast@kernel.org \
    --cc=bpf@vger.kernel.org \
    --cc=daniel@iogearbox.net \
    --cc=haoluo@google.com \
    --cc=john.fastabend@gmail.com \
    --cc=kpsingh@kernel.org \
    --cc=martin.lau@linux.dev \
    --cc=mcgrof@kernel.org \
    --cc=sdf@google.com \
    --cc=song@kernel.org \
    --cc=vmalik@redhat.com \
    --cc=yhs@fb.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