Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f56a653c authored by Martin KaFai Lau's avatar Martin KaFai Lau Committed by Daniel Borkmann
Browse files

bpf: btf: Add BPF_BTF_LOAD command



This patch adds a BPF_BTF_LOAD command which
1) loads and verifies the BTF (implemented in earlier patches)
2) returns a BTF fd to userspace.  In the next patch, the
   BTF fd can be specified during BPF_MAP_CREATE.

It currently limits to CAP_SYS_ADMIN.

Signed-off-by: default avatarMartin KaFai Lau <kafai@fb.com>
Acked-by: default avatarAlexei Starovoitov <ast@fb.com>
Signed-off-by: default avatarDaniel Borkmann <daniel@iogearbox.net>
parent b00b8dae
Loading
Loading
Loading
Loading
+4 −0
Original line number Original line Diff line number Diff line
@@ -8,7 +8,11 @@


struct btf;
struct btf;
struct btf_type;
struct btf_type;
union bpf_attr;


void btf_put(struct btf *btf);
int btf_new_fd(const union bpf_attr *attr);
struct btf *btf_get_by_fd(int fd);
/* Figure out the size of a type_id.  If type_id is a modifier
/* Figure out the size of a type_id.  If type_id is a modifier
 * (e.g. const), it will be resolved to find out the type with size.
 * (e.g. const), it will be resolved to find out the type with size.
 *
 *
+9 −0
Original line number Original line Diff line number Diff line
@@ -95,6 +95,7 @@ enum bpf_cmd {
	BPF_OBJ_GET_INFO_BY_FD,
	BPF_OBJ_GET_INFO_BY_FD,
	BPF_PROG_QUERY,
	BPF_PROG_QUERY,
	BPF_RAW_TRACEPOINT_OPEN,
	BPF_RAW_TRACEPOINT_OPEN,
	BPF_BTF_LOAD,
};
};


enum bpf_map_type {
enum bpf_map_type {
@@ -363,6 +364,14 @@ union bpf_attr {
		__u64 name;
		__u64 name;
		__u32 prog_fd;
		__u32 prog_fd;
	} raw_tracepoint;
	} raw_tracepoint;

	struct { /* anonymous struct for BPF_BTF_LOAD */
		__aligned_u64	btf;
		__aligned_u64	btf_log_buf;
		__u32		btf_size;
		__u32		btf_log_size;
		__u32		btf_log_level;
	};
} __attribute__((aligned(8)));
} __attribute__((aligned(8)));


/* BPF helper function descriptions:
/* BPF helper function descriptions:
+67 −0
Original line number Original line Diff line number Diff line
@@ -7,6 +7,8 @@
#include <linux/compiler.h>
#include <linux/compiler.h>
#include <linux/errno.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/slab.h>
#include <linux/anon_inodes.h>
#include <linux/file.h>
#include <linux/uaccess.h>
#include <linux/uaccess.h>
#include <linux/kernel.h>
#include <linux/kernel.h>
#include <linux/bpf_verifier.h>
#include <linux/bpf_verifier.h>
@@ -190,6 +192,7 @@ struct btf {
	u32 nr_types;
	u32 nr_types;
	u32 types_size;
	u32 types_size;
	u32 data_size;
	u32 data_size;
	refcount_t refcnt;
};
};


enum verifier_phase {
enum verifier_phase {
@@ -604,6 +607,17 @@ static void btf_free(struct btf *btf)
	kfree(btf);
	kfree(btf);
}
}


static void btf_get(struct btf *btf)
{
	refcount_inc(&btf->refcnt);
}

void btf_put(struct btf *btf)
{
	if (btf && refcount_dec_and_test(&btf->refcnt))
		btf_free(btf);
}

static int env_resolve_init(struct btf_verifier_env *env)
static int env_resolve_init(struct btf_verifier_env *env)
{
{
	struct btf *btf = env->btf;
	struct btf *btf = env->btf;
@@ -1963,6 +1977,7 @@ static struct btf *btf_parse(void __user *btf_data, u32 btf_data_size,


	if (!err) {
	if (!err) {
		btf_verifier_env_free(env);
		btf_verifier_env_free(env);
		btf_get(btf);
		return btf;
		return btf;
	}
	}


@@ -1980,3 +1995,55 @@ void btf_type_seq_show(const struct btf *btf, u32 type_id, void *obj,


	btf_type_ops(t)->seq_show(btf, t, type_id, obj, 0, m);
	btf_type_ops(t)->seq_show(btf, t, type_id, obj, 0, m);
}
}

static int btf_release(struct inode *inode, struct file *filp)
{
	btf_put(filp->private_data);
	return 0;
}

static const struct file_operations btf_fops = {
	.release	= btf_release,
};

int btf_new_fd(const union bpf_attr *attr)
{
	struct btf *btf;
	int fd;

	btf = btf_parse(u64_to_user_ptr(attr->btf),
			attr->btf_size, attr->btf_log_level,
			u64_to_user_ptr(attr->btf_log_buf),
			attr->btf_log_size);
	if (IS_ERR(btf))
		return PTR_ERR(btf);

	fd = anon_inode_getfd("btf", &btf_fops, btf,
			      O_RDONLY | O_CLOEXEC);
	if (fd < 0)
		btf_put(btf);

	return fd;
}

struct btf *btf_get_by_fd(int fd)
{
	struct btf *btf;
	struct fd f;

	f = fdget(fd);

	if (!f.file)
		return ERR_PTR(-EBADF);

	if (f.file->f_op != &btf_fops) {
		fdput(f);
		return ERR_PTR(-EINVAL);
	}

	btf = f.file->private_data;
	btf_get(btf);
	fdput(f);

	return btf;
}
+17 −0
Original line number Original line Diff line number Diff line
@@ -11,6 +11,7 @@
 */
 */
#include <linux/bpf.h>
#include <linux/bpf.h>
#include <linux/bpf_trace.h>
#include <linux/bpf_trace.h>
#include <linux/btf.h>
#include <linux/syscalls.h>
#include <linux/syscalls.h>
#include <linux/slab.h>
#include <linux/slab.h>
#include <linux/sched/signal.h>
#include <linux/sched/signal.h>
@@ -2023,6 +2024,19 @@ static int bpf_obj_get_info_by_fd(const union bpf_attr *attr,
	return err;
	return err;
}
}


#define BPF_BTF_LOAD_LAST_FIELD btf_log_level

static int bpf_btf_load(const union bpf_attr *attr)
{
	if (CHECK_ATTR(BPF_BTF_LOAD))
		return -EINVAL;

	if (!capable(CAP_SYS_ADMIN))
		return -EPERM;

	return btf_new_fd(attr);
}

SYSCALL_DEFINE3(bpf, int, cmd, union bpf_attr __user *, uattr, unsigned int, size)
SYSCALL_DEFINE3(bpf, int, cmd, union bpf_attr __user *, uattr, unsigned int, size)
{
{
	union bpf_attr attr = {};
	union bpf_attr attr = {};
@@ -2103,6 +2117,9 @@ SYSCALL_DEFINE3(bpf, int, cmd, union bpf_attr __user *, uattr, unsigned int, siz
	case BPF_RAW_TRACEPOINT_OPEN:
	case BPF_RAW_TRACEPOINT_OPEN:
		err = bpf_raw_tracepoint_open(&attr);
		err = bpf_raw_tracepoint_open(&attr);
		break;
		break;
	case BPF_BTF_LOAD:
		err = bpf_btf_load(&attr);
		break;
	default:
	default:
		err = -EINVAL;
		err = -EINVAL;
		break;
		break;