From: Kumar Kartikeya Dwivedi <memxor@gmail.com>
To: bpf@vger.kernel.org
Cc: Alexei Starovoitov <ast@kernel.org>,
Daniel Borkmann <daniel@iogearbox.net>,
Andrii Nakryiko <andrii@kernel.org>,
Martin KaFai Lau <martin.lau@linux.dev>,
Yonghong Song <yonghong.song@linux.dev>,
David Vernet <void@manifault.com>,
Puranjay Mohan <puranjay12@gmail.com>
Subject: [PATCH bpf-next v3 15/17] libbpf: Add support for custom exception callbacks
Date: Wed, 13 Sep 2023 01:32:12 +0200 [thread overview]
Message-ID: <20230912233214.1518551-16-memxor@gmail.com> (raw)
In-Reply-To: <20230912233214.1518551-1-memxor@gmail.com>
Add support to libbpf to append exception callbacks when loading a
program. The exception callback is found by discovering the declaration
tag 'exception_callback:<value>' and finding the callback in the value
of the tag.
The process is done in two steps. First, for each main program, the
bpf_object__sanitize_and_load_btf function finds and marks its
corresponding exception callback as defined by the declaration tag on
it. Second, bpf_object__reloc_code is modified to append the indicated
exception callback at the end of the instruction iteration (since
exception callback will never be appended in that loop, as it is not
directly referenced).
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
---
tools/lib/bpf/libbpf.c | 114 +++++++++++++++++++++++++++++++++++++++--
1 file changed, 109 insertions(+), 5 deletions(-)
diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index afc07a8f7dc7..3a6108e3238b 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -436,9 +436,11 @@ struct bpf_program {
int fd;
bool autoload;
bool autoattach;
+ bool sym_global;
bool mark_btf_static;
enum bpf_prog_type type;
enum bpf_attach_type expected_attach_type;
+ int exception_cb_idx;
int prog_ifindex;
__u32 attach_btf_obj_fd;
@@ -765,6 +767,7 @@ bpf_object__init_prog(struct bpf_object *obj, struct bpf_program *prog,
prog->type = BPF_PROG_TYPE_UNSPEC;
prog->fd = -1;
+ prog->exception_cb_idx = -1;
/* libbpf's convention for SEC("?abc...") is that it's just like
* SEC("abc...") but the corresponding bpf_program starts out with
@@ -871,14 +874,16 @@ bpf_object__add_programs(struct bpf_object *obj, Elf_Data *sec_data,
if (err)
return err;
+ if (ELF64_ST_BIND(sym->st_info) != STB_LOCAL)
+ prog->sym_global = true;
+
/* if function is a global/weak symbol, but has restricted
* (STV_HIDDEN or STV_INTERNAL) visibility, mark its BTF FUNC
* as static to enable more permissive BPF verification mode
* with more outside context available to BPF verifier
*/
- if (ELF64_ST_BIND(sym->st_info) != STB_LOCAL
- && (ELF64_ST_VISIBILITY(sym->st_other) == STV_HIDDEN
- || ELF64_ST_VISIBILITY(sym->st_other) == STV_INTERNAL))
+ if (prog->sym_global && (ELF64_ST_VISIBILITY(sym->st_other) == STV_HIDDEN
+ || ELF64_ST_VISIBILITY(sym->st_other) == STV_INTERNAL))
prog->mark_btf_static = true;
nr_progs++;
@@ -3142,6 +3147,86 @@ static int bpf_object__sanitize_and_load_btf(struct bpf_object *obj)
}
}
+ if (!kernel_supports(obj, FEAT_BTF_DECL_TAG))
+ goto skip_exception_cb;
+ for (i = 0; i < obj->nr_programs; i++) {
+ struct bpf_program *prog = &obj->programs[i];
+ int j, k, n;
+
+ if (prog_is_subprog(obj, prog))
+ continue;
+ n = btf__type_cnt(obj->btf);
+ for (j = 1; j < n; j++) {
+ const char *str = "exception_callback:", *name;
+ size_t len = strlen(str);
+ struct btf_type *t;
+
+ t = btf_type_by_id(obj->btf, j);
+ if (!btf_is_decl_tag(t) || btf_decl_tag(t)->component_idx != -1)
+ continue;
+
+ name = btf__str_by_offset(obj->btf, t->name_off);
+ if (strncmp(name, str, len))
+ continue;
+
+ t = btf_type_by_id(obj->btf, t->type);
+ if (!btf_is_func(t) || btf_func_linkage(t) != BTF_FUNC_GLOBAL) {
+ pr_warn("prog '%s': exception_callback:<value> decl tag not applied to the main program\n",
+ prog->name);
+ return -EINVAL;
+ }
+ if (strcmp(prog->name, btf__str_by_offset(obj->btf, t->name_off)))
+ continue;
+ /* Multiple callbacks are specified for the same prog,
+ * the verifier will eventually return an error for this
+ * case, hence simply skip appending a subprog.
+ */
+ if (prog->exception_cb_idx >= 0) {
+ prog->exception_cb_idx = -1;
+ break;
+ }
+
+ name += len;
+ if (str_is_empty(name)) {
+ pr_warn("prog '%s': exception_callback:<value> decl tag contains empty value\n",
+ prog->name);
+ return -EINVAL;
+ }
+
+ for (k = 0; k < obj->nr_programs; k++) {
+ struct bpf_program *subprog = &obj->programs[k];
+
+ if (!prog_is_subprog(obj, subprog))
+ continue;
+ if (strcmp(name, subprog->name))
+ continue;
+ /* Enforce non-hidden, as from verifier point of
+ * view it expects global functions, whereas the
+ * mark_btf_static fixes up linkage as static.
+ */
+ if (!subprog->sym_global || subprog->mark_btf_static) {
+ pr_warn("prog '%s': exception callback %s must be a global non-hidden function\n",
+ prog->name, subprog->name);
+ return -EINVAL;
+ }
+ /* Let's see if we already saw a static exception callback with the same name */
+ if (prog->exception_cb_idx >= 0) {
+ pr_warn("prog '%s': multiple subprogs with same name as exception callback '%s'\n",
+ prog->name, subprog->name);
+ return -EINVAL;
+ }
+ prog->exception_cb_idx = k;
+ break;
+ }
+
+ if (prog->exception_cb_idx >= 0)
+ continue;
+ pr_warn("prog '%s': cannot find exception callback '%s'\n", prog->name, name);
+ return -ENOENT;
+ }
+ }
+skip_exception_cb:
+
sanitize = btf_needs_sanitization(obj);
if (sanitize) {
const void *raw_data;
@@ -6270,10 +6355,10 @@ static int
bpf_object__reloc_code(struct bpf_object *obj, struct bpf_program *main_prog,
struct bpf_program *prog)
{
- size_t sub_insn_idx, insn_idx, new_cnt;
+ size_t sub_insn_idx, insn_idx;
struct bpf_program *subprog;
- struct bpf_insn *insns, *insn;
struct reloc_desc *relo;
+ struct bpf_insn *insn;
int err;
err = reloc_prog_func_and_line_info(obj, main_prog, prog);
@@ -6582,6 +6667,25 @@ bpf_object__relocate(struct bpf_object *obj, const char *targ_btf_path)
prog->name, err);
return err;
}
+
+ /* Now, also append exception callback if it has not been done already. */
+ if (prog->exception_cb_idx >= 0) {
+ struct bpf_program *subprog = &obj->programs[prog->exception_cb_idx];
+
+ /* Calling exception callback directly is disallowed, which the
+ * verifier will reject later. In case it was processed already,
+ * we can skip this step, otherwise for all other valid cases we
+ * have to append exception callback now.
+ */
+ if (subprog->sub_insn_off == 0) {
+ err = bpf_object__append_subprog_code(obj, prog, subprog);
+ if (err)
+ return err;
+ err = bpf_object__reloc_code(obj, prog, subprog);
+ if (err)
+ return err;
+ }
+ }
}
/* Process data relos for main programs */
for (i = 0; i < obj->nr_programs; i++) {
--
2.41.0
next prev parent reply other threads:[~2023-09-12 23:32 UTC|newest]
Thread overview: 36+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-09-12 23:31 [PATCH bpf-next v3 00/17] Exceptions - 1/2 Kumar Kartikeya Dwivedi
2023-09-12 23:31 ` [PATCH bpf-next v3 01/17] bpf: Use bpf_is_subprog to check for subprogs Kumar Kartikeya Dwivedi
2023-09-12 23:31 ` [PATCH bpf-next v3 02/17] arch/x86: Implement arch_bpf_stack_walk Kumar Kartikeya Dwivedi
2023-09-12 23:32 ` [PATCH bpf-next v3 03/17] bpf: Implement support for adding hidden subprogs Kumar Kartikeya Dwivedi
2023-09-12 23:32 ` [PATCH bpf-next v3 04/17] bpf: Implement BPF exceptions Kumar Kartikeya Dwivedi
2023-09-12 23:32 ` [PATCH bpf-next v3 05/17] bpf: Refactor check_btf_func and split into two phases Kumar Kartikeya Dwivedi
2023-09-12 23:32 ` [PATCH bpf-next v3 06/17] bpf: Add support for custom exception callbacks Kumar Kartikeya Dwivedi
2023-09-12 23:32 ` [PATCH bpf-next v3 07/17] bpf: Perform CFG walk for exception callback Kumar Kartikeya Dwivedi
2023-09-12 23:32 ` [PATCH bpf-next v3 08/17] bpf: Treat first argument as return value for bpf_throw Kumar Kartikeya Dwivedi
2023-09-12 23:32 ` [PATCH bpf-next v3 09/17] mm: kasan: Declare kasan_unpoison_task_stack_below in kasan.h Kumar Kartikeya Dwivedi
2023-09-16 16:24 ` Andrey Konovalov
2023-09-12 23:32 ` [PATCH bpf-next v3 10/17] bpf: Prevent KASAN false positive with bpf_throw Kumar Kartikeya Dwivedi
2023-09-16 16:25 ` Andrey Konovalov
2023-09-18 13:20 ` Matthieu Baerts
2023-09-18 13:26 ` Kumar Kartikeya Dwivedi
2023-09-12 23:32 ` [PATCH bpf-next v3 11/17] bpf: Detect IP == ksym.end as part of BPF program Kumar Kartikeya Dwivedi
2023-09-12 23:32 ` [PATCH bpf-next v3 12/17] bpf: Disallow fentry/fexit/freplace for exception callbacks Kumar Kartikeya Dwivedi
2023-09-13 15:24 ` Puranjay Mohan
2023-09-14 12:13 ` Kumar Kartikeya Dwivedi
2023-09-16 16:44 ` Alexei Starovoitov
2023-09-16 17:30 ` Kumar Kartikeya Dwivedi
2023-09-16 19:34 ` Kumar Kartikeya Dwivedi
2023-09-18 1:56 ` Alexei Starovoitov
2023-09-12 23:32 ` [PATCH bpf-next v3 13/17] bpf: Fix kfunc callback register type handling Kumar Kartikeya Dwivedi
2023-09-12 23:32 ` [PATCH bpf-next v3 14/17] libbpf: Refactor bpf_object__reloc_code Kumar Kartikeya Dwivedi
2023-09-12 23:32 ` Kumar Kartikeya Dwivedi [this message]
2023-09-20 0:25 ` [PATCH bpf-next v3 15/17] libbpf: Add support for custom exception callbacks Andrii Nakryiko
2023-09-20 1:02 ` Kumar Kartikeya Dwivedi
2023-09-20 17:08 ` Andrii Nakryiko
2023-09-12 23:32 ` [PATCH bpf-next v3 16/17] selftests/bpf: Add BPF assertion macros Kumar Kartikeya Dwivedi
2023-09-12 23:32 ` [PATCH bpf-next v3 17/17] selftests/bpf: Add tests for BPF exceptions Kumar Kartikeya Dwivedi
2023-09-13 15:14 ` Puranjay Mohan
2023-09-13 16:12 ` Puranjay Mohan
2023-09-12 23:37 ` [PATCH bpf-next v3 00/17] Exceptions - 1/2 Kumar Kartikeya Dwivedi
2023-09-12 23:53 ` Puranjay Mohan
2023-09-16 16:50 ` patchwork-bot+netdevbpf
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20230912233214.1518551-16-memxor@gmail.com \
--to=memxor@gmail.com \
--cc=andrii@kernel.org \
--cc=ast@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=daniel@iogearbox.net \
--cc=martin.lau@linux.dev \
--cc=puranjay12@gmail.com \
--cc=void@manifault.com \
--cc=yonghong.song@linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox