mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-10-03 23:58:05 +00:00
Merge branch 'Add _opts variant for bpf_*_get_fd_by_id()'
Roberto Sassu says: ==================== From: Roberto Sassu <roberto.sassu@huawei.com> Add the _opts variant for bpf_*_get_fd_by_id() functions, to be able to pass to the kernel more options, when requesting a fd of an eBPF object. Pass the options through a newly introduced structure, bpf_get_fd_by_id_opts, which currently contains open_flags (the other two members are for compatibility and for padding). open_flags allows the caller to request specific permissions to access a map (e.g. read-only). This is useful for example in the situation where a map is write-protected. Besides patches 2-6, which introduce the new variants and the data structure, patch 1 fixes the LIBBPF_1.0.0 declaration in libbpf.map. Changelog v1: - Don't CC stable kernel mailing list for patch 1 (suggested by Andrii) - Rename bpf_get_fd_opts struct to bpf_get_fd_by_id_opts (suggested by Andrii) - Move declaration of _opts variants after non-opts variants (suggested by Andrii) - Correctly initialize bpf_map_info, fix style issues, use map from skeleton, check valid fd in the test (suggested by Andrii) - Rename libbpf_get_fd_opts test to libbpf_get_fd_by_id_opts ==================== Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
This commit is contained in:
commit
f6ac03ebeb
6 changed files with 189 additions and 5 deletions
|
@ -935,58 +935,98 @@ int bpf_link_get_next_id(__u32 start_id, __u32 *next_id)
|
|||
return bpf_obj_get_next_id(start_id, next_id, BPF_LINK_GET_NEXT_ID);
|
||||
}
|
||||
|
||||
int bpf_prog_get_fd_by_id(__u32 id)
|
||||
int bpf_prog_get_fd_by_id_opts(__u32 id,
|
||||
const struct bpf_get_fd_by_id_opts *opts)
|
||||
{
|
||||
const size_t attr_sz = offsetofend(union bpf_attr, open_flags);
|
||||
union bpf_attr attr;
|
||||
int fd;
|
||||
|
||||
if (!OPTS_VALID(opts, bpf_get_fd_by_id_opts))
|
||||
return libbpf_err(-EINVAL);
|
||||
|
||||
memset(&attr, 0, attr_sz);
|
||||
attr.prog_id = id;
|
||||
attr.open_flags = OPTS_GET(opts, open_flags, 0);
|
||||
|
||||
fd = sys_bpf_fd(BPF_PROG_GET_FD_BY_ID, &attr, attr_sz);
|
||||
return libbpf_err_errno(fd);
|
||||
}
|
||||
|
||||
int bpf_map_get_fd_by_id(__u32 id)
|
||||
int bpf_prog_get_fd_by_id(__u32 id)
|
||||
{
|
||||
return bpf_prog_get_fd_by_id_opts(id, NULL);
|
||||
}
|
||||
|
||||
int bpf_map_get_fd_by_id_opts(__u32 id,
|
||||
const struct bpf_get_fd_by_id_opts *opts)
|
||||
{
|
||||
const size_t attr_sz = offsetofend(union bpf_attr, open_flags);
|
||||
union bpf_attr attr;
|
||||
int fd;
|
||||
|
||||
if (!OPTS_VALID(opts, bpf_get_fd_by_id_opts))
|
||||
return libbpf_err(-EINVAL);
|
||||
|
||||
memset(&attr, 0, attr_sz);
|
||||
attr.map_id = id;
|
||||
attr.open_flags = OPTS_GET(opts, open_flags, 0);
|
||||
|
||||
fd = sys_bpf_fd(BPF_MAP_GET_FD_BY_ID, &attr, attr_sz);
|
||||
return libbpf_err_errno(fd);
|
||||
}
|
||||
|
||||
int bpf_btf_get_fd_by_id(__u32 id)
|
||||
int bpf_map_get_fd_by_id(__u32 id)
|
||||
{
|
||||
return bpf_map_get_fd_by_id_opts(id, NULL);
|
||||
}
|
||||
|
||||
int bpf_btf_get_fd_by_id_opts(__u32 id,
|
||||
const struct bpf_get_fd_by_id_opts *opts)
|
||||
{
|
||||
const size_t attr_sz = offsetofend(union bpf_attr, open_flags);
|
||||
union bpf_attr attr;
|
||||
int fd;
|
||||
|
||||
if (!OPTS_VALID(opts, bpf_get_fd_by_id_opts))
|
||||
return libbpf_err(-EINVAL);
|
||||
|
||||
memset(&attr, 0, attr_sz);
|
||||
attr.btf_id = id;
|
||||
attr.open_flags = OPTS_GET(opts, open_flags, 0);
|
||||
|
||||
fd = sys_bpf_fd(BPF_BTF_GET_FD_BY_ID, &attr, attr_sz);
|
||||
return libbpf_err_errno(fd);
|
||||
}
|
||||
|
||||
int bpf_link_get_fd_by_id(__u32 id)
|
||||
int bpf_btf_get_fd_by_id(__u32 id)
|
||||
{
|
||||
return bpf_btf_get_fd_by_id_opts(id, NULL);
|
||||
}
|
||||
|
||||
int bpf_link_get_fd_by_id_opts(__u32 id,
|
||||
const struct bpf_get_fd_by_id_opts *opts)
|
||||
{
|
||||
const size_t attr_sz = offsetofend(union bpf_attr, open_flags);
|
||||
union bpf_attr attr;
|
||||
int fd;
|
||||
|
||||
if (!OPTS_VALID(opts, bpf_get_fd_by_id_opts))
|
||||
return libbpf_err(-EINVAL);
|
||||
|
||||
memset(&attr, 0, attr_sz);
|
||||
attr.link_id = id;
|
||||
attr.open_flags = OPTS_GET(opts, open_flags, 0);
|
||||
|
||||
fd = sys_bpf_fd(BPF_LINK_GET_FD_BY_ID, &attr, attr_sz);
|
||||
return libbpf_err_errno(fd);
|
||||
}
|
||||
|
||||
int bpf_link_get_fd_by_id(__u32 id)
|
||||
{
|
||||
return bpf_link_get_fd_by_id_opts(id, NULL);
|
||||
}
|
||||
|
||||
int bpf_obj_get_info_by_fd(int bpf_fd, void *info, __u32 *info_len)
|
||||
{
|
||||
const size_t attr_sz = offsetofend(union bpf_attr, info);
|
||||
|
|
|
@ -365,10 +365,26 @@ LIBBPF_API int bpf_prog_get_next_id(__u32 start_id, __u32 *next_id);
|
|||
LIBBPF_API int bpf_map_get_next_id(__u32 start_id, __u32 *next_id);
|
||||
LIBBPF_API int bpf_btf_get_next_id(__u32 start_id, __u32 *next_id);
|
||||
LIBBPF_API int bpf_link_get_next_id(__u32 start_id, __u32 *next_id);
|
||||
|
||||
struct bpf_get_fd_by_id_opts {
|
||||
size_t sz; /* size of this struct for forward/backward compatibility */
|
||||
__u32 open_flags; /* permissions requested for the operation on fd */
|
||||
size_t :0;
|
||||
};
|
||||
#define bpf_get_fd_by_id_opts__last_field open_flags
|
||||
|
||||
LIBBPF_API int bpf_prog_get_fd_by_id(__u32 id);
|
||||
LIBBPF_API int bpf_prog_get_fd_by_id_opts(__u32 id,
|
||||
const struct bpf_get_fd_by_id_opts *opts);
|
||||
LIBBPF_API int bpf_map_get_fd_by_id(__u32 id);
|
||||
LIBBPF_API int bpf_map_get_fd_by_id_opts(__u32 id,
|
||||
const struct bpf_get_fd_by_id_opts *opts);
|
||||
LIBBPF_API int bpf_btf_get_fd_by_id(__u32 id);
|
||||
LIBBPF_API int bpf_btf_get_fd_by_id_opts(__u32 id,
|
||||
const struct bpf_get_fd_by_id_opts *opts);
|
||||
LIBBPF_API int bpf_link_get_fd_by_id(__u32 id);
|
||||
LIBBPF_API int bpf_link_get_fd_by_id_opts(__u32 id,
|
||||
const struct bpf_get_fd_by_id_opts *opts);
|
||||
LIBBPF_API int bpf_obj_get_info_by_fd(int bpf_fd, void *info, __u32 *info_len);
|
||||
|
||||
struct bpf_prog_query_opts {
|
||||
|
|
|
@ -367,10 +367,14 @@ LIBBPF_1.0.0 {
|
|||
libbpf_bpf_map_type_str;
|
||||
libbpf_bpf_prog_type_str;
|
||||
perf_buffer__buffer;
|
||||
};
|
||||
} LIBBPF_0.8.0;
|
||||
|
||||
LIBBPF_1.1.0 {
|
||||
global:
|
||||
bpf_btf_get_fd_by_id_opts;
|
||||
bpf_link_get_fd_by_id_opts;
|
||||
bpf_map_get_fd_by_id_opts;
|
||||
bpf_prog_get_fd_by_id_opts;
|
||||
user_ring_buffer__discard;
|
||||
user_ring_buffer__free;
|
||||
user_ring_buffer__new;
|
||||
|
|
|
@ -76,3 +76,4 @@ lookup_key # JIT does not support calling kernel f
|
|||
verify_pkcs7_sig # JIT does not support calling kernel function (kfunc)
|
||||
kfunc_dynptr_param # JIT does not support calling kernel function (kfunc)
|
||||
deny_namespace # failed to attach: ERROR: strerror_r(-524)=22 (trampoline)
|
||||
libbpf_get_fd_by_id_opts # failed to attach: ERROR: strerror_r(-524)=22 (trampoline)
|
||||
|
|
|
@ -0,0 +1,87 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
/*
|
||||
* Copyright (C) 2022 Huawei Technologies Duesseldorf GmbH
|
||||
*
|
||||
* Author: Roberto Sassu <roberto.sassu@huawei.com>
|
||||
*/
|
||||
|
||||
#include <test_progs.h>
|
||||
|
||||
#include "test_libbpf_get_fd_by_id_opts.skel.h"
|
||||
|
||||
void test_libbpf_get_fd_by_id_opts(void)
|
||||
{
|
||||
struct test_libbpf_get_fd_by_id_opts *skel;
|
||||
struct bpf_map_info info_m = {};
|
||||
__u32 len = sizeof(info_m), value;
|
||||
int ret, zero = 0, fd = -1;
|
||||
LIBBPF_OPTS(bpf_get_fd_by_id_opts, fd_opts_rdonly,
|
||||
.open_flags = BPF_F_RDONLY,
|
||||
);
|
||||
|
||||
skel = test_libbpf_get_fd_by_id_opts__open_and_load();
|
||||
if (!ASSERT_OK_PTR(skel,
|
||||
"test_libbpf_get_fd_by_id_opts__open_and_load"))
|
||||
return;
|
||||
|
||||
ret = test_libbpf_get_fd_by_id_opts__attach(skel);
|
||||
if (!ASSERT_OK(ret, "test_libbpf_get_fd_by_id_opts__attach"))
|
||||
goto close_prog;
|
||||
|
||||
ret = bpf_obj_get_info_by_fd(bpf_map__fd(skel->maps.data_input),
|
||||
&info_m, &len);
|
||||
if (!ASSERT_OK(ret, "bpf_obj_get_info_by_fd"))
|
||||
goto close_prog;
|
||||
|
||||
fd = bpf_map_get_fd_by_id(info_m.id);
|
||||
if (!ASSERT_LT(fd, 0, "bpf_map_get_fd_by_id"))
|
||||
goto close_prog;
|
||||
|
||||
fd = bpf_map_get_fd_by_id_opts(info_m.id, NULL);
|
||||
if (!ASSERT_LT(fd, 0, "bpf_map_get_fd_by_id_opts"))
|
||||
goto close_prog;
|
||||
|
||||
fd = bpf_map_get_fd_by_id_opts(info_m.id, &fd_opts_rdonly);
|
||||
if (!ASSERT_GE(fd, 0, "bpf_map_get_fd_by_id_opts"))
|
||||
goto close_prog;
|
||||
|
||||
/* Map lookup should work with read-only fd. */
|
||||
ret = bpf_map_lookup_elem(fd, &zero, &value);
|
||||
if (!ASSERT_OK(ret, "bpf_map_lookup_elem"))
|
||||
goto close_prog;
|
||||
|
||||
if (!ASSERT_EQ(value, 0, "map value mismatch"))
|
||||
goto close_prog;
|
||||
|
||||
/* Map update should not work with read-only fd. */
|
||||
ret = bpf_map_update_elem(fd, &zero, &len, BPF_ANY);
|
||||
if (!ASSERT_LT(ret, 0, "bpf_map_update_elem"))
|
||||
goto close_prog;
|
||||
|
||||
/* Map update should work with read-write fd. */
|
||||
ret = bpf_map_update_elem(bpf_map__fd(skel->maps.data_input), &zero,
|
||||
&len, BPF_ANY);
|
||||
if (!ASSERT_OK(ret, "bpf_map_update_elem"))
|
||||
goto close_prog;
|
||||
|
||||
/* Prog get fd with opts set should not work (no kernel support). */
|
||||
ret = bpf_prog_get_fd_by_id_opts(0, &fd_opts_rdonly);
|
||||
if (!ASSERT_EQ(ret, -EINVAL, "bpf_prog_get_fd_by_id_opts"))
|
||||
goto close_prog;
|
||||
|
||||
/* Link get fd with opts set should not work (no kernel support). */
|
||||
ret = bpf_link_get_fd_by_id_opts(0, &fd_opts_rdonly);
|
||||
if (!ASSERT_EQ(ret, -EINVAL, "bpf_link_get_fd_by_id_opts"))
|
||||
goto close_prog;
|
||||
|
||||
/* BTF get fd with opts set should not work (no kernel support). */
|
||||
ret = bpf_btf_get_fd_by_id_opts(0, &fd_opts_rdonly);
|
||||
ASSERT_EQ(ret, -EINVAL, "bpf_btf_get_fd_by_id_opts");
|
||||
|
||||
close_prog:
|
||||
if (fd >= 0)
|
||||
close(fd);
|
||||
|
||||
test_libbpf_get_fd_by_id_opts__destroy(skel);
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
/*
|
||||
* Copyright (C) 2022 Huawei Technologies Duesseldorf GmbH
|
||||
*
|
||||
* Author: Roberto Sassu <roberto.sassu@huawei.com>
|
||||
*/
|
||||
|
||||
#include "vmlinux.h"
|
||||
#include <errno.h>
|
||||
#include <bpf/bpf_helpers.h>
|
||||
#include <bpf/bpf_tracing.h>
|
||||
|
||||
/* From include/linux/mm.h. */
|
||||
#define FMODE_WRITE 0x2
|
||||
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_ARRAY);
|
||||
__uint(max_entries, 1);
|
||||
__type(key, __u32);
|
||||
__type(value, __u32);
|
||||
} data_input SEC(".maps");
|
||||
|
||||
char _license[] SEC("license") = "GPL";
|
||||
|
||||
SEC("lsm/bpf_map")
|
||||
int BPF_PROG(check_access, struct bpf_map *map, fmode_t fmode)
|
||||
{
|
||||
if (map != (struct bpf_map *)&data_input)
|
||||
return 0;
|
||||
|
||||
if (fmode & FMODE_WRITE)
|
||||
return -EACCES;
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in a new issue