--- /dev/null
+From stable-owner@vger.kernel.org Fri Dec 16 13:57:05 2022
+From: Jiri Olsa <jolsa@kernel.org>
+Date: Fri, 16 Dec 2022 13:56:23 +0100
+Subject: bpf: Rename __bpf_kprobe_multi_cookie_cmp to bpf_kprobe_multi_addrs_cmp
+To: stable@vger.kernel.org
+Cc: Song Liu <song@kernel.org>, bpf@vger.kernel.org, Martynas Pumputis <m@lambda.lt>
+Message-ID: <20221216125628.1622505-4-jolsa@kernel.org>
+
+From: Jiri Olsa <jolsa@kernel.org>
+
+commit 1a1b0716d36d21f8448bd7d3f1c0ade7230bb294 upstream.
+
+Renaming __bpf_kprobe_multi_cookie_cmp to bpf_kprobe_multi_addrs_cmp,
+because it's more suitable to current and upcoming code.
+
+Acked-by: Song Liu <song@kernel.org>
+Signed-off-by: Jiri Olsa <jolsa@kernel.org>
+Link: https://lore.kernel.org/r/20221025134148.3300700-4-jolsa@kernel.org
+Signed-off-by: Alexei Starovoitov <ast@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ kernel/trace/bpf_trace.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+--- a/kernel/trace/bpf_trace.c
++++ b/kernel/trace/bpf_trace.c
+@@ -2362,7 +2362,7 @@ static void bpf_kprobe_multi_cookie_swap
+ swap(*cookie_a, *cookie_b);
+ }
+
+-static int __bpf_kprobe_multi_cookie_cmp(const void *a, const void *b)
++static int bpf_kprobe_multi_addrs_cmp(const void *a, const void *b)
+ {
+ const unsigned long *addr_a = a, *addr_b = b;
+
+@@ -2373,7 +2373,7 @@ static int __bpf_kprobe_multi_cookie_cmp
+
+ static int bpf_kprobe_multi_cookie_cmp(const void *a, const void *b, const void *priv)
+ {
+- return __bpf_kprobe_multi_cookie_cmp(a, b);
++ return bpf_kprobe_multi_addrs_cmp(a, b);
+ }
+
+ static u64 bpf_kprobe_multi_cookie(struct bpf_run_ctx *ctx)
+@@ -2391,7 +2391,7 @@ static u64 bpf_kprobe_multi_cookie(struc
+ return 0;
+ entry_ip = run_ctx->entry_ip;
+ addr = bsearch(&entry_ip, link->addrs, link->cnt, sizeof(entry_ip),
+- __bpf_kprobe_multi_cookie_cmp);
++ bpf_kprobe_multi_addrs_cmp);
+ if (!addr)
+ return 0;
+ cookie = link->cookies + (addr - link->addrs);
--- /dev/null
+From stable-owner@vger.kernel.org Fri Dec 16 13:57:18 2022
+From: Jiri Olsa <jolsa@kernel.org>
+Date: Fri, 16 Dec 2022 13:56:24 +0100
+Subject: bpf: Take module reference on kprobe_multi link
+To: stable@vger.kernel.org
+Cc: Andrii Nakryiko <andrii@kernel.org>, bpf@vger.kernel.org, Martynas Pumputis <m@lambda.lt>
+Message-ID: <20221216125628.1622505-5-jolsa@kernel.org>
+
+From: Jiri Olsa <jolsa@kernel.org>
+
+commit e22061b2d3095c12f90336479f24bf5eeb70e1bd upstream.
+
+Currently we allow to create kprobe multi link on function from kernel
+module, but we don't take the module reference to ensure it's not
+unloaded while we are tracing it.
+
+The multi kprobe link is based on fprobe/ftrace layer which takes
+different approach and releases ftrace hooks when module is unloaded
+even if there's tracer registered on top of it.
+
+Adding code that gathers all the related modules for the link and takes
+their references before it's attached. All kernel module references are
+released after link is unregistered.
+
+Note that we do it the same way already for trampoline probes
+(but for single address).
+
+Acked-by: Andrii Nakryiko <andrii@kernel.org>
+Signed-off-by: Jiri Olsa <jolsa@kernel.org>
+Link: https://lore.kernel.org/r/20221025134148.3300700-5-jolsa@kernel.org
+Signed-off-by: Alexei Starovoitov <ast@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ kernel/trace/bpf_trace.c | 92 +++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 92 insertions(+)
+
+--- a/kernel/trace/bpf_trace.c
++++ b/kernel/trace/bpf_trace.c
+@@ -2264,6 +2264,8 @@ struct bpf_kprobe_multi_link {
+ unsigned long *addrs;
+ u64 *cookies;
+ u32 cnt;
++ u32 mods_cnt;
++ struct module **mods;
+ };
+
+ struct bpf_kprobe_multi_run_ctx {
+@@ -2319,6 +2321,14 @@ error:
+ return err;
+ }
+
++static void kprobe_multi_put_modules(struct module **mods, u32 cnt)
++{
++ u32 i;
++
++ for (i = 0; i < cnt; i++)
++ module_put(mods[i]);
++}
++
+ static void free_user_syms(struct user_syms *us)
+ {
+ kvfree(us->syms);
+@@ -2331,6 +2341,7 @@ static void bpf_kprobe_multi_link_releas
+
+ kmulti_link = container_of(link, struct bpf_kprobe_multi_link, link);
+ unregister_fprobe(&kmulti_link->fp);
++ kprobe_multi_put_modules(kmulti_link->mods, kmulti_link->mods_cnt);
+ }
+
+ static void bpf_kprobe_multi_link_dealloc(struct bpf_link *link)
+@@ -2340,6 +2351,7 @@ static void bpf_kprobe_multi_link_deallo
+ kmulti_link = container_of(link, struct bpf_kprobe_multi_link, link);
+ kvfree(kmulti_link->addrs);
+ kvfree(kmulti_link->cookies);
++ kfree(kmulti_link->mods);
+ kfree(kmulti_link);
+ }
+
+@@ -2475,6 +2487,71 @@ static void symbols_swap_r(void *a, void
+ }
+ }
+
++struct module_addr_args {
++ unsigned long *addrs;
++ u32 addrs_cnt;
++ struct module **mods;
++ int mods_cnt;
++ int mods_cap;
++};
++
++static int module_callback(void *data, const char *name,
++ struct module *mod, unsigned long addr)
++{
++ struct module_addr_args *args = data;
++ struct module **mods;
++
++ /* We iterate all modules symbols and for each we:
++ * - search for it in provided addresses array
++ * - if found we check if we already have the module pointer stored
++ * (we iterate modules sequentially, so we can check just the last
++ * module pointer)
++ * - take module reference and store it
++ */
++ if (!bsearch(&addr, args->addrs, args->addrs_cnt, sizeof(addr),
++ bpf_kprobe_multi_addrs_cmp))
++ return 0;
++
++ if (args->mods && args->mods[args->mods_cnt - 1] == mod)
++ return 0;
++
++ if (args->mods_cnt == args->mods_cap) {
++ args->mods_cap = max(16, args->mods_cap * 3 / 2);
++ mods = krealloc_array(args->mods, args->mods_cap, sizeof(*mods), GFP_KERNEL);
++ if (!mods)
++ return -ENOMEM;
++ args->mods = mods;
++ }
++
++ if (!try_module_get(mod))
++ return -EINVAL;
++
++ args->mods[args->mods_cnt] = mod;
++ args->mods_cnt++;
++ return 0;
++}
++
++static int get_modules_for_addrs(struct module ***mods, unsigned long *addrs, u32 addrs_cnt)
++{
++ struct module_addr_args args = {
++ .addrs = addrs,
++ .addrs_cnt = addrs_cnt,
++ };
++ int err;
++
++ /* We return either err < 0 in case of error, ... */
++ err = module_kallsyms_on_each_symbol(module_callback, &args);
++ if (err) {
++ kprobe_multi_put_modules(args.mods, args.mods_cnt);
++ kfree(args.mods);
++ return err;
++ }
++
++ /* or number of modules found if everything is ok. */
++ *mods = args.mods;
++ return args.mods_cnt;
++}
++
+ int bpf_kprobe_multi_link_attach(const union bpf_attr *attr, struct bpf_prog *prog)
+ {
+ struct bpf_kprobe_multi_link *link = NULL;
+@@ -2585,10 +2662,25 @@ int bpf_kprobe_multi_link_attach(const u
+ bpf_kprobe_multi_cookie_cmp,
+ bpf_kprobe_multi_cookie_swap,
+ link);
++ } else {
++ /*
++ * We need to sort addrs array even if there are no cookies
++ * provided, to allow bsearch in get_modules_for_addrs.
++ */
++ sort(addrs, cnt, sizeof(*addrs),
++ bpf_kprobe_multi_addrs_cmp, NULL);
++ }
++
++ err = get_modules_for_addrs(&link->mods, addrs, cnt);
++ if (err < 0) {
++ bpf_link_cleanup(&link_primer);
++ return err;
+ }
++ link->mods_cnt = err;
+
+ err = register_fprobe_ips(&link->fp, addrs, cnt);
+ if (err) {
++ kprobe_multi_put_modules(link->mods, link->mods_cnt);
+ bpf_link_cleanup(&link_primer);
+ return err;
+ }
--- /dev/null
+From stable-owner@vger.kernel.org Fri Dec 16 13:57:01 2022
+From: Jiri Olsa <jolsa@kernel.org>
+Date: Fri, 16 Dec 2022 13:56:22 +0100
+Subject: ftrace: Add support to resolve module symbols in ftrace_lookup_symbols
+To: stable@vger.kernel.org
+Cc: Martynas Pumputis <m@lambda.lt>, Song Liu <song@kernel.org>, bpf@vger.kernel.org
+Message-ID: <20221216125628.1622505-3-jolsa@kernel.org>
+
+From: Jiri Olsa <jolsa@kernel.org>
+
+commit 3640bf8584f4ab0f5eed6285f09213954acd8b62 upstream.
+
+Currently ftrace_lookup_symbols iterates only over core symbols,
+adding module_kallsyms_on_each_symbol call to check on modules
+symbols as well.
+
+Also removing 'args.found == args.cnt' condition, because it's
+already checked in kallsyms_callback function.
+
+Also removing 'err < 0' check, because both *kallsyms_on_each_symbol
+functions do not return error.
+
+Reported-by: Martynas Pumputis <m@lambda.lt>
+Acked-by: Song Liu <song@kernel.org>
+Signed-off-by: Jiri Olsa <jolsa@kernel.org>
+Link: https://lore.kernel.org/r/20221025134148.3300700-3-jolsa@kernel.org
+Signed-off-by: Alexei Starovoitov <ast@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ kernel/trace/ftrace.c | 16 +++++++++++-----
+ 1 file changed, 11 insertions(+), 5 deletions(-)
+
+--- a/kernel/trace/ftrace.c
++++ b/kernel/trace/ftrace.c
+@@ -8261,6 +8261,10 @@ struct kallsyms_data {
+ size_t found;
+ };
+
++/* This function gets called for all kernel and module symbols
++ * and returns 1 in case we resolved all the requested symbols,
++ * 0 otherwise.
++ */
+ static int kallsyms_callback(void *data, const char *name,
+ struct module *mod, unsigned long addr)
+ {
+@@ -8304,17 +8308,19 @@ static int kallsyms_callback(void *data,
+ int ftrace_lookup_symbols(const char **sorted_syms, size_t cnt, unsigned long *addrs)
+ {
+ struct kallsyms_data args;
+- int err;
++ int found_all;
+
+ memset(addrs, 0, sizeof(*addrs) * cnt);
+ args.addrs = addrs;
+ args.syms = sorted_syms;
+ args.cnt = cnt;
+ args.found = 0;
+- err = kallsyms_on_each_symbol(kallsyms_callback, &args);
+- if (err < 0)
+- return err;
+- return args.found == args.cnt ? 0 : -ESRCH;
++
++ found_all = kallsyms_on_each_symbol(kallsyms_callback, &args);
++ if (found_all)
++ return 0;
++ found_all = module_kallsyms_on_each_symbol(kallsyms_callback, &args);
++ return found_all ? 0 : -ESRCH;
+ }
+
+ #ifdef CONFIG_SYSCTL
--- /dev/null
+From stable-owner@vger.kernel.org Fri Dec 16 13:56:47 2022
+From: Jiri Olsa <jolsa@kernel.org>
+Date: Fri, 16 Dec 2022 13:56:21 +0100
+Subject: kallsyms: Make module_kallsyms_on_each_symbol generally available
+To: stable@vger.kernel.org
+Cc: Christoph Hellwig <hch@lst.de>, Song Liu <song@kernel.org>, bpf@vger.kernel.org, Martynas Pumputis <m@lambda.lt>
+Message-ID: <20221216125628.1622505-2-jolsa@kernel.org>
+
+From: Jiri Olsa <jolsa@kernel.org>
+
+commit 73feb8d5fa3b755bb51077c0aabfb6aa556fd498 upstream.
+
+Making module_kallsyms_on_each_symbol generally available, so it
+can be used outside CONFIG_LIVEPATCH option in following changes.
+
+Rather than adding another ifdef option let's make the function
+generally available (when CONFIG_KALLSYMS and CONFIG_MODULES
+options are defined).
+
+Cc: Christoph Hellwig <hch@lst.de>
+Acked-by: Song Liu <song@kernel.org>
+Signed-off-by: Jiri Olsa <jolsa@kernel.org>
+Link: https://lore.kernel.org/r/20221025134148.3300700-2-jolsa@kernel.org
+Signed-off-by: Alexei Starovoitov <ast@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ include/linux/module.h | 9 +++++++++
+ kernel/module/kallsyms.c | 2 --
+ 2 files changed, 9 insertions(+), 2 deletions(-)
+
+--- a/include/linux/module.h
++++ b/include/linux/module.h
+@@ -879,8 +879,17 @@ static inline bool module_sig_ok(struct
+ }
+ #endif /* CONFIG_MODULE_SIG */
+
++#if defined(CONFIG_MODULES) && defined(CONFIG_KALLSYMS)
+ int module_kallsyms_on_each_symbol(int (*fn)(void *, const char *,
+ struct module *, unsigned long),
+ void *data);
++#else
++static inline int module_kallsyms_on_each_symbol(int (*fn)(void *, const char *,
++ struct module *, unsigned long),
++ void *data)
++{
++ return -EOPNOTSUPP;
++}
++#endif /* CONFIG_MODULES && CONFIG_KALLSYMS */
+
+ #endif /* _LINUX_MODULE_H */
+--- a/kernel/module/kallsyms.c
++++ b/kernel/module/kallsyms.c
+@@ -494,7 +494,6 @@ unsigned long module_kallsyms_lookup_nam
+ return ret;
+ }
+
+-#ifdef CONFIG_LIVEPATCH
+ int module_kallsyms_on_each_symbol(int (*fn)(void *, const char *,
+ struct module *, unsigned long),
+ void *data)
+@@ -531,4 +530,3 @@ out:
+ mutex_unlock(&module_mutex);
+ return ret;
+ }
+-#endif /* CONFIG_LIVEPATCH */
--- /dev/null
+From stable-owner@vger.kernel.org Fri Dec 16 13:57:32 2022
+From: Jiri Olsa <jolsa@kernel.org>
+Date: Fri, 16 Dec 2022 13:56:26 +0100
+Subject: selftests/bpf: Add bpf_testmod_fentry_* functions
+To: stable@vger.kernel.org
+Cc: Song Liu <song@kernel.org>, bpf@vger.kernel.org, Martynas Pumputis <m@lambda.lt>
+Message-ID: <20221216125628.1622505-7-jolsa@kernel.org>
+
+From: Jiri Olsa <jolsa@kernel.org>
+
+commit fee356ede980b6c2c8db612e18b25738356d6744 upstream.
+
+Adding 3 bpf_testmod_fentry_* functions to have a way to test
+kprobe multi link on kernel module. They follow bpf_fentry_test*
+functions prototypes/code.
+
+Adding equivalent functions to all bpf_fentry_test* does not
+seems necessary at the moment, could be added later.
+
+Acked-by: Song Liu <song@kernel.org>
+Signed-off-by: Jiri Olsa <jolsa@kernel.org>
+Link: https://lore.kernel.org/r/20221025134148.3300700-7-jolsa@kernel.org
+Signed-off-by: Alexei Starovoitov <ast@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.c | 24 ++++++++++++++++++
+ 1 file changed, 24 insertions(+)
+
+--- a/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.c
++++ b/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.c
+@@ -88,6 +88,23 @@ __weak noinline struct file *bpf_testmod
+ }
+ }
+
++noinline int bpf_testmod_fentry_test1(int a)
++{
++ return a + 1;
++}
++
++noinline int bpf_testmod_fentry_test2(int a, u64 b)
++{
++ return a + b;
++}
++
++noinline int bpf_testmod_fentry_test3(char a, int b, u64 c)
++{
++ return a + b + c;
++}
++
++int bpf_testmod_fentry_ok;
++
+ noinline ssize_t
+ bpf_testmod_test_read(struct file *file, struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+@@ -119,6 +136,13 @@ bpf_testmod_test_read(struct file *file,
+ return snprintf(buf, len, "%d\n", writable.val);
+ }
+
++ if (bpf_testmod_fentry_test1(1) != 2 ||
++ bpf_testmod_fentry_test2(2, 3) != 5 ||
++ bpf_testmod_fentry_test3(4, 5, 6) != 15)
++ goto out;
++
++ bpf_testmod_fentry_ok = 1;
++out:
+ return -EIO; /* always fail */
+ }
+ EXPORT_SYMBOL(bpf_testmod_test_read);
--- /dev/null
+From stable-owner@vger.kernel.org Fri Dec 16 13:57:41 2022
+From: Jiri Olsa <jolsa@kernel.org>
+Date: Fri, 16 Dec 2022 13:56:27 +0100
+Subject: selftests/bpf: Add kprobe_multi check to module attach test
+To: stable@vger.kernel.org
+Cc: Song Liu <song@kernel.org>, bpf@vger.kernel.org, Martynas Pumputis <m@lambda.lt>
+Message-ID: <20221216125628.1622505-8-jolsa@kernel.org>
+
+From: Jiri Olsa <jolsa@kernel.org>
+
+commit e697d8dcebd2f557fa5e5ed57aaf0a9992ce9df8 upstream.
+
+Adding test that makes sure the kernel module won't be removed
+if there's kprobe multi link defined on top of it.
+
+Acked-by: Song Liu <song@kernel.org>
+Signed-off-by: Jiri Olsa <jolsa@kernel.org>
+Link: https://lore.kernel.org/r/20221025134148.3300700-8-jolsa@kernel.org
+Signed-off-by: Alexei Starovoitov <ast@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ tools/testing/selftests/bpf/prog_tests/module_attach.c | 7 +++++++
+ tools/testing/selftests/bpf/progs/test_module_attach.c | 6 ++++++
+ 2 files changed, 13 insertions(+)
+
+--- a/tools/testing/selftests/bpf/prog_tests/module_attach.c
++++ b/tools/testing/selftests/bpf/prog_tests/module_attach.c
+@@ -103,6 +103,13 @@ void test_module_attach(void)
+ ASSERT_ERR(delete_module("bpf_testmod", 0), "delete_module");
+ bpf_link__destroy(link);
+
++ link = bpf_program__attach(skel->progs.kprobe_multi);
++ if (!ASSERT_OK_PTR(link, "attach_kprobe_multi"))
++ goto cleanup;
++
++ ASSERT_ERR(delete_module("bpf_testmod", 0), "delete_module");
++ bpf_link__destroy(link);
++
+ cleanup:
+ test_module_attach__destroy(skel);
+ }
+--- a/tools/testing/selftests/bpf/progs/test_module_attach.c
++++ b/tools/testing/selftests/bpf/progs/test_module_attach.c
+@@ -110,4 +110,10 @@ int BPF_PROG(handle_fmod_ret,
+ return 0; /* don't override the exit code */
+ }
+
++SEC("kprobe.multi/bpf_testmod_test_read")
++int BPF_PROG(kprobe_multi)
++{
++ return 0;
++}
++
+ char _license[] SEC("license") = "GPL";
--- /dev/null
+From stable-owner@vger.kernel.org Fri Dec 16 13:57:50 2022
+From: Jiri Olsa <jolsa@kernel.org>
+Date: Fri, 16 Dec 2022 13:56:28 +0100
+Subject: selftests/bpf: Add kprobe_multi kmod attach api tests
+To: stable@vger.kernel.org
+Cc: Song Liu <song@kernel.org>, bpf@vger.kernel.org, Martynas Pumputis <m@lambda.lt>
+Message-ID: <20221216125628.1622505-9-jolsa@kernel.org>
+
+From: Jiri Olsa <jolsa@kernel.org>
+
+commit be884a22c1c835a146e97c6ab282a2b31b002e1f upstream.
+
+Adding kprobe_multi kmod attach api tests that attach bpf_testmod
+functions via bpf_program__attach_kprobe_multi_opts.
+
+Running it as serial test, because we don't want other tests to
+reload bpf_testmod while it's running.
+
+Acked-by: Song Liu <song@kernel.org>
+Signed-off-by: Jiri Olsa <jolsa@kernel.org>
+Link: https://lore.kernel.org/r/20221025134148.3300700-9-jolsa@kernel.org
+Signed-off-by: Alexei Starovoitov <ast@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ tools/testing/selftests/bpf/prog_tests/kprobe_multi_testmod_test.c | 89 ++++++++++
+ tools/testing/selftests/bpf/progs/kprobe_multi.c | 50 +++++
+ 2 files changed, 139 insertions(+)
+ create mode 100644 tools/testing/selftests/bpf/prog_tests/kprobe_multi_testmod_test.c
+
+--- /dev/null
++++ b/tools/testing/selftests/bpf/prog_tests/kprobe_multi_testmod_test.c
+@@ -0,0 +1,89 @@
++// SPDX-License-Identifier: GPL-2.0
++#include <test_progs.h>
++#include "kprobe_multi.skel.h"
++#include "trace_helpers.h"
++#include "bpf/libbpf_internal.h"
++
++static void kprobe_multi_testmod_check(struct kprobe_multi *skel)
++{
++ ASSERT_EQ(skel->bss->kprobe_testmod_test1_result, 1, "kprobe_test1_result");
++ ASSERT_EQ(skel->bss->kprobe_testmod_test2_result, 1, "kprobe_test2_result");
++ ASSERT_EQ(skel->bss->kprobe_testmod_test3_result, 1, "kprobe_test3_result");
++
++ ASSERT_EQ(skel->bss->kretprobe_testmod_test1_result, 1, "kretprobe_test1_result");
++ ASSERT_EQ(skel->bss->kretprobe_testmod_test2_result, 1, "kretprobe_test2_result");
++ ASSERT_EQ(skel->bss->kretprobe_testmod_test3_result, 1, "kretprobe_test3_result");
++}
++
++static void test_testmod_attach_api(struct bpf_kprobe_multi_opts *opts)
++{
++ struct kprobe_multi *skel = NULL;
++
++ skel = kprobe_multi__open_and_load();
++ if (!ASSERT_OK_PTR(skel, "fentry_raw_skel_load"))
++ return;
++
++ skel->bss->pid = getpid();
++
++ skel->links.test_kprobe_testmod = bpf_program__attach_kprobe_multi_opts(
++ skel->progs.test_kprobe_testmod,
++ NULL, opts);
++ if (!skel->links.test_kprobe_testmod)
++ goto cleanup;
++
++ opts->retprobe = true;
++ skel->links.test_kretprobe_testmod = bpf_program__attach_kprobe_multi_opts(
++ skel->progs.test_kretprobe_testmod,
++ NULL, opts);
++ if (!skel->links.test_kretprobe_testmod)
++ goto cleanup;
++
++ ASSERT_OK(trigger_module_test_read(1), "trigger_read");
++ kprobe_multi_testmod_check(skel);
++
++cleanup:
++ kprobe_multi__destroy(skel);
++}
++
++static void test_testmod_attach_api_addrs(void)
++{
++ LIBBPF_OPTS(bpf_kprobe_multi_opts, opts);
++ unsigned long long addrs[3];
++
++ addrs[0] = ksym_get_addr("bpf_testmod_fentry_test1");
++ ASSERT_NEQ(addrs[0], 0, "ksym_get_addr");
++ addrs[1] = ksym_get_addr("bpf_testmod_fentry_test2");
++ ASSERT_NEQ(addrs[1], 0, "ksym_get_addr");
++ addrs[2] = ksym_get_addr("bpf_testmod_fentry_test3");
++ ASSERT_NEQ(addrs[2], 0, "ksym_get_addr");
++
++ opts.addrs = (const unsigned long *) addrs;
++ opts.cnt = ARRAY_SIZE(addrs);
++
++ test_testmod_attach_api(&opts);
++}
++
++static void test_testmod_attach_api_syms(void)
++{
++ LIBBPF_OPTS(bpf_kprobe_multi_opts, opts);
++ const char *syms[3] = {
++ "bpf_testmod_fentry_test1",
++ "bpf_testmod_fentry_test2",
++ "bpf_testmod_fentry_test3",
++ };
++
++ opts.syms = syms;
++ opts.cnt = ARRAY_SIZE(syms);
++ test_testmod_attach_api(&opts);
++}
++
++void serial_test_kprobe_multi_testmod_test(void)
++{
++ if (!ASSERT_OK(load_kallsyms_refresh(), "load_kallsyms_refresh"))
++ return;
++
++ if (test__start_subtest("testmod_attach_api_syms"))
++ test_testmod_attach_api_syms();
++ if (test__start_subtest("testmod_attach_api_addrs"))
++ test_testmod_attach_api_addrs();
++}
+--- a/tools/testing/selftests/bpf/progs/kprobe_multi.c
++++ b/tools/testing/selftests/bpf/progs/kprobe_multi.c
+@@ -110,3 +110,53 @@ int test_kretprobe_manual(struct pt_regs
+ kprobe_multi_check(ctx, true);
+ return 0;
+ }
++
++extern const void bpf_testmod_fentry_test1 __ksym;
++extern const void bpf_testmod_fentry_test2 __ksym;
++extern const void bpf_testmod_fentry_test3 __ksym;
++
++__u64 kprobe_testmod_test1_result = 0;
++__u64 kprobe_testmod_test2_result = 0;
++__u64 kprobe_testmod_test3_result = 0;
++
++__u64 kretprobe_testmod_test1_result = 0;
++__u64 kretprobe_testmod_test2_result = 0;
++__u64 kretprobe_testmod_test3_result = 0;
++
++static void kprobe_multi_testmod_check(void *ctx, bool is_return)
++{
++ if (bpf_get_current_pid_tgid() >> 32 != pid)
++ return;
++
++ __u64 addr = bpf_get_func_ip(ctx);
++
++ if (is_return) {
++ if ((const void *) addr == &bpf_testmod_fentry_test1)
++ kretprobe_testmod_test1_result = 1;
++ if ((const void *) addr == &bpf_testmod_fentry_test2)
++ kretprobe_testmod_test2_result = 1;
++ if ((const void *) addr == &bpf_testmod_fentry_test3)
++ kretprobe_testmod_test3_result = 1;
++ } else {
++ if ((const void *) addr == &bpf_testmod_fentry_test1)
++ kprobe_testmod_test1_result = 1;
++ if ((const void *) addr == &bpf_testmod_fentry_test2)
++ kprobe_testmod_test2_result = 1;
++ if ((const void *) addr == &bpf_testmod_fentry_test3)
++ kprobe_testmod_test3_result = 1;
++ }
++}
++
++SEC("kprobe.multi")
++int test_kprobe_testmod(struct pt_regs *ctx)
++{
++ kprobe_multi_testmod_check(ctx, false);
++ return 0;
++}
++
++SEC("kretprobe.multi")
++int test_kretprobe_testmod(struct pt_regs *ctx)
++{
++ kprobe_multi_testmod_check(ctx, true);
++ return 0;
++}
--- /dev/null
+From stable-owner@vger.kernel.org Fri Dec 16 13:57:23 2022
+From: Jiri Olsa <jolsa@kernel.org>
+Date: Fri, 16 Dec 2022 13:56:25 +0100
+Subject: selftests/bpf: Add load_kallsyms_refresh function
+To: stable@vger.kernel.org
+Cc: Song Liu <song@kernel.org>, bpf@vger.kernel.org, Martynas Pumputis <m@lambda.lt>
+Message-ID: <20221216125628.1622505-6-jolsa@kernel.org>
+
+From: Jiri Olsa <jolsa@kernel.org>
+
+commit 10705b2b7a8e4eb46ab5bf1b9ee354cb9a929428 upstream.
+
+Adding load_kallsyms_refresh function to re-read symbols from
+/proc/kallsyms file.
+
+This will be needed to get proper functions addresses from
+bpf_testmod.ko module, which is loaded/unloaded several times
+during the tests run, so symbols might be already old when
+we need to use them.
+
+Acked-by: Song Liu <song@kernel.org>
+Signed-off-by: Jiri Olsa <jolsa@kernel.org>
+Link: https://lore.kernel.org/r/20221025134148.3300700-6-jolsa@kernel.org
+Signed-off-by: Alexei Starovoitov <ast@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ tools/testing/selftests/bpf/trace_helpers.c | 20 +++++++++++++-------
+ tools/testing/selftests/bpf/trace_helpers.h | 2 ++
+ 2 files changed, 15 insertions(+), 7 deletions(-)
+
+--- a/tools/testing/selftests/bpf/trace_helpers.c
++++ b/tools/testing/selftests/bpf/trace_helpers.c
+@@ -23,7 +23,7 @@ static int ksym_cmp(const void *p1, cons
+ return ((struct ksym *)p1)->addr - ((struct ksym *)p2)->addr;
+ }
+
+-int load_kallsyms(void)
++int load_kallsyms_refresh(void)
+ {
+ FILE *f;
+ char func[256], buf[256];
+@@ -31,12 +31,7 @@ int load_kallsyms(void)
+ void *addr;
+ int i = 0;
+
+- /*
+- * This is called/used from multiplace places,
+- * load symbols just once.
+- */
+- if (sym_cnt)
+- return 0;
++ sym_cnt = 0;
+
+ f = fopen("/proc/kallsyms", "r");
+ if (!f)
+@@ -57,6 +52,17 @@ int load_kallsyms(void)
+ return 0;
+ }
+
++int load_kallsyms(void)
++{
++ /*
++ * This is called/used from multiplace places,
++ * load symbols just once.
++ */
++ if (sym_cnt)
++ return 0;
++ return load_kallsyms_refresh();
++}
++
+ struct ksym *ksym_search(long key)
+ {
+ int start = 0, end = sym_cnt;
+--- a/tools/testing/selftests/bpf/trace_helpers.h
++++ b/tools/testing/selftests/bpf/trace_helpers.h
+@@ -10,6 +10,8 @@ struct ksym {
+ };
+
+ int load_kallsyms(void);
++int load_kallsyms_refresh(void);
++
+ struct ksym *ksym_search(long key);
+ long ksym_get_addr(const char *name);
+
pci-mt7621-add-sentinel-to-quirks-table.patch
+kallsyms-make-module_kallsyms_on_each_symbol-generally-available.patch
+ftrace-add-support-to-resolve-module-symbols-in-ftrace_lookup_symbols.patch
+bpf-rename-__bpf_kprobe_multi_cookie_cmp-to-bpf_kprobe_multi_addrs_cmp.patch
+bpf-take-module-reference-on-kprobe_multi-link.patch
+selftests-bpf-add-load_kallsyms_refresh-function.patch
+selftests-bpf-add-bpf_testmod_fentry_-functions.patch
+selftests-bpf-add-kprobe_multi-check-to-module-attach-test.patch
+selftests-bpf-add-kprobe_multi-kmod-attach-api-tests.patch