Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix attaching fentry/fexit/fmod_ret/lsm to modules #4159

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions include/linux/btf.h
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,7 @@ u32 btf_obj_id(const struct btf *btf);
bool btf_is_kernel(const struct btf *btf);
bool btf_is_module(const struct btf *btf);
struct module *btf_try_get_module(const struct btf *btf);
const char *btf_module_name(const struct btf *btf);
u32 btf_nr_types(const struct btf *btf);
bool btf_member_is_reg_int(const struct btf *btf, const struct btf_type *s,
const struct btf_member *m,
Expand Down
7 changes: 7 additions & 0 deletions include/linux/module.h
Original file line number Diff line number Diff line change
Expand Up @@ -605,6 +605,7 @@ struct module *find_module(const char *name);
int module_get_kallsym(unsigned int symnum, unsigned long *value, char *type,
char *name, char *module_name, int *exported);

unsigned long kallsyms_lookup_name_in_module(const char *module_name, const char *name);
/* Look for this name: can be of form module:name. */
unsigned long module_kallsyms_lookup_name(const char *name);

Expand Down Expand Up @@ -783,6 +784,12 @@ static inline int module_get_kallsym(unsigned int symnum, unsigned long *value,
return -ERANGE;
}

static inline unsigned long kallsyms_lookup_name_in_module(const char *module_name,
const char *name)
{
return 0;
}

static inline unsigned long module_kallsyms_lookup_name(const char *name)
{
return 0;
Expand Down
5 changes: 5 additions & 0 deletions kernel/bpf/btf.c
Original file line number Diff line number Diff line change
Expand Up @@ -7208,6 +7208,11 @@ bool btf_is_module(const struct btf *btf)
return btf->kernel_btf && strcmp(btf->name, "vmlinux") != 0;
}

const char *btf_module_name(const struct btf *btf)
{
return btf->name;
}

enum {
BTF_MODULE_F_LIVE = (1 << 0),
};
Expand Down
5 changes: 4 additions & 1 deletion kernel/bpf/verifier.c
Original file line number Diff line number Diff line change
Expand Up @@ -16483,7 +16483,10 @@ 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))
addr = kallsyms_lookup_name_in_module(btf_module_name(btf), tname);
else
addr = kallsyms_lookup_name(tname);
if (!addr) {
bpf_log(log,
"The address of function %s cannot be found\n",
Expand Down
16 changes: 16 additions & 0 deletions kernel/module/kallsyms.c
Original file line number Diff line number Diff line change
Expand Up @@ -482,6 +482,22 @@ static unsigned long __module_kallsyms_lookup_name(const char *name)
return 0;
}

unsigned long kallsyms_lookup_name_in_module(const char *module_name, const char *name)
{
unsigned long ret;
struct module *mod;

preempt_disable();
mod = find_module_all(module_name, strlen(module_name), false);
if (mod)
ret = find_kallsyms_symbol_value(mod, name);
else
ret = 0;
preempt_enable();
return ret;

}

/* Look for this name: can be of form module:name. */
unsigned long module_kallsyms_lookup_name(const char *name)
{
Expand Down
5 changes: 5 additions & 0 deletions net/bpf/test_run.c
Original file line number Diff line number Diff line change
Expand Up @@ -536,6 +536,11 @@ int noinline bpf_modify_return_test(int a, int *b)
return a + *b;
}

int noinline bpf_fentry_shadow_test(int a)
{
return a + 1;
}

u64 noinline bpf_kfunc_call_test1(struct sock *sk, u32 a, u64 b, u32 c, u64 d)
{
return a + b + c + d;
Expand Down
7 changes: 7 additions & 0 deletions tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.c
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,13 @@ static const struct btf_kfunc_id_set bpf_testmod_kfunc_set = {
.set = &bpf_testmod_check_kfunc_ids,
};

noinline int bpf_fentry_shadow_test(int a)
{
return a + 2;
}
EXPORT_SYMBOL_GPL(bpf_fentry_shadow_test);
ALLOW_ERROR_INJECTION(bpf_fentry_shadow_test, ERRNO);

extern int bpf_fentry_test1(int a);

static int bpf_testmod_init(void)
Expand Down
124 changes: 124 additions & 0 deletions tools/testing/selftests/bpf/prog_tests/module_attach_shadow.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2022 Red Hat */
#include <test_progs.h>
#include <bpf/btf.h>
#include "bpf/libbpf_internal.h"
#include "cgroup_helpers.h"

static const char *module_name = "bpf_testmod";
static const char *symbol_name = "bpf_fentry_shadow_test";

int get_bpf_testmod_btf_fd(void)
{
struct bpf_btf_info info;
char name[64];
__u32 id = 0, len;
int err, fd;

while (true) {
err = bpf_btf_get_next_id(id, &id);
if (err) {
log_err("failed to iterate BTF objects");
return err;
}

fd = bpf_btf_get_fd_by_id(id);
if (fd < 0) {
err = -errno;
log_err("failed to get FD for BTF object #%d", id);
return err;
}

len = sizeof(info);
memset(&info, 0, sizeof(info));
info.name = ptr_to_u64(name);
info.name_len = sizeof(name);

err = bpf_obj_get_info_by_fd(fd, &info, &len);
if (err) {
err = -errno;
log_err("failed to get info for BTF object #%d", id);
close(fd);
return err;
}

if (strcmp(name, module_name) == 0)
return fd;

close(fd);
}
return -ENOENT;
}

void test_module_fentry_shadow(void)
{
struct btf *vmlinux_btf = NULL, *mod_btf = NULL;
int err, i;
int btf_fd[2] = {};
int prog_fd[2] = {};
int link_fd[2] = {};
__s32 btf_id[2] = {};

const struct bpf_insn trace_program[] = {
BPF_MOV64_IMM(BPF_REG_0, 0),
BPF_EXIT_INSN(),
};

LIBBPF_OPTS(bpf_prog_load_opts, load_opts,
.expected_attach_type = BPF_TRACE_FENTRY,
);

LIBBPF_OPTS(bpf_test_run_opts, test_opts);

vmlinux_btf = btf__load_vmlinux_btf();
if (!ASSERT_OK_PTR(vmlinux_btf, "load_vmlinux_btf"))
return;

btf_fd[1] = get_bpf_testmod_btf_fd();
if (!ASSERT_GT(btf_fd[1], 0, "get_bpf_testmod_btf_fd"))
goto out;

mod_btf = btf_get_from_fd(btf_fd[1], vmlinux_btf);
if (!ASSERT_OK_PTR(mod_btf, "btf_get_from_fd"))
goto out;

btf_id[0] = btf__find_by_name_kind(vmlinux_btf, symbol_name, BTF_KIND_FUNC);
if (!ASSERT_GT(btf_id[0], 0, "btf_find_by_name"))
goto out;

btf_id[1] = btf__find_by_name_kind(mod_btf, symbol_name, BTF_KIND_FUNC);
if (!ASSERT_GT(btf_id[1], 0, "btf_find_by_name"))
goto out;

for (i = 0; i < 2; i++) {
load_opts.attach_btf_id = btf_id[i];
load_opts.attach_btf_obj_fd = btf_fd[i];
prog_fd[i] = bpf_prog_load(BPF_PROG_TYPE_TRACING, NULL, "GPL",
trace_program,
sizeof(trace_program) / sizeof(struct bpf_insn),
&load_opts);
if (!ASSERT_GE(prog_fd[i], 0, "bpf_prog_load"))
goto out;

link_fd[i] = bpf_link_create(prog_fd[i], 0, BPF_TRACE_FENTRY, NULL);
if (!ASSERT_GE(link_fd[i], 0, "bpf_link_create"))
goto out;
}

err = bpf_prog_test_run_opts(prog_fd[0], &test_opts);
ASSERT_OK(err, "running test");

out:
if (vmlinux_btf)
btf__free(vmlinux_btf);
if (mod_btf)
btf__free(mod_btf);
for (i = 0; i < 2; i++) {
if (btf_fd[i])
close(btf_fd[i]);
if (prog_fd[i])
close(prog_fd[i]);
if (link_fd[i])
close(link_fd[i]);
}
}