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

Configure Feed

Select the types of activity you want to include in your feed.

libbpf: Fix BTF handling in bpf_program__clone()

Align bpf_program__clone() with bpf_object_load_prog() by gating
BTF func/line info on FEAT_BTF_FUNC kernel support, and resolve
caller-provided prog_btf_fd before checking obj->btf so that callers
with their own BTF can use clone() even when the object has no BTF
loaded.

While at it, treat func_info and line_info fields as atomic groups
to prevent mismatches between pointer and count from different sources.

Move bpf_program__clone() to libbpf 1.8.

Fixes: 970bd2dced35 ("libbpf: Introduce bpf_program__clone()")
Signed-off-by: Mykyta Yatsenko <yatsenko@meta.com>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Link: https://lore.kernel.org/bpf/20260401151640.356419-1-mykyta.yatsenko5@gmail.com

authored by

Mykyta Yatsenko and committed by
Andrii Nakryiko
1cc96e0e e25cfbec

+44 -17
+43 -16
tools/lib/bpf/libbpf.c
··· 9852 9852 { 9853 9853 LIBBPF_OPTS(bpf_prog_load_opts, attr); 9854 9854 struct bpf_object *obj; 9855 - int err, fd; 9855 + const void *info; 9856 + __u32 info_cnt, info_rec_size; 9857 + int err, fd, prog_btf_fd; 9856 9858 9857 9859 if (!prog) 9858 9860 return libbpf_err(-EINVAL); ··· 9880 9878 if (attr.token_fd) 9881 9879 attr.prog_flags |= BPF_F_TOKEN_FD; 9882 9880 9883 - /* BTF func/line info */ 9884 - if (obj->btf && btf__fd(obj->btf) >= 0) { 9885 - attr.prog_btf_fd = OPTS_GET(opts, prog_btf_fd, 0) ?: btf__fd(obj->btf); 9886 - attr.func_info = OPTS_GET(opts, func_info, NULL) ?: prog->func_info; 9887 - attr.func_info_cnt = OPTS_GET(opts, func_info_cnt, 0) ?: prog->func_info_cnt; 9888 - attr.func_info_rec_size = 9889 - OPTS_GET(opts, func_info_rec_size, 0) ?: prog->func_info_rec_size; 9890 - attr.line_info = OPTS_GET(opts, line_info, NULL) ?: prog->line_info; 9891 - attr.line_info_cnt = OPTS_GET(opts, line_info_cnt, 0) ?: prog->line_info_cnt; 9892 - attr.line_info_rec_size = 9893 - OPTS_GET(opts, line_info_rec_size, 0) ?: prog->line_info_rec_size; 9881 + prog_btf_fd = OPTS_GET(opts, prog_btf_fd, 0); 9882 + if (!prog_btf_fd && obj->btf) 9883 + prog_btf_fd = btf__fd(obj->btf); 9884 + 9885 + /* BTF func/line info: only pass if kernel supports it */ 9886 + if (kernel_supports(obj, FEAT_BTF_FUNC) && prog_btf_fd > 0) { 9887 + attr.prog_btf_fd = prog_btf_fd; 9888 + 9889 + /* func_info/line_info triples: all-or-nothing from caller */ 9890 + info = OPTS_GET(opts, func_info, NULL); 9891 + info_cnt = OPTS_GET(opts, func_info_cnt, 0); 9892 + info_rec_size = OPTS_GET(opts, func_info_rec_size, 0); 9893 + if (!!info != !!info_cnt || !!info != !!info_rec_size) { 9894 + pr_warn("prog '%s': func_info, func_info_cnt, and func_info_rec_size must all be specified or all omitted\n", 9895 + prog->name); 9896 + return libbpf_err(-EINVAL); 9897 + } 9898 + attr.func_info = info ?: prog->func_info; 9899 + attr.func_info_cnt = info ? info_cnt : prog->func_info_cnt; 9900 + attr.func_info_rec_size = info ? info_rec_size : prog->func_info_rec_size; 9901 + 9902 + info = OPTS_GET(opts, line_info, NULL); 9903 + info_cnt = OPTS_GET(opts, line_info_cnt, 0); 9904 + info_rec_size = OPTS_GET(opts, line_info_rec_size, 0); 9905 + if (!!info != !!info_cnt || !!info != !!info_rec_size) { 9906 + pr_warn("prog '%s': line_info, line_info_cnt, and line_info_rec_size must all be specified or all omitted\n", 9907 + prog->name); 9908 + return libbpf_err(-EINVAL); 9909 + } 9910 + attr.line_info = info ?: prog->line_info; 9911 + attr.line_info_cnt = info ? info_cnt : prog->line_info_cnt; 9912 + attr.line_info_rec_size = info ? info_rec_size : prog->line_info_rec_size; 9894 9913 } 9895 9914 9915 + /* Logging is caller-controlled; no fallback to prog/obj log settings */ 9896 9916 attr.log_buf = OPTS_GET(opts, log_buf, NULL); 9897 9917 attr.log_size = OPTS_GET(opts, log_size, 0); 9898 9918 attr.log_level = OPTS_GET(opts, log_level, 0); ··· 9936 9912 9937 9913 /* Re-apply caller overrides for output fields */ 9938 9914 if (OPTS_GET(opts, expected_attach_type, 0)) 9939 - attr.expected_attach_type = 9940 - OPTS_GET(opts, expected_attach_type, 0); 9915 + attr.expected_attach_type = OPTS_GET(opts, expected_attach_type, 0); 9941 9916 if (OPTS_GET(opts, attach_btf_id, 0)) 9942 9917 attr.attach_btf_id = OPTS_GET(opts, attach_btf_id, 0); 9943 9918 if (OPTS_GET(opts, attach_btf_obj_fd, 0)) 9944 - attr.attach_btf_obj_fd = 9945 - OPTS_GET(opts, attach_btf_obj_fd, 0); 9919 + attr.attach_btf_obj_fd = OPTS_GET(opts, attach_btf_obj_fd, 0); 9946 9920 9921 + /* 9922 + * Unlike bpf_object_load_prog(), we intentionally do not call bpf_prog_bind_map() 9923 + * for RODATA maps here to avoid mutating the object's state. Callers can bind the 9924 + * required maps themselves using bpf_prog_bind_map(). 9925 + */ 9947 9926 fd = bpf_prog_load(prog->type, prog->name, obj->license, prog->insns, prog->insns_cnt, 9948 9927 &attr); 9949 9928
+1 -1
tools/lib/bpf/libbpf.map
··· 452 452 bpf_map__set_exclusive_program; 453 453 bpf_map__exclusive_program; 454 454 bpf_prog_assoc_struct_ops; 455 - bpf_program__clone; 456 455 bpf_program__assoc_struct_ops; 457 456 btf__permute; 458 457 } LIBBPF_1.6.0; 459 458 460 459 LIBBPF_1.8.0 { 461 460 global: 461 + bpf_program__clone; 462 462 btf__new_empty_opts; 463 463 } LIBBPF_1.7.0;