aboutsummaryrefslogtreecommitdiffstats
path: root/tools/lib/bpf/libbpf_probes.c
diff options
context:
space:
mode:
authorAndrii Nakryiko <andriin@fb.com>2019-05-10 17:13:15 -0400
committerDaniel Borkmann <daniel@iogearbox.net>2019-05-12 19:31:20 -0400
commitd7c4b3980c18e81c0470f5df6d96d832f446d26f (patch)
tree40533816350a46db39797d06ac310ed229a4519a /tools/lib/bpf/libbpf_probes.c
parentff1f28c03f6a7cb5ee5802288258c2fc07ed9b07 (diff)
libbpf: detect supported kernel BTF features and sanitize BTF
Depending on used versions of libbpf, Clang, and kernel, it's possible to have valid BPF object files with valid BTF information, that still won't load successfully due to Clang emitting newer BTF features (e.g., BTF_KIND_FUNC, .BTF.ext's line_info/func_info, BTF_KIND_DATASEC, etc), that are not yet supported by older kernel. This patch adds detection of BTF features and sanitizes BPF object's BTF by substituting various supported BTF kinds, which have compatible layout: - BTF_KIND_FUNC -> BTF_KIND_TYPEDEF - BTF_KIND_FUNC_PROTO -> BTF_KIND_ENUM - BTF_KIND_VAR -> BTF_KIND_INT - BTF_KIND_DATASEC -> BTF_KIND_STRUCT Replacement is done in such a way as to preserve as much information as possible (names, sizes, etc) where possible without violating kernel's validation rules. v2->v3: - remove duplicate #defines from libbpf_util.h v1->v2: - add internal libbpf_internal.h w/ common stuff - switch SK storage BTF to use new libbpf__probe_raw_btf() Reported-by: Alexei Starovoitov <ast@fb.com> Signed-off-by: Andrii Nakryiko <andriin@fb.com> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Diffstat (limited to 'tools/lib/bpf/libbpf_probes.c')
-rw-r--r--tools/lib/bpf/libbpf_probes.c73
1 files changed, 41 insertions, 32 deletions
diff --git a/tools/lib/bpf/libbpf_probes.c b/tools/lib/bpf/libbpf_probes.c
index a2c64a9ce1a6..5e2aa83f637a 100644
--- a/tools/lib/bpf/libbpf_probes.c
+++ b/tools/lib/bpf/libbpf_probes.c
@@ -15,6 +15,7 @@
15 15
16#include "bpf.h" 16#include "bpf.h"
17#include "libbpf.h" 17#include "libbpf.h"
18#include "libbpf_internal.h"
18 19
19static bool grep(const char *buffer, const char *pattern) 20static bool grep(const char *buffer, const char *pattern)
20{ 21{
@@ -132,21 +133,43 @@ bool bpf_probe_prog_type(enum bpf_prog_type prog_type, __u32 ifindex)
132 return errno != EINVAL && errno != EOPNOTSUPP; 133 return errno != EINVAL && errno != EOPNOTSUPP;
133} 134}
134 135
135static int load_btf(void) 136int libbpf__probe_raw_btf(const char *raw_types, size_t types_len,
137 const char *str_sec, size_t str_len)
136{ 138{
137#define BTF_INFO_ENC(kind, kind_flag, vlen) \ 139 struct btf_header hdr = {
138 ((!!(kind_flag) << 31) | ((kind) << 24) | ((vlen) & BTF_MAX_VLEN)) 140 .magic = BTF_MAGIC,
139#define BTF_TYPE_ENC(name, info, size_or_type) \ 141 .version = BTF_VERSION,
140 (name), (info), (size_or_type) 142 .hdr_len = sizeof(struct btf_header),
141#define BTF_INT_ENC(encoding, bits_offset, nr_bits) \ 143 .type_len = types_len,
142 ((encoding) << 24 | (bits_offset) << 16 | (nr_bits)) 144 .str_off = types_len,
143#define BTF_TYPE_INT_ENC(name, encoding, bits_offset, bits, sz) \ 145 .str_len = str_len,
144 BTF_TYPE_ENC(name, BTF_INFO_ENC(BTF_KIND_INT, 0, 0), sz), \ 146 };
145 BTF_INT_ENC(encoding, bits_offset, bits) 147 int btf_fd, btf_len;
146#define BTF_MEMBER_ENC(name, type, bits_offset) \ 148 __u8 *raw_btf;
147 (name), (type), (bits_offset) 149
148 150 btf_len = hdr.hdr_len + hdr.type_len + hdr.str_len;
149 const char btf_str_sec[] = "\0bpf_spin_lock\0val\0cnt\0l"; 151 raw_btf = malloc(btf_len);
152 if (!raw_btf)
153 return -ENOMEM;
154
155 memcpy(raw_btf, &hdr, sizeof(hdr));
156 memcpy(raw_btf + hdr.hdr_len, raw_types, hdr.type_len);
157 memcpy(raw_btf + hdr.hdr_len + hdr.type_len, str_sec, hdr.str_len);
158
159 btf_fd = bpf_load_btf(raw_btf, btf_len, NULL, 0, false);
160 if (btf_fd < 0) {
161 free(raw_btf);
162 return 0;
163 }
164
165 close(btf_fd);
166 free(raw_btf);
167 return 1;
168}
169
170static int load_sk_storage_btf(void)
171{
172 const char strs[] = "\0bpf_spin_lock\0val\0cnt\0l";
150 /* struct bpf_spin_lock { 173 /* struct bpf_spin_lock {
151 * int val; 174 * int val;
152 * }; 175 * };
@@ -155,7 +178,7 @@ static int load_btf(void)
155 * struct bpf_spin_lock l; 178 * struct bpf_spin_lock l;
156 * }; 179 * };
157 */ 180 */
158 __u32 btf_raw_types[] = { 181 __u32 types[] = {
159 /* int */ 182 /* int */
160 BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */ 183 BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
161 /* struct bpf_spin_lock */ /* [2] */ 184 /* struct bpf_spin_lock */ /* [2] */
@@ -166,23 +189,9 @@ static int load_btf(void)
166 BTF_MEMBER_ENC(19, 1, 0), /* int cnt; */ 189 BTF_MEMBER_ENC(19, 1, 0), /* int cnt; */
167 BTF_MEMBER_ENC(23, 2, 32),/* struct bpf_spin_lock l; */ 190 BTF_MEMBER_ENC(23, 2, 32),/* struct bpf_spin_lock l; */
168 }; 191 };
169 struct btf_header btf_hdr = {
170 .magic = BTF_MAGIC,
171 .version = BTF_VERSION,
172 .hdr_len = sizeof(struct btf_header),
173 .type_len = sizeof(btf_raw_types),
174 .str_off = sizeof(btf_raw_types),
175 .str_len = sizeof(btf_str_sec),
176 };
177 __u8 raw_btf[sizeof(struct btf_header) + sizeof(btf_raw_types) +
178 sizeof(btf_str_sec)];
179
180 memcpy(raw_btf, &btf_hdr, sizeof(btf_hdr));
181 memcpy(raw_btf + sizeof(btf_hdr), btf_raw_types, sizeof(btf_raw_types));
182 memcpy(raw_btf + sizeof(btf_hdr) + sizeof(btf_raw_types),
183 btf_str_sec, sizeof(btf_str_sec));
184 192
185 return bpf_load_btf(raw_btf, sizeof(raw_btf), 0, 0, 0); 193 return libbpf__probe_raw_btf((char *)types, sizeof(types),
194 strs, sizeof(strs));
186} 195}
187 196
188bool bpf_probe_map_type(enum bpf_map_type map_type, __u32 ifindex) 197bool bpf_probe_map_type(enum bpf_map_type map_type, __u32 ifindex)
@@ -222,7 +231,7 @@ bool bpf_probe_map_type(enum bpf_map_type map_type, __u32 ifindex)
222 value_size = 8; 231 value_size = 8;
223 max_entries = 0; 232 max_entries = 0;
224 map_flags = BPF_F_NO_PREALLOC; 233 map_flags = BPF_F_NO_PREALLOC;
225 btf_fd = load_btf(); 234 btf_fd = load_sk_storage_btf();
226 if (btf_fd < 0) 235 if (btf_fd < 0)
227 return false; 236 return false;
228 break; 237 break;