Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

libbpf: improve early detection of doomed-to-fail BPF program loading

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>

authored by

Andrii Nakryiko and committed by
Martin KaFai Lau
c78420ba 548c2ede

+14 -1
+14 -1
tools/lib/bpf/libbpf.c
··· 7372 7372 __u32 log_level = prog->log_level; 7373 7373 int ret, err; 7374 7374 7375 - if (prog->type == BPF_PROG_TYPE_UNSPEC) { 7375 + /* Be more helpful by rejecting programs that can't be validated early 7376 + * with more meaningful and actionable error message. 7377 + */ 7378 + switch (prog->type) { 7379 + case BPF_PROG_TYPE_UNSPEC: 7376 7380 /* 7377 7381 * The program type must be set. Most likely we couldn't find a proper 7378 7382 * section definition at load time, and thus we didn't infer the type. ··· 7384 7380 pr_warn("prog '%s': missing BPF prog type, check ELF section name '%s'\n", 7385 7381 prog->name, prog->sec_name); 7386 7382 return -EINVAL; 7383 + case BPF_PROG_TYPE_STRUCT_OPS: 7384 + if (prog->attach_btf_id == 0) { 7385 + pr_warn("prog '%s': SEC(\"struct_ops\") program isn't referenced anywhere, did you forget to use it?\n", 7386 + prog->name); 7387 + return -EINVAL; 7388 + } 7389 + break; 7390 + default: 7391 + break; 7387 7392 } 7388 7393 7389 7394 if (!insns || !insns_cnt)