Commit 5d23328d authored by YiFei Zhu's avatar YiFei Zhu Committed by Alexei Starovoitov
Browse files

libbpf: Add BPF_PROG_BIND_MAP syscall and use it on .rodata section



The patch adds a simple wrapper bpf_prog_bind_map around the syscall.
When the libbpf tries to load a program, it will probe the kernel for
the support of this syscall and unconditionally bind .rodata section
to the program.

Signed-off-by: default avatarYiFei Zhu <zhuyifei@google.com>
Signed-off-by: default avatarStanislav Fomichev <sdf@google.com>
Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
Cc: YiFei Zhu <zhuyifei1999@gmail.com>
Link: https://lore.kernel.org/bpf/20200915234543.3220146-4-sdf@google.com
parent ef15314a
Loading
Loading
Loading
Loading
+16 −0
Original line number Diff line number Diff line
@@ -872,3 +872,19 @@ int bpf_enable_stats(enum bpf_stats_type type)

	return sys_bpf(BPF_ENABLE_STATS, &attr, sizeof(attr));
}

int bpf_prog_bind_map(int prog_fd, int map_fd,
		      const struct bpf_prog_bind_opts *opts)
{
	union bpf_attr attr;

	if (!OPTS_VALID(opts, bpf_prog_bind_opts))
		return -EINVAL;

	memset(&attr, 0, sizeof(attr));
	attr.prog_bind_map.prog_fd = prog_fd;
	attr.prog_bind_map.map_fd = map_fd;
	attr.prog_bind_map.flags = OPTS_GET(opts, flags, 0);

	return sys_bpf(BPF_PROG_BIND_MAP, &attr, sizeof(attr));
}
+8 −0
Original line number Diff line number Diff line
@@ -243,6 +243,14 @@ LIBBPF_API int bpf_task_fd_query(int pid, int fd, __u32 flags, char *buf,
enum bpf_stats_type; /* defined in up-to-date linux/bpf.h */
LIBBPF_API int bpf_enable_stats(enum bpf_stats_type type);

struct bpf_prog_bind_opts {
	size_t sz; /* size of this struct for forward/backward compatibility */
	__u32 flags;
};
#define bpf_prog_bind_opts__last_field flags

LIBBPF_API int bpf_prog_bind_map(int prog_fd, int map_fd,
				 const struct bpf_prog_bind_opts *opts);
#ifdef __cplusplus
} /* extern "C" */
#endif
+69 −0
Original line number Diff line number Diff line
@@ -174,6 +174,8 @@ enum kern_feature_id {
	FEAT_EXP_ATTACH_TYPE,
	/* bpf_probe_read_{kernel,user}[_str] helpers */
	FEAT_PROBE_READ_KERN,
	/* BPF_PROG_BIND_MAP is supported */
	FEAT_PROG_BIND_MAP,
	__FEAT_CNT,
};

@@ -409,6 +411,7 @@ struct bpf_object {
	struct extern_desc *externs;
	int nr_extern;
	int kconfig_map_idx;
	int rodata_map_idx;

	bool loaded;
	bool has_subcalls;
@@ -1070,6 +1073,7 @@ static struct bpf_object *bpf_object__new(const char *path,
	obj->efile.bss_shndx = -1;
	obj->efile.st_ops_shndx = -1;
	obj->kconfig_map_idx = -1;
	obj->rodata_map_idx = -1;

	obj->kern_version = get_kernel_version();
	obj->loaded = false;
@@ -1428,6 +1432,8 @@ static int bpf_object__init_global_data_maps(struct bpf_object *obj)
						    obj->efile.rodata->d_size);
		if (err)
			return err;

		obj->rodata_map_idx = obj->nr_maps - 1;
	}
	if (obj->efile.bss_shndx >= 0) {
		err = bpf_object__init_internal_map(obj, LIBBPF_MAP_BSS,
@@ -3894,6 +3900,52 @@ static int probe_kern_probe_read_kernel(void)
	return probe_fd(bpf_load_program_xattr(&attr, NULL, 0));
}

static int probe_prog_bind_map(void)
{
	struct bpf_load_program_attr prg_attr;
	struct bpf_create_map_attr map_attr;
	char *cp, errmsg[STRERR_BUFSIZE];
	struct bpf_insn insns[] = {
		BPF_MOV64_IMM(BPF_REG_0, 0),
		BPF_EXIT_INSN(),
	};
	int ret, map, prog;

	memset(&map_attr, 0, sizeof(map_attr));
	map_attr.map_type = BPF_MAP_TYPE_ARRAY;
	map_attr.key_size = sizeof(int);
	map_attr.value_size = 32;
	map_attr.max_entries = 1;

	map = bpf_create_map_xattr(&map_attr);
	if (map < 0) {
		ret = -errno;
		cp = libbpf_strerror_r(ret, errmsg, sizeof(errmsg));
		pr_warn("Error in %s():%s(%d). Couldn't create simple array map.\n",
			__func__, cp, -ret);
		return ret;
	}

	memset(&prg_attr, 0, sizeof(prg_attr));
	prg_attr.prog_type = BPF_PROG_TYPE_SOCKET_FILTER;
	prg_attr.insns = insns;
	prg_attr.insns_cnt = ARRAY_SIZE(insns);
	prg_attr.license = "GPL";

	prog = bpf_load_program_xattr(&prg_attr, NULL, 0);
	if (prog < 0) {
		close(map);
		return 0;
	}

	ret = bpf_prog_bind_map(prog, map, NULL);

	close(map);
	close(prog);

	return ret >= 0;
}

enum kern_feature_result {
	FEAT_UNKNOWN = 0,
	FEAT_SUPPORTED = 1,
@@ -3934,6 +3986,9 @@ static struct kern_feature_desc {
	},
	[FEAT_PROBE_READ_KERN] = {
		"bpf_probe_read_kernel() helper", probe_kern_probe_read_kernel,
	},
	[FEAT_PROG_BIND_MAP] = {
		"BPF_PROG_BIND_MAP support", probe_prog_bind_map,
	}
};

@@ -6468,6 +6523,20 @@ load_program(struct bpf_program *prog, struct bpf_insn *insns, int insns_cnt,
	if (ret >= 0) {
		if (log_buf && load_attr.log_level)
			pr_debug("verifier log:\n%s", log_buf);

		if (prog->obj->rodata_map_idx >= 0 &&
		    kernel_supports(FEAT_PROG_BIND_MAP)) {
			struct bpf_map *rodata_map =
				&prog->obj->maps[prog->obj->rodata_map_idx];

			if (bpf_prog_bind_map(ret, bpf_map__fd(rodata_map), NULL)) {
				cp = libbpf_strerror_r(errno, errmsg, sizeof(errmsg));
				pr_warn("prog '%s': failed to bind .rodata map: %s\n",
					prog->name, cp);
				/* Don't fail hard if can't bind rodata. */
			}
		}

		*pfd = ret;
		ret = 0;
		goto out;
+1 −0
Original line number Diff line number Diff line
@@ -302,6 +302,7 @@ LIBBPF_0.1.0 {

LIBBPF_0.2.0 {
	global:
		bpf_prog_bind_map;
		bpf_program__section_name;
		perf_buffer__buffer_cnt;
		perf_buffer__buffer_fd;