libbpf: improve early detection of doomed-to-fail BPF program loading
authorAndrii Nakryiko <andrii@kernel.org>
Tue, 7 May 2024 00:13:33 +0000 (17:13 -0700)
committerMartin KaFai Lau <martin.lau@kernel.org>
Tue, 7 May 2024 23:21:59 +0000 (16:21 -0700)
Extend libbpf's pre-load checks for BPF programs, detecting more typical
conditions that are destinated to cause BPF program failure. This is an
opportunity to provide more helpful and actionable error message to
users, instead of potentially very confusing BPF verifier log and/or
error.

In this case, we detect struct_ops BPF program that was not referenced
anywhere, but still attempted to be loaded (according to libbpf logic).
Suggest that the program might need to be used in some struct_ops
variable. User will get a message of the following kind:

  libbpf: prog 'test_1_forgotten': SEC("struct_ops") program isn't referenced anywhere, did you forget to use it?

Suggested-by: Tejun Heo <tj@kernel.org>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Link: https://lore.kernel.org/r/20240507001335.1445325-6-andrii@kernel.org
Signed-off-by: Martin KaFai Lau <martin.lau@kernel.org>
tools/lib/bpf/libbpf.c

index 04de4fb..5401f2d 100644 (file)
@@ -7372,7 +7372,11 @@ static int bpf_object_load_prog(struct bpf_object *obj, struct bpf_program *prog
        __u32 log_level = prog->log_level;
        int ret, err;
 
-       if (prog->type == BPF_PROG_TYPE_UNSPEC) {
+       /* Be more helpful by rejecting programs that can't be validated early
+        * with more meaningful and actionable error message.
+        */
+       switch (prog->type) {
+       case BPF_PROG_TYPE_UNSPEC:
                /*
                 * The program type must be set.  Most likely we couldn't find a proper
                 * section definition at load time, and thus we didn't infer the type.
@@ -7380,6 +7384,15 @@ static int bpf_object_load_prog(struct bpf_object *obj, struct bpf_program *prog
                pr_warn("prog '%s': missing BPF prog type, check ELF section name '%s'\n",
                        prog->name, prog->sec_name);
                return -EINVAL;
+       case BPF_PROG_TYPE_STRUCT_OPS:
+               if (prog->attach_btf_id == 0) {
+                       pr_warn("prog '%s': SEC(\"struct_ops\") program isn't referenced anywhere, did you forget to use it?\n",
+                               prog->name);
+                       return -EINVAL;
+               }
+               break;
+       default:
+               break;
        }
 
        if (!insns || !insns_cnt)