Skip to content

Commit 197afc6

Browse files
anakryikoborkmann
authored andcommitted
libbpf: Don't attempt to load unused subprog as an entry-point BPF program
If BPF code contains unused BPF subprogram and there are no other subprogram calls (which can realistically happen in real-world applications given sufficiently smart Clang code optimizations), libbpf will erroneously assume that subprograms are entry-point programs and will attempt to load them with UNSPEC program type. Fix by not relying on subcall instructions and rather detect it based on the structure of BPF object's sections. Fixes: 9a94f27 ("tools: libbpf: restore the ability to load programs from .text section") Reported-by: Dmitrii Banshchikov <dbanschikov@fb.com> Signed-off-by: Andrii Nakryiko <andrii@kernel.org> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net> Acked-by: Yonghong Song <yhs@fb.com> Link: https://lore.kernel.org/bpf/20201107000251.256821-1-andrii@kernel.org
1 parent 4e0396c commit 197afc6

File tree

3 files changed

+40
-10
lines changed

3 files changed

+40
-10
lines changed

tools/lib/bpf/libbpf.c

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -560,8 +560,6 @@ bpf_object__init_prog(struct bpf_object *obj, struct bpf_program *prog,
560560
const char *name, size_t sec_idx, const char *sec_name,
561561
size_t sec_off, void *insn_data, size_t insn_data_sz)
562562
{
563-
int i;
564-
565563
if (insn_data_sz == 0 || insn_data_sz % BPF_INSN_SZ || sec_off % BPF_INSN_SZ) {
566564
pr_warn("sec '%s': corrupted program '%s', offset %zu, size %zu\n",
567565
sec_name, name, sec_off, insn_data_sz);
@@ -600,13 +598,6 @@ bpf_object__init_prog(struct bpf_object *obj, struct bpf_program *prog,
600598
goto errout;
601599
memcpy(prog->insns, insn_data, insn_data_sz);
602600

603-
for (i = 0; i < prog->insns_cnt; i++) {
604-
if (insn_is_subprog_call(&prog->insns[i])) {
605-
obj->has_subcalls = true;
606-
break;
607-
}
608-
}
609-
610601
return 0;
611602
errout:
612603
pr_warn("sec '%s': failed to allocate memory for prog '%s'\n", sec_name, name);
@@ -3280,7 +3271,19 @@ bpf_object__find_program_by_title(const struct bpf_object *obj,
32803271
static bool prog_is_subprog(const struct bpf_object *obj,
32813272
const struct bpf_program *prog)
32823273
{
3283-
return prog->sec_idx == obj->efile.text_shndx && obj->has_subcalls;
3274+
/* For legacy reasons, libbpf supports an entry-point BPF programs
3275+
* without SEC() attribute, i.e., those in the .text section. But if
3276+
* there are 2 or more such programs in the .text section, they all
3277+
* must be subprograms called from entry-point BPF programs in
3278+
* designated SEC()'tions, otherwise there is no way to distinguish
3279+
* which of those programs should be loaded vs which are a subprogram.
3280+
* Similarly, if there is a function/program in .text and at least one
3281+
* other BPF program with custom SEC() attribute, then we just assume
3282+
* .text programs are subprograms (even if they are not called from
3283+
* other programs), because libbpf never explicitly supported mixing
3284+
* SEC()-designated BPF programs and .text entry-point BPF programs.
3285+
*/
3286+
return prog->sec_idx == obj->efile.text_shndx && obj->nr_programs > 1;
32843287
}
32853288

32863289
struct bpf_program *

tools/testing/selftests/bpf/prog_tests/subprogs.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,14 @@
33
#include <test_progs.h>
44
#include <time.h>
55
#include "test_subprogs.skel.h"
6+
#include "test_subprogs_unused.skel.h"
67

78
static int duration;
89

910
void test_subprogs(void)
1011
{
1112
struct test_subprogs *skel;
13+
struct test_subprogs_unused *skel2;
1214
int err;
1315

1416
skel = test_subprogs__open_and_load();
@@ -26,6 +28,10 @@ void test_subprogs(void)
2628
CHECK(skel->bss->res3 != 19, "res3", "got %d, exp %d\n", skel->bss->res3, 19);
2729
CHECK(skel->bss->res4 != 36, "res4", "got %d, exp %d\n", skel->bss->res4, 36);
2830

31+
skel2 = test_subprogs_unused__open_and_load();
32+
ASSERT_OK_PTR(skel2, "unused_progs_skel");
33+
test_subprogs_unused__destroy(skel2);
34+
2935
cleanup:
3036
test_subprogs__destroy(skel);
3137
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#include "vmlinux.h"
2+
#include <bpf/bpf_helpers.h>
3+
#include <bpf/bpf_core_read.h>
4+
5+
const char LICENSE[] SEC("license") = "GPL";
6+
7+
__attribute__((maybe_unused)) __noinline int unused1(int x)
8+
{
9+
return x + 1;
10+
}
11+
12+
static __attribute__((maybe_unused)) __noinline int unused2(int x)
13+
{
14+
return x + 2;
15+
}
16+
17+
SEC("raw_tp/sys_enter")
18+
int main_prog(void *ctx)
19+
{
20+
return 0;
21+
}

0 commit comments

Comments
 (0)