1// SPDX-License-Identifier: GPL-2.0
2/* Copyright (c) 2022 Meta Platforms, Inc. and affiliates. */
3#include <test_progs.h>
4#include <bpf/btf.h>
5
6#include "test_log_fixup.skel.h"
7
8enum trunc_type {
9	TRUNC_NONE,
10	TRUNC_PARTIAL,
11	TRUNC_FULL,
12};
13
14static void bad_core_relo(size_t log_buf_size, enum trunc_type trunc_type)
15{
16	char log_buf[8 * 1024];
17	struct test_log_fixup* skel;
18	int err;
19
20	skel = test_log_fixup__open();
21	if (!ASSERT_OK_PTR(skel, "skel_open"))
22		return;
23
24	bpf_program__set_autoload(skel->progs.bad_relo, true);
25	memset(log_buf, 0, sizeof(log_buf));
26	bpf_program__set_log_buf(skel->progs.bad_relo, log_buf, log_buf_size ?: sizeof(log_buf));
27	bpf_program__set_log_level(skel->progs.bad_relo, 1 | 8); /* BPF_LOG_FIXED to force truncation */
28
29	err = test_log_fixup__load(skel);
30	if (!ASSERT_ERR(err, "load_fail"))
31		goto cleanup;
32
33	ASSERT_HAS_SUBSTR(log_buf,
34			  "0: <invalid CO-RE relocation>\n"
35			  "failed to resolve CO-RE relocation <byte_sz> ",
36			  "log_buf_part1");
37
38	switch (trunc_type) {
39	case TRUNC_NONE:
40		ASSERT_HAS_SUBSTR(log_buf,
41				  "struct task_struct___bad.fake_field (0:1 @ offset 4)\n",
42				  "log_buf_part2");
43		ASSERT_HAS_SUBSTR(log_buf,
44				  "max_states_per_insn 0 total_states 0 peak_states 0 mark_read 0\n",
45				  "log_buf_end");
46		break;
47	case TRUNC_PARTIAL:
48		/* we should get full libbpf message patch */
49		ASSERT_HAS_SUBSTR(log_buf,
50				  "struct task_struct___bad.fake_field (0:1 @ offset 4)\n",
51				  "log_buf_part2");
52		/* we shouldn't get full end of BPF verifier log */
53		ASSERT_NULL(strstr(log_buf, "max_states_per_insn 0 total_states 0 peak_states 0 mark_read 0\n"),
54			    "log_buf_end");
55		break;
56	case TRUNC_FULL:
57		/* we shouldn't get second part of libbpf message patch */
58		ASSERT_NULL(strstr(log_buf, "struct task_struct___bad.fake_field (0:1 @ offset 4)\n"),
59			    "log_buf_part2");
60		/* we shouldn't get full end of BPF verifier log */
61		ASSERT_NULL(strstr(log_buf, "max_states_per_insn 0 total_states 0 peak_states 0 mark_read 0\n"),
62			    "log_buf_end");
63		break;
64	}
65
66	if (env.verbosity > VERBOSE_NONE)
67		printf("LOG:   \n=================\n%s=================\n", log_buf);
68cleanup:
69	test_log_fixup__destroy(skel);
70}
71
72static void bad_core_relo_subprog(void)
73{
74	char log_buf[8 * 1024];
75	struct test_log_fixup* skel;
76	int err;
77
78	skel = test_log_fixup__open();
79	if (!ASSERT_OK_PTR(skel, "skel_open"))
80		return;
81
82	bpf_program__set_autoload(skel->progs.bad_relo_subprog, true);
83	bpf_program__set_log_buf(skel->progs.bad_relo_subprog, log_buf, sizeof(log_buf));
84
85	err = test_log_fixup__load(skel);
86	if (!ASSERT_ERR(err, "load_fail"))
87		goto cleanup;
88
89	ASSERT_HAS_SUBSTR(log_buf,
90			  ": <invalid CO-RE relocation>\n"
91			  "failed to resolve CO-RE relocation <byte_off> ",
92			  "log_buf");
93	ASSERT_HAS_SUBSTR(log_buf,
94			  "struct task_struct___bad.fake_field_subprog (0:2 @ offset 8)\n",
95			  "log_buf");
96
97	if (env.verbosity > VERBOSE_NONE)
98		printf("LOG:   \n=================\n%s=================\n", log_buf);
99
100cleanup:
101	test_log_fixup__destroy(skel);
102}
103
104static void missing_map(void)
105{
106	char log_buf[8 * 1024];
107	struct test_log_fixup* skel;
108	int err;
109
110	skel = test_log_fixup__open();
111	if (!ASSERT_OK_PTR(skel, "skel_open"))
112		return;
113
114	bpf_map__set_autocreate(skel->maps.missing_map, false);
115
116	bpf_program__set_autoload(skel->progs.use_missing_map, true);
117	bpf_program__set_log_buf(skel->progs.use_missing_map, log_buf, sizeof(log_buf));
118
119	err = test_log_fixup__load(skel);
120	if (!ASSERT_ERR(err, "load_fail"))
121		goto cleanup;
122
123	ASSERT_TRUE(bpf_map__autocreate(skel->maps.existing_map), "existing_map_autocreate");
124	ASSERT_FALSE(bpf_map__autocreate(skel->maps.missing_map), "missing_map_autocreate");
125
126	ASSERT_HAS_SUBSTR(log_buf,
127			  ": <invalid BPF map reference>\n"
128			  "BPF map 'missing_map' is referenced but wasn't created\n",
129			  "log_buf");
130
131	if (env.verbosity > VERBOSE_NONE)
132		printf("LOG:   \n=================\n%s=================\n", log_buf);
133
134cleanup:
135	test_log_fixup__destroy(skel);
136}
137
138static void missing_kfunc(void)
139{
140	char log_buf[8 * 1024];
141	struct test_log_fixup* skel;
142	int err;
143
144	skel = test_log_fixup__open();
145	if (!ASSERT_OK_PTR(skel, "skel_open"))
146		return;
147
148	bpf_program__set_autoload(skel->progs.use_missing_kfunc, true);
149	bpf_program__set_log_buf(skel->progs.use_missing_kfunc, log_buf, sizeof(log_buf));
150
151	err = test_log_fixup__load(skel);
152	if (!ASSERT_ERR(err, "load_fail"))
153		goto cleanup;
154
155	ASSERT_HAS_SUBSTR(log_buf,
156			  "0: <invalid kfunc call>\n"
157			  "kfunc 'bpf_nonexistent_kfunc' is referenced but wasn't resolved\n",
158			  "log_buf");
159
160	if (env.verbosity > VERBOSE_NONE)
161		printf("LOG:   \n=================\n%s=================\n", log_buf);
162
163cleanup:
164	test_log_fixup__destroy(skel);
165}
166
167void test_log_fixup(void)
168{
169	if (test__start_subtest("bad_core_relo_trunc_none"))
170		bad_core_relo(0, TRUNC_NONE /* full buf */);
171	if (test__start_subtest("bad_core_relo_trunc_partial"))
172		bad_core_relo(300, TRUNC_PARTIAL /* truncate original log a bit */);
173	if (test__start_subtest("bad_core_relo_trunc_full"))
174		bad_core_relo(240, TRUNC_FULL  /* truncate also libbpf's message patch */);
175	if (test__start_subtest("bad_core_relo_subprog"))
176		bad_core_relo_subprog();
177	if (test__start_subtest("missing_map"))
178		missing_map();
179	if (test__start_subtest("missing_kfunc"))
180		missing_kfunc();
181}
182