@@ -89,7 +89,9 @@ int btf_type_snprintf_show(const struct btf *btf, u32 type_id, void *obj,
char *buf, int len, u64 flags);
int btf_get_fd_by_id(u32 id);
+struct btf *btf_get_by_id(int id);
u32 btf_obj_id(const struct btf *btf);
+bool btf_is_kernel(const struct btf *btf);
bool btf_member_is_reg_int(const struct btf *btf, const struct btf_type *s,
const struct btf_member *m,
u32 expected_offset, u32 expected_size);
@@ -558,6 +558,7 @@ union bpf_attr {
__u32 line_info_cnt; /* number of bpf_line_info records */
__u32 attach_btf_id; /* in-kernel BTF type id to attach to */
__u32 attach_prog_fd; /* 0 to attach to vmlinux */
+ __u32 attach_btf_obj_id; /* vmlinux/module BTF object ID for BTF type */
};
struct { /* anonymous struct used by BPF_OBJ_* commands */
@@ -5652,6 +5652,19 @@ struct btf *btf_get_by_fd(int fd)
return btf;
}
+struct btf *btf_get_by_id(int id)
+{
+ struct btf *btf;
+
+ rcu_read_lock();
+ btf = idr_find(&btf_idr, id);
+ if (!btf || !refcount_inc_not_zero(&btf->refcnt))
+ btf = ERR_PTR(-ENOENT);
+ rcu_read_unlock();
+
+ return btf;
+}
+
int btf_get_info_by_fd(const struct btf *btf,
const union bpf_attr *attr,
union bpf_attr __user *uattr)
@@ -5717,12 +5730,7 @@ int btf_get_fd_by_id(u32 id)
struct btf *btf;
int fd;
- rcu_read_lock();
- btf = idr_find(&btf_idr, id);
- if (!btf || !refcount_inc_not_zero(&btf->refcnt))
- btf = ERR_PTR(-ENOENT);
- rcu_read_unlock();
-
+ btf = btf_get_by_id(id);
if (IS_ERR(btf))
return PTR_ERR(btf);
@@ -5738,6 +5746,11 @@ u32 btf_obj_id(const struct btf *btf)
return btf->id;
}
+bool btf_is_kernel(const struct btf *btf)
+{
+ return btf->kernel_btf;
+}
+
static int btf_id_cmp_func(const void *a, const void *b)
{
const int *pa = a, *pb = b;
@@ -1968,7 +1968,7 @@ static void bpf_prog_load_fixup_attach_type(union bpf_attr *attr)
static int
bpf_prog_load_check_attach(enum bpf_prog_type prog_type,
enum bpf_attach_type expected_attach_type,
- u32 btf_id, u32 prog_fd)
+ u32 btf_obj_id, u32 btf_id, u32 prog_fd)
{
if (btf_id) {
if (btf_id > BTF_MAX_TYPE)
@@ -1985,6 +1985,9 @@ bpf_prog_load_check_attach(enum bpf_prog_type prog_type,
}
}
+ if (btf_obj_id && (!btf_id || prog_fd))
+ return -EINVAL;
+
if (prog_fd && prog_type != BPF_PROG_TYPE_TRACING &&
prog_type != BPF_PROG_TYPE_EXT)
return -EINVAL;
@@ -2097,7 +2100,7 @@ static bool is_perfmon_prog_type(enum bpf_prog_type prog_type)
}
/* last field in 'union bpf_attr' used by this command */
-#define BPF_PROG_LOAD_LAST_FIELD attach_prog_fd
+#define BPF_PROG_LOAD_LAST_FIELD attach_btf_obj_id
static int bpf_prog_load(union bpf_attr *attr, union bpf_attr __user *uattr)
{
@@ -2146,6 +2149,7 @@ static int bpf_prog_load(union bpf_attr *attr, union bpf_attr __user *uattr)
bpf_prog_load_fixup_attach_type(attr);
if (bpf_prog_load_check_attach(type, attr->expected_attach_type,
+ attr->attach_btf_obj_id,
attr->attach_btf_id,
attr->attach_prog_fd))
return -EINVAL;
@@ -2158,7 +2162,19 @@ static int bpf_prog_load(union bpf_attr *attr, union bpf_attr __user *uattr)
prog->expected_attach_type = attr->expected_attach_type;
prog->aux->attach_btf_id = attr->attach_btf_id;
- if (attr->attach_btf_id && !attr->attach_prog_fd) {
+ if (attr->attach_btf_obj_id) {
+ struct btf *btf;
+
+ btf = btf_get_by_id(attr->attach_btf_obj_id);
+ if (IS_ERR(btf))
+ return PTR_ERR(btf);
+ if (!btf_is_kernel(btf)) {
+ btf_put(btf);
+ return -EINVAL;
+ }
+
+ prog->aux->attach_btf = btf;
+ } else if (attr->attach_btf_id && !attr->attach_prog_fd) {
struct btf *btf;
btf = bpf_get_btf_vmlinux();
@@ -558,6 +558,7 @@ union bpf_attr {
__u32 line_info_cnt; /* number of bpf_line_info records */
__u32 attach_btf_id; /* in-kernel BTF type id to attach to */
__u32 attach_prog_fd; /* 0 to attach to vmlinux */
+ __u32 attach_btf_obj_id; /* vmlinux/module BTF object ID for BTF type */
};
struct { /* anonymous struct used by BPF_OBJ_* commands */
Add ability for user-space programs to specify non-vmlinux BTF when attaching BTF-powered BPF programs: raw_tp, fentry/fexit/fmod_ret, LSM, etc. For this, add attach_btf_obj_id field which contains BTF object ID for either vmlinux or module. For backwards compatibility (and simplicity) reasons, 0 denotes vmlinux BTF. Only kernel BTF (vmlinux or module) can be specified. Signed-off-by: Andrii Nakryiko <andrii@kernel.org> --- include/linux/btf.h | 2 ++ include/uapi/linux/bpf.h | 1 + kernel/bpf/btf.c | 25 +++++++++++++++++++------ kernel/bpf/syscall.c | 22 +++++++++++++++++++--- tools/include/uapi/linux/bpf.h | 1 + 5 files changed, 42 insertions(+), 9 deletions(-)