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 
8 enum trunc_type {
9 	TRUNC_NONE,
10 	TRUNC_PARTIAL,
11 	TRUNC_FULL,
12 };
13 
14 static 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 
28 	err = test_log_fixup__load(skel);
29 	if (!ASSERT_ERR(err, "load_fail"))
30 		goto cleanup;
31 
32 	ASSERT_HAS_SUBSTR(log_buf,
33 			  "0: <invalid CO-RE relocation>\n"
34 			  "failed to resolve CO-RE relocation <byte_sz> ",
35 			  "log_buf_part1");
36 
37 	switch (trunc_type) {
38 	case TRUNC_NONE:
39 		ASSERT_HAS_SUBSTR(log_buf,
40 				  "struct task_struct___bad.fake_field (0:1 @ offset 4)\n",
41 				  "log_buf_part2");
42 		ASSERT_HAS_SUBSTR(log_buf,
43 				  "max_states_per_insn 0 total_states 0 peak_states 0 mark_read 0\n",
44 				  "log_buf_end");
45 		break;
46 	case TRUNC_PARTIAL:
47 		/* we should get full libbpf message patch */
48 		ASSERT_HAS_SUBSTR(log_buf,
49 				  "struct task_struct___bad.fake_field (0:1 @ offset 4)\n",
50 				  "log_buf_part2");
51 		/* we shouldn't get full end of BPF verifier log */
52 		ASSERT_NULL(strstr(log_buf, "max_states_per_insn 0 total_states 0 peak_states 0 mark_read 0\n"),
53 			    "log_buf_end");
54 		break;
55 	case TRUNC_FULL:
56 		/* we shouldn't get second part of libbpf message patch */
57 		ASSERT_NULL(strstr(log_buf, "struct task_struct___bad.fake_field (0:1 @ offset 4)\n"),
58 			    "log_buf_part2");
59 		/* we shouldn't get full end of BPF verifier log */
60 		ASSERT_NULL(strstr(log_buf, "max_states_per_insn 0 total_states 0 peak_states 0 mark_read 0\n"),
61 			    "log_buf_end");
62 		break;
63 	}
64 
65 	if (env.verbosity > VERBOSE_NONE)
66 		printf("LOG:   \n=================\n%s=================\n", log_buf);
67 cleanup:
68 	test_log_fixup__destroy(skel);
69 }
70 
71 static void bad_core_relo_subprog(void)
72 {
73 	char log_buf[8 * 1024];
74 	struct test_log_fixup* skel;
75 	int err;
76 
77 	skel = test_log_fixup__open();
78 	if (!ASSERT_OK_PTR(skel, "skel_open"))
79 		return;
80 
81 	bpf_program__set_autoload(skel->progs.bad_relo_subprog, true);
82 	bpf_program__set_log_buf(skel->progs.bad_relo_subprog, log_buf, sizeof(log_buf));
83 
84 	err = test_log_fixup__load(skel);
85 	if (!ASSERT_ERR(err, "load_fail"))
86 		goto cleanup;
87 
88 	ASSERT_HAS_SUBSTR(log_buf,
89 			  ": <invalid CO-RE relocation>\n"
90 			  "failed to resolve CO-RE relocation <byte_off> ",
91 			  "log_buf");
92 	ASSERT_HAS_SUBSTR(log_buf,
93 			  "struct task_struct___bad.fake_field_subprog (0:2 @ offset 8)\n",
94 			  "log_buf");
95 
96 	if (env.verbosity > VERBOSE_NONE)
97 		printf("LOG:   \n=================\n%s=================\n", log_buf);
98 
99 cleanup:
100 	test_log_fixup__destroy(skel);
101 }
102 
103 static void missing_map(void)
104 {
105 	char log_buf[8 * 1024];
106 	struct test_log_fixup* skel;
107 	int err;
108 
109 	skel = test_log_fixup__open();
110 	if (!ASSERT_OK_PTR(skel, "skel_open"))
111 		return;
112 
113 	bpf_map__set_autocreate(skel->maps.missing_map, false);
114 
115 	bpf_program__set_autoload(skel->progs.use_missing_map, true);
116 	bpf_program__set_log_buf(skel->progs.use_missing_map, log_buf, sizeof(log_buf));
117 
118 	err = test_log_fixup__load(skel);
119 	if (!ASSERT_ERR(err, "load_fail"))
120 		goto cleanup;
121 
122 	ASSERT_TRUE(bpf_map__autocreate(skel->maps.existing_map), "existing_map_autocreate");
123 	ASSERT_FALSE(bpf_map__autocreate(skel->maps.missing_map), "missing_map_autocreate");
124 
125 	ASSERT_HAS_SUBSTR(log_buf,
126 			  "8: <invalid BPF map reference>\n"
127 			  "BPF map 'missing_map' is referenced but wasn't created\n",
128 			  "log_buf");
129 
130 	if (env.verbosity > VERBOSE_NONE)
131 		printf("LOG:   \n=================\n%s=================\n", log_buf);
132 
133 cleanup:
134 	test_log_fixup__destroy(skel);
135 }
136 
137 void test_log_fixup(void)
138 {
139 	if (test__start_subtest("bad_core_relo_trunc_none"))
140 		bad_core_relo(0, TRUNC_NONE /* full buf */);
141 	if (test__start_subtest("bad_core_relo_trunc_partial"))
142 		bad_core_relo(300, TRUNC_PARTIAL /* truncate original log a bit */);
143 	if (test__start_subtest("bad_core_relo_trunc_full"))
144 		bad_core_relo(250, TRUNC_FULL  /* truncate also libbpf's message patch */);
145 	if (test__start_subtest("bad_core_relo_subprog"))
146 		bad_core_relo_subprog();
147 	if (test__start_subtest("missing_map"))
148 		missing_map();
149 }
150