Commit 47faff37 authored by Andrii Nakryiko's avatar Andrii Nakryiko Committed by Daniel Borkmann
Browse files

libbpf: Add bpf_cookie to perf_event, kprobe, uprobe, and tp attach APIs



Wire through bpf_cookie for all attach APIs that use perf_event_open under the
hood:
  - for kprobes, extend existing bpf_kprobe_opts with bpf_cookie field;
  - for perf_event, uprobe, and tracepoint APIs, add their _opts variants and
    pass bpf_cookie through opts.

For kernel that don't support BPF_LINK_CREATE for perf_events, and thus
bpf_cookie is not supported either, return error and log warning for user.

Signed-off-by: default avatarAndrii Nakryiko <andrii@kernel.org>
Signed-off-by: default avatarDaniel Borkmann <daniel@iogearbox.net>
Link: https://lore.kernel.org/bpf/20210815070609.987780-12-andrii@kernel.org
parent 3ec84f4b
Loading
Loading
Loading
Loading
+65 −13
Original line number Diff line number Diff line
@@ -9014,12 +9014,16 @@ static void bpf_link_perf_dealloc(struct bpf_link *link)
	free(perf_link);
}

struct bpf_link *bpf_program__attach_perf_event(struct bpf_program *prog, int pfd)
struct bpf_link *bpf_program__attach_perf_event_opts(struct bpf_program *prog, int pfd,
						     const struct bpf_perf_event_opts *opts)
{
	char errmsg[STRERR_BUFSIZE];
	struct bpf_link_perf *link;
	int prog_fd, link_fd = -1, err;

	if (!OPTS_VALID(opts, bpf_perf_event_opts))
		return libbpf_err_ptr(-EINVAL);

	if (pfd < 0) {
		pr_warn("prog '%s': invalid perf event FD %d\n",
			prog->name, pfd);
@@ -9040,7 +9044,10 @@ struct bpf_link *bpf_program__attach_perf_event(struct bpf_program *prog, int pf
	link->perf_event_fd = pfd;

	if (kernel_supports(prog->obj, FEAT_PERF_LINK)) {
		link_fd = bpf_link_create(prog_fd, pfd, BPF_PERF_EVENT, NULL);
		DECLARE_LIBBPF_OPTS(bpf_link_create_opts, link_opts,
			.perf_event.bpf_cookie = OPTS_GET(opts, bpf_cookie, 0));

		link_fd = bpf_link_create(prog_fd, pfd, BPF_PERF_EVENT, &link_opts);
		if (link_fd < 0) {
			err = -errno;
			pr_warn("prog '%s': failed to create BPF link for perf_event FD %d: %d (%s)\n",
@@ -9050,6 +9057,12 @@ struct bpf_link *bpf_program__attach_perf_event(struct bpf_program *prog, int pf
		}
		link->link.fd = link_fd;
	} else {
		if (OPTS_GET(opts, bpf_cookie, 0)) {
			pr_warn("prog '%s': user context value is not supported\n", prog->name);
			err = -EOPNOTSUPP;
			goto err_out;
		}

		if (ioctl(pfd, PERF_EVENT_IOC_SET_BPF, prog_fd) < 0) {
			err = -errno;
			pr_warn("prog '%s': failed to attach to perf_event FD %d: %s\n",
@@ -9076,6 +9089,11 @@ struct bpf_link *bpf_program__attach_perf_event(struct bpf_program *prog, int pf
	return libbpf_err_ptr(err);
}

struct bpf_link *bpf_program__attach_perf_event(struct bpf_program *prog, int pfd)
{
	return bpf_program__attach_perf_event_opts(prog, pfd, NULL);
}

/*
 * this function is expected to parse integer in the range of [0, 2^31-1] from
 * given file using scanf format string fmt. If actual parsed value is
@@ -9184,8 +9202,9 @@ static int perf_event_open_probe(bool uprobe, bool retprobe, const char *name,
struct bpf_link *
bpf_program__attach_kprobe_opts(struct bpf_program *prog,
				const char *func_name,
				struct bpf_kprobe_opts *opts)
				const struct bpf_kprobe_opts *opts)
{
	DECLARE_LIBBPF_OPTS(bpf_perf_event_opts, pe_opts);
	char errmsg[STRERR_BUFSIZE];
	struct bpf_link *link;
	unsigned long offset;
@@ -9197,6 +9216,7 @@ bpf_program__attach_kprobe_opts(struct bpf_program *prog,

	retprobe = OPTS_GET(opts, retprobe, false);
	offset = OPTS_GET(opts, offset, 0);
	pe_opts.bpf_cookie = OPTS_GET(opts, bpf_cookie, 0);

	pfd = perf_event_open_probe(false /* uprobe */, retprobe, func_name,
				    offset, -1 /* pid */);
@@ -9206,7 +9226,7 @@ bpf_program__attach_kprobe_opts(struct bpf_program *prog,
			libbpf_strerror_r(pfd, errmsg, sizeof(errmsg)));
		return libbpf_err_ptr(pfd);
	}
	link = bpf_program__attach_perf_event(prog, pfd);
	link = bpf_program__attach_perf_event_opts(prog, pfd, &pe_opts);
	err = libbpf_get_error(link);
	if (err) {
		close(pfd);
@@ -9261,14 +9281,22 @@ static struct bpf_link *attach_kprobe(const struct bpf_sec_def *sec,
	return link;
}

struct bpf_link *bpf_program__attach_uprobe(struct bpf_program *prog,
					    bool retprobe, pid_t pid,
					    const char *binary_path,
					    size_t func_offset)
LIBBPF_API struct bpf_link *
bpf_program__attach_uprobe_opts(struct bpf_program *prog, pid_t pid,
				const char *binary_path, size_t func_offset,
				const struct bpf_uprobe_opts *opts)
{
	DECLARE_LIBBPF_OPTS(bpf_perf_event_opts, pe_opts);
	char errmsg[STRERR_BUFSIZE];
	struct bpf_link *link;
	int pfd, err;
	bool retprobe;

	if (!OPTS_VALID(opts, bpf_uprobe_opts))
		return libbpf_err_ptr(-EINVAL);

	retprobe = OPTS_GET(opts, retprobe, false);
	pe_opts.bpf_cookie = OPTS_GET(opts, bpf_cookie, 0);

	pfd = perf_event_open_probe(true /* uprobe */, retprobe,
				    binary_path, func_offset, pid);
@@ -9279,7 +9307,7 @@ struct bpf_link *bpf_program__attach_uprobe(struct bpf_program *prog,
			libbpf_strerror_r(pfd, errmsg, sizeof(errmsg)));
		return libbpf_err_ptr(pfd);
	}
	link = bpf_program__attach_perf_event(prog, pfd);
	link = bpf_program__attach_perf_event_opts(prog, pfd, &pe_opts);
	err = libbpf_get_error(link);
	if (err) {
		close(pfd);
@@ -9292,6 +9320,16 @@ struct bpf_link *bpf_program__attach_uprobe(struct bpf_program *prog,
	return link;
}

struct bpf_link *bpf_program__attach_uprobe(struct bpf_program *prog,
					    bool retprobe, pid_t pid,
					    const char *binary_path,
					    size_t func_offset)
{
	DECLARE_LIBBPF_OPTS(bpf_uprobe_opts, opts, .retprobe = retprobe);

	return bpf_program__attach_uprobe_opts(prog, pid, binary_path, func_offset, &opts);
}

static int determine_tracepoint_id(const char *tp_category,
				   const char *tp_name)
{
@@ -9342,14 +9380,21 @@ static int perf_event_open_tracepoint(const char *tp_category,
	return pfd;
}

struct bpf_link *bpf_program__attach_tracepoint(struct bpf_program *prog,
struct bpf_link *bpf_program__attach_tracepoint_opts(struct bpf_program *prog,
						     const char *tp_category,
						const char *tp_name)
						     const char *tp_name,
						     const struct bpf_tracepoint_opts *opts)
{
	DECLARE_LIBBPF_OPTS(bpf_perf_event_opts, pe_opts);
	char errmsg[STRERR_BUFSIZE];
	struct bpf_link *link;
	int pfd, err;

	if (!OPTS_VALID(opts, bpf_tracepoint_opts))
		return libbpf_err_ptr(-EINVAL);

	pe_opts.bpf_cookie = OPTS_GET(opts, bpf_cookie, 0);

	pfd = perf_event_open_tracepoint(tp_category, tp_name);
	if (pfd < 0) {
		pr_warn("prog '%s': failed to create tracepoint '%s/%s' perf event: %s\n",
@@ -9357,7 +9402,7 @@ struct bpf_link *bpf_program__attach_tracepoint(struct bpf_program *prog,
			libbpf_strerror_r(pfd, errmsg, sizeof(errmsg)));
		return libbpf_err_ptr(pfd);
	}
	link = bpf_program__attach_perf_event(prog, pfd);
	link = bpf_program__attach_perf_event_opts(prog, pfd, &pe_opts);
	err = libbpf_get_error(link);
	if (err) {
		close(pfd);
@@ -9369,6 +9414,13 @@ struct bpf_link *bpf_program__attach_tracepoint(struct bpf_program *prog,
	return link;
}

struct bpf_link *bpf_program__attach_tracepoint(struct bpf_program *prog,
						const char *tp_category,
						const char *tp_name)
{
	return bpf_program__attach_tracepoint_opts(prog, tp_category, tp_name, NULL);
}

static struct bpf_link *attach_tp(const struct bpf_sec_def *sec,
				  struct bpf_program *prog)
{
+59 −12
Original line number Diff line number Diff line
@@ -104,17 +104,6 @@ struct bpf_object_open_opts {
};
#define bpf_object_open_opts__last_field btf_custom_path

struct bpf_kprobe_opts {
	/* size of this struct, for forward/backward compatiblity */
	size_t sz;
	/* function's offset to install kprobe to */
	unsigned long offset;
	/* kprobe is return probe */
	bool retprobe;
	size_t :0;
};
#define bpf_kprobe_opts__last_field retprobe

LIBBPF_API struct bpf_object *bpf_object__open(const char *path);
LIBBPF_API struct bpf_object *
bpf_object__open_file(const char *path, const struct bpf_object_open_opts *opts);
@@ -255,24 +244,82 @@ LIBBPF_API int bpf_link__destroy(struct bpf_link *link);

LIBBPF_API struct bpf_link *
bpf_program__attach(struct bpf_program *prog);

struct bpf_perf_event_opts {
	/* size of this struct, for forward/backward compatiblity */
	size_t sz;
	/* custom user-provided value fetchable through bpf_get_attach_cookie() */
	__u64 bpf_cookie;
};
#define bpf_perf_event_opts__last_field bpf_cookie

LIBBPF_API struct bpf_link *
bpf_program__attach_perf_event(struct bpf_program *prog, int pfd);

LIBBPF_API struct bpf_link *
bpf_program__attach_perf_event_opts(struct bpf_program *prog, int pfd,
				    const struct bpf_perf_event_opts *opts);

struct bpf_kprobe_opts {
	/* size of this struct, for forward/backward compatiblity */
	size_t sz;
	/* custom user-provided value fetchable through bpf_get_attach_cookie() */
	__u64 bpf_cookie;
	/* function's offset to install kprobe to */
	unsigned long offset;
	/* kprobe is return probe */
	bool retprobe;
	size_t :0;
};
#define bpf_kprobe_opts__last_field retprobe

LIBBPF_API struct bpf_link *
bpf_program__attach_kprobe(struct bpf_program *prog, bool retprobe,
			   const char *func_name);
LIBBPF_API struct bpf_link *
bpf_program__attach_kprobe_opts(struct bpf_program *prog,
                                const char *func_name,
                                struct bpf_kprobe_opts *opts);
                                const struct bpf_kprobe_opts *opts);

struct bpf_uprobe_opts {
	/* size of this struct, for forward/backward compatiblity */
	size_t sz;
	/* custom user-provided value fetchable through bpf_get_attach_cookie() */
	__u64 bpf_cookie;
	/* uprobe is return probe, invoked at function return time */
	bool retprobe;
	size_t :0;
};
#define bpf_uprobe_opts__last_field retprobe

LIBBPF_API struct bpf_link *
bpf_program__attach_uprobe(struct bpf_program *prog, bool retprobe,
			   pid_t pid, const char *binary_path,
			   size_t func_offset);
LIBBPF_API struct bpf_link *
bpf_program__attach_uprobe_opts(struct bpf_program *prog, pid_t pid,
				const char *binary_path, size_t func_offset,
				const struct bpf_uprobe_opts *opts);

struct bpf_tracepoint_opts {
	/* size of this struct, for forward/backward compatiblity */
	size_t sz;
	/* custom user-provided value fetchable through bpf_get_attach_cookie() */
	__u64 bpf_cookie;
};
#define bpf_tracepoint_opts__last_field bpf_cookie

LIBBPF_API struct bpf_link *
bpf_program__attach_tracepoint(struct bpf_program *prog,
			       const char *tp_category,
			       const char *tp_name);
LIBBPF_API struct bpf_link *
bpf_program__attach_tracepoint_opts(struct bpf_program *prog,
				    const char *tp_category,
				    const char *tp_name,
				    const struct bpf_tracepoint_opts *opts);

LIBBPF_API struct bpf_link *
bpf_program__attach_raw_tracepoint(struct bpf_program *prog,
				   const char *tp_name);
LIBBPF_API struct bpf_link *
+3 −0
Original line number Diff line number Diff line
@@ -374,6 +374,9 @@ LIBBPF_0.5.0 {
		bpf_map__pin_path;
		bpf_map_lookup_and_delete_elem_flags;
		bpf_program__attach_kprobe_opts;
		bpf_program__attach_perf_event_opts;
		bpf_program__attach_tracepoint_opts;
		bpf_program__attach_uprobe_opts;
		bpf_object__gen_loader;
		btf__load_from_kernel_by_id;
		btf__load_from_kernel_by_id_split;