~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/lib/bpf/features.c

Version: ~ [ linux-6.11-rc3 ] ~ [ linux-6.10.4 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.45 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.104 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.164 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.223 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.281 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.319 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
  2 /* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */
  3 #include <linux/kernel.h>
  4 #include <linux/filter.h>
  5 #include "bpf.h"
  6 #include "libbpf.h"
  7 #include "libbpf_common.h"
  8 #include "libbpf_internal.h"
  9 #include "str_error.h"
 10 
 11 static inline __u64 ptr_to_u64(const void *ptr)
 12 {
 13         return (__u64)(unsigned long)ptr;
 14 }
 15 
 16 int probe_fd(int fd)
 17 {
 18         if (fd >= 0)
 19                 close(fd);
 20         return fd >= 0;
 21 }
 22 
 23 static int probe_kern_prog_name(int token_fd)
 24 {
 25         const size_t attr_sz = offsetofend(union bpf_attr, prog_token_fd);
 26         struct bpf_insn insns[] = {
 27                 BPF_MOV64_IMM(BPF_REG_0, 0),
 28                 BPF_EXIT_INSN(),
 29         };
 30         union bpf_attr attr;
 31         int ret;
 32 
 33         memset(&attr, 0, attr_sz);
 34         attr.prog_type = BPF_PROG_TYPE_SOCKET_FILTER;
 35         attr.license = ptr_to_u64("GPL");
 36         attr.insns = ptr_to_u64(insns);
 37         attr.insn_cnt = (__u32)ARRAY_SIZE(insns);
 38         attr.prog_token_fd = token_fd;
 39         if (token_fd)
 40                 attr.prog_flags |= BPF_F_TOKEN_FD;
 41         libbpf_strlcpy(attr.prog_name, "libbpf_nametest", sizeof(attr.prog_name));
 42 
 43         /* make sure loading with name works */
 44         ret = sys_bpf_prog_load(&attr, attr_sz, PROG_LOAD_ATTEMPTS);
 45         return probe_fd(ret);
 46 }
 47 
 48 static int probe_kern_global_data(int token_fd)
 49 {
 50         char *cp, errmsg[STRERR_BUFSIZE];
 51         struct bpf_insn insns[] = {
 52                 BPF_LD_MAP_VALUE(BPF_REG_1, 0, 16),
 53                 BPF_ST_MEM(BPF_DW, BPF_REG_1, 0, 42),
 54                 BPF_MOV64_IMM(BPF_REG_0, 0),
 55                 BPF_EXIT_INSN(),
 56         };
 57         LIBBPF_OPTS(bpf_map_create_opts, map_opts,
 58                 .token_fd = token_fd,
 59                 .map_flags = token_fd ? BPF_F_TOKEN_FD : 0,
 60         );
 61         LIBBPF_OPTS(bpf_prog_load_opts, prog_opts,
 62                 .token_fd = token_fd,
 63                 .prog_flags = token_fd ? BPF_F_TOKEN_FD : 0,
 64         );
 65         int ret, map, insn_cnt = ARRAY_SIZE(insns);
 66 
 67         map = bpf_map_create(BPF_MAP_TYPE_ARRAY, "libbpf_global", sizeof(int), 32, 1, &map_opts);
 68         if (map < 0) {
 69                 ret = -errno;
 70                 cp = libbpf_strerror_r(ret, errmsg, sizeof(errmsg));
 71                 pr_warn("Error in %s():%s(%d). Couldn't create simple array map.\n",
 72                         __func__, cp, -ret);
 73                 return ret;
 74         }
 75 
 76         insns[0].imm = map;
 77 
 78         ret = bpf_prog_load(BPF_PROG_TYPE_SOCKET_FILTER, NULL, "GPL", insns, insn_cnt, &prog_opts);
 79         close(map);
 80         return probe_fd(ret);
 81 }
 82 
 83 static int probe_kern_btf(int token_fd)
 84 {
 85         static const char strs[] = "\0int";
 86         __u32 types[] = {
 87                 /* int */
 88                 BTF_TYPE_INT_ENC(1, BTF_INT_SIGNED, 0, 32, 4),
 89         };
 90 
 91         return probe_fd(libbpf__load_raw_btf((char *)types, sizeof(types),
 92                                              strs, sizeof(strs), token_fd));
 93 }
 94 
 95 static int probe_kern_btf_func(int token_fd)
 96 {
 97         static const char strs[] = "\0int\0x\0a";
 98         /* void x(int a) {} */
 99         __u32 types[] = {
100                 /* int */
101                 BTF_TYPE_INT_ENC(1, BTF_INT_SIGNED, 0, 32, 4),  /* [1] */
102                 /* FUNC_PROTO */                                /* [2] */
103                 BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_FUNC_PROTO, 0, 1), 0),
104                 BTF_PARAM_ENC(7, 1),
105                 /* FUNC x */                                    /* [3] */
106                 BTF_TYPE_ENC(5, BTF_INFO_ENC(BTF_KIND_FUNC, 0, 0), 2),
107         };
108 
109         return probe_fd(libbpf__load_raw_btf((char *)types, sizeof(types),
110                                              strs, sizeof(strs), token_fd));
111 }
112 
113 static int probe_kern_btf_func_global(int token_fd)
114 {
115         static const char strs[] = "\0int\0x\0a";
116         /* static void x(int a) {} */
117         __u32 types[] = {
118                 /* int */
119                 BTF_TYPE_INT_ENC(1, BTF_INT_SIGNED, 0, 32, 4),  /* [1] */
120                 /* FUNC_PROTO */                                /* [2] */
121                 BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_FUNC_PROTO, 0, 1), 0),
122                 BTF_PARAM_ENC(7, 1),
123                 /* FUNC x BTF_FUNC_GLOBAL */                    /* [3] */
124                 BTF_TYPE_ENC(5, BTF_INFO_ENC(BTF_KIND_FUNC, 0, BTF_FUNC_GLOBAL), 2),
125         };
126 
127         return probe_fd(libbpf__load_raw_btf((char *)types, sizeof(types),
128                                              strs, sizeof(strs), token_fd));
129 }
130 
131 static int probe_kern_btf_datasec(int token_fd)
132 {
133         static const char strs[] = "\0x\0.data";
134         /* static int a; */
135         __u32 types[] = {
136                 /* int */
137                 BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4),  /* [1] */
138                 /* VAR x */                                     /* [2] */
139                 BTF_TYPE_ENC(1, BTF_INFO_ENC(BTF_KIND_VAR, 0, 0), 1),
140                 BTF_VAR_STATIC,
141                 /* DATASEC val */                               /* [3] */
142                 BTF_TYPE_ENC(3, BTF_INFO_ENC(BTF_KIND_DATASEC, 0, 1), 4),
143                 BTF_VAR_SECINFO_ENC(2, 0, 4),
144         };
145 
146         return probe_fd(libbpf__load_raw_btf((char *)types, sizeof(types),
147                                              strs, sizeof(strs), token_fd));
148 }
149 
150 static int probe_kern_btf_qmark_datasec(int token_fd)
151 {
152         static const char strs[] = "\0x\0?.data";
153         /* static int a; */
154         __u32 types[] = {
155                 /* int */
156                 BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4),  /* [1] */
157                 /* VAR x */                                     /* [2] */
158                 BTF_TYPE_ENC(1, BTF_INFO_ENC(BTF_KIND_VAR, 0, 0), 1),
159                 BTF_VAR_STATIC,
160                 /* DATASEC ?.data */                            /* [3] */
161                 BTF_TYPE_ENC(3, BTF_INFO_ENC(BTF_KIND_DATASEC, 0, 1), 4),
162                 BTF_VAR_SECINFO_ENC(2, 0, 4),
163         };
164 
165         return probe_fd(libbpf__load_raw_btf((char *)types, sizeof(types),
166                                              strs, sizeof(strs), token_fd));
167 }
168 
169 static int probe_kern_btf_float(int token_fd)
170 {
171         static const char strs[] = "\0float";
172         __u32 types[] = {
173                 /* float */
174                 BTF_TYPE_FLOAT_ENC(1, 4),
175         };
176 
177         return probe_fd(libbpf__load_raw_btf((char *)types, sizeof(types),
178                                              strs, sizeof(strs), token_fd));
179 }
180 
181 static int probe_kern_btf_decl_tag(int token_fd)
182 {
183         static const char strs[] = "\0tag";
184         __u32 types[] = {
185                 /* int */
186                 BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4),  /* [1] */
187                 /* VAR x */                                     /* [2] */
188                 BTF_TYPE_ENC(1, BTF_INFO_ENC(BTF_KIND_VAR, 0, 0), 1),
189                 BTF_VAR_STATIC,
190                 /* attr */
191                 BTF_TYPE_DECL_TAG_ENC(1, 2, -1),
192         };
193 
194         return probe_fd(libbpf__load_raw_btf((char *)types, sizeof(types),
195                                              strs, sizeof(strs), token_fd));
196 }
197 
198 static int probe_kern_btf_type_tag(int token_fd)
199 {
200         static const char strs[] = "\0tag";
201         __u32 types[] = {
202                 /* int */
203                 BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4),          /* [1] */
204                 /* attr */
205                 BTF_TYPE_TYPE_TAG_ENC(1, 1),                            /* [2] */
206                 /* ptr */
207                 BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_PTR, 0, 0), 2),   /* [3] */
208         };
209 
210         return probe_fd(libbpf__load_raw_btf((char *)types, sizeof(types),
211                                              strs, sizeof(strs), token_fd));
212 }
213 
214 static int probe_kern_array_mmap(int token_fd)
215 {
216         LIBBPF_OPTS(bpf_map_create_opts, opts,
217                 .map_flags = BPF_F_MMAPABLE | (token_fd ? BPF_F_TOKEN_FD : 0),
218                 .token_fd = token_fd,
219         );
220         int fd;
221 
222         fd = bpf_map_create(BPF_MAP_TYPE_ARRAY, "libbpf_mmap", sizeof(int), sizeof(int), 1, &opts);
223         return probe_fd(fd);
224 }
225 
226 static int probe_kern_exp_attach_type(int token_fd)
227 {
228         LIBBPF_OPTS(bpf_prog_load_opts, opts,
229                 .expected_attach_type = BPF_CGROUP_INET_SOCK_CREATE,
230                 .token_fd = token_fd,
231                 .prog_flags = token_fd ? BPF_F_TOKEN_FD : 0,
232         );
233         struct bpf_insn insns[] = {
234                 BPF_MOV64_IMM(BPF_REG_0, 0),
235                 BPF_EXIT_INSN(),
236         };
237         int fd, insn_cnt = ARRAY_SIZE(insns);
238 
239         /* use any valid combination of program type and (optional)
240          * non-zero expected attach type (i.e., not a BPF_CGROUP_INET_INGRESS)
241          * to see if kernel supports expected_attach_type field for
242          * BPF_PROG_LOAD command
243          */
244         fd = bpf_prog_load(BPF_PROG_TYPE_CGROUP_SOCK, NULL, "GPL", insns, insn_cnt, &opts);
245         return probe_fd(fd);
246 }
247 
248 static int probe_kern_probe_read_kernel(int token_fd)
249 {
250         LIBBPF_OPTS(bpf_prog_load_opts, opts,
251                 .token_fd = token_fd,
252                 .prog_flags = token_fd ? BPF_F_TOKEN_FD : 0,
253         );
254         struct bpf_insn insns[] = {
255                 BPF_MOV64_REG(BPF_REG_1, BPF_REG_10),   /* r1 = r10 (fp) */
256                 BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -8),  /* r1 += -8 */
257                 BPF_MOV64_IMM(BPF_REG_2, 8),            /* r2 = 8 */
258                 BPF_MOV64_IMM(BPF_REG_3, 0),            /* r3 = 0 */
259                 BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_probe_read_kernel),
260                 BPF_EXIT_INSN(),
261         };
262         int fd, insn_cnt = ARRAY_SIZE(insns);
263 
264         fd = bpf_prog_load(BPF_PROG_TYPE_TRACEPOINT, NULL, "GPL", insns, insn_cnt, &opts);
265         return probe_fd(fd);
266 }
267 
268 static int probe_prog_bind_map(int token_fd)
269 {
270         char *cp, errmsg[STRERR_BUFSIZE];
271         struct bpf_insn insns[] = {
272                 BPF_MOV64_IMM(BPF_REG_0, 0),
273                 BPF_EXIT_INSN(),
274         };
275         LIBBPF_OPTS(bpf_map_create_opts, map_opts,
276                 .token_fd = token_fd,
277                 .map_flags = token_fd ? BPF_F_TOKEN_FD : 0,
278         );
279         LIBBPF_OPTS(bpf_prog_load_opts, prog_opts,
280                 .token_fd = token_fd,
281                 .prog_flags = token_fd ? BPF_F_TOKEN_FD : 0,
282         );
283         int ret, map, prog, insn_cnt = ARRAY_SIZE(insns);
284 
285         map = bpf_map_create(BPF_MAP_TYPE_ARRAY, "libbpf_det_bind", sizeof(int), 32, 1, &map_opts);
286         if (map < 0) {
287                 ret = -errno;
288                 cp = libbpf_strerror_r(ret, errmsg, sizeof(errmsg));
289                 pr_warn("Error in %s():%s(%d). Couldn't create simple array map.\n",
290                         __func__, cp, -ret);
291                 return ret;
292         }
293 
294         prog = bpf_prog_load(BPF_PROG_TYPE_SOCKET_FILTER, NULL, "GPL", insns, insn_cnt, &prog_opts);
295         if (prog < 0) {
296                 close(map);
297                 return 0;
298         }
299 
300         ret = bpf_prog_bind_map(prog, map, NULL);
301 
302         close(map);
303         close(prog);
304 
305         return ret >= 0;
306 }
307 
308 static int probe_module_btf(int token_fd)
309 {
310         static const char strs[] = "\0int";
311         __u32 types[] = {
312                 /* int */
313                 BTF_TYPE_INT_ENC(1, BTF_INT_SIGNED, 0, 32, 4),
314         };
315         struct bpf_btf_info info;
316         __u32 len = sizeof(info);
317         char name[16];
318         int fd, err;
319 
320         fd = libbpf__load_raw_btf((char *)types, sizeof(types), strs, sizeof(strs), token_fd);
321         if (fd < 0)
322                 return 0; /* BTF not supported at all */
323 
324         memset(&info, 0, sizeof(info));
325         info.name = ptr_to_u64(name);
326         info.name_len = sizeof(name);
327 
328         /* check that BPF_OBJ_GET_INFO_BY_FD supports specifying name pointer;
329          * kernel's module BTF support coincides with support for
330          * name/name_len fields in struct bpf_btf_info.
331          */
332         err = bpf_btf_get_info_by_fd(fd, &info, &len);
333         close(fd);
334         return !err;
335 }
336 
337 static int probe_perf_link(int token_fd)
338 {
339         struct bpf_insn insns[] = {
340                 BPF_MOV64_IMM(BPF_REG_0, 0),
341                 BPF_EXIT_INSN(),
342         };
343         LIBBPF_OPTS(bpf_prog_load_opts, opts,
344                 .token_fd = token_fd,
345                 .prog_flags = token_fd ? BPF_F_TOKEN_FD : 0,
346         );
347         int prog_fd, link_fd, err;
348 
349         prog_fd = bpf_prog_load(BPF_PROG_TYPE_TRACEPOINT, NULL, "GPL",
350                                 insns, ARRAY_SIZE(insns), &opts);
351         if (prog_fd < 0)
352                 return -errno;
353 
354         /* use invalid perf_event FD to get EBADF, if link is supported;
355          * otherwise EINVAL should be returned
356          */
357         link_fd = bpf_link_create(prog_fd, -1, BPF_PERF_EVENT, NULL);
358         err = -errno; /* close() can clobber errno */
359 
360         if (link_fd >= 0)
361                 close(link_fd);
362         close(prog_fd);
363 
364         return link_fd < 0 && err == -EBADF;
365 }
366 
367 static int probe_uprobe_multi_link(int token_fd)
368 {
369         LIBBPF_OPTS(bpf_prog_load_opts, load_opts,
370                 .expected_attach_type = BPF_TRACE_UPROBE_MULTI,
371                 .token_fd = token_fd,
372                 .prog_flags = token_fd ? BPF_F_TOKEN_FD : 0,
373         );
374         LIBBPF_OPTS(bpf_link_create_opts, link_opts);
375         struct bpf_insn insns[] = {
376                 BPF_MOV64_IMM(BPF_REG_0, 0),
377                 BPF_EXIT_INSN(),
378         };
379         int prog_fd, link_fd, err;
380         unsigned long offset = 0;
381 
382         prog_fd = bpf_prog_load(BPF_PROG_TYPE_KPROBE, NULL, "GPL",
383                                 insns, ARRAY_SIZE(insns), &load_opts);
384         if (prog_fd < 0)
385                 return -errno;
386 
387         /* Creating uprobe in '/' binary should fail with -EBADF. */
388         link_opts.uprobe_multi.path = "/";
389         link_opts.uprobe_multi.offsets = &offset;
390         link_opts.uprobe_multi.cnt = 1;
391 
392         link_fd = bpf_link_create(prog_fd, -1, BPF_TRACE_UPROBE_MULTI, &link_opts);
393         err = -errno; /* close() can clobber errno */
394 
395         if (link_fd >= 0 || err != -EBADF) {
396                 if (link_fd >= 0)
397                         close(link_fd);
398                 close(prog_fd);
399                 return 0;
400         }
401 
402         /* Initial multi-uprobe support in kernel didn't handle PID filtering
403          * correctly (it was doing thread filtering, not process filtering).
404          * So now we'll detect if PID filtering logic was fixed, and, if not,
405          * we'll pretend multi-uprobes are not supported, if not.
406          * Multi-uprobes are used in USDT attachment logic, and we need to be
407          * conservative here, because multi-uprobe selection happens early at
408          * load time, while the use of PID filtering is known late at
409          * attachment time, at which point it's too late to undo multi-uprobe
410          * selection.
411          *
412          * Creating uprobe with pid == -1 for (invalid) '/' binary will fail
413          * early with -EINVAL on kernels with fixed PID filtering logic;
414          * otherwise -ESRCH would be returned if passed correct binary path
415          * (but we'll just get -BADF, of course).
416          */
417         link_opts.uprobe_multi.pid = -1; /* invalid PID */
418         link_opts.uprobe_multi.path = "/"; /* invalid path */
419         link_opts.uprobe_multi.offsets = &offset;
420         link_opts.uprobe_multi.cnt = 1;
421 
422         link_fd = bpf_link_create(prog_fd, -1, BPF_TRACE_UPROBE_MULTI, &link_opts);
423         err = -errno; /* close() can clobber errno */
424 
425         if (link_fd >= 0)
426                 close(link_fd);
427         close(prog_fd);
428 
429         return link_fd < 0 && err == -EINVAL;
430 }
431 
432 static int probe_kern_bpf_cookie(int token_fd)
433 {
434         struct bpf_insn insns[] = {
435                 BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_get_attach_cookie),
436                 BPF_EXIT_INSN(),
437         };
438         LIBBPF_OPTS(bpf_prog_load_opts, opts,
439                 .token_fd = token_fd,
440                 .prog_flags = token_fd ? BPF_F_TOKEN_FD : 0,
441         );
442         int ret, insn_cnt = ARRAY_SIZE(insns);
443 
444         ret = bpf_prog_load(BPF_PROG_TYPE_TRACEPOINT, NULL, "GPL", insns, insn_cnt, &opts);
445         return probe_fd(ret);
446 }
447 
448 static int probe_kern_btf_enum64(int token_fd)
449 {
450         static const char strs[] = "\0enum64";
451         __u32 types[] = {
452                 BTF_TYPE_ENC(1, BTF_INFO_ENC(BTF_KIND_ENUM64, 0, 0), 8),
453         };
454 
455         return probe_fd(libbpf__load_raw_btf((char *)types, sizeof(types),
456                                              strs, sizeof(strs), token_fd));
457 }
458 
459 static int probe_kern_arg_ctx_tag(int token_fd)
460 {
461         static const char strs[] = "\0a\0b\0arg:ctx\0";
462         const __u32 types[] = {
463                 /* [1] INT */
464                 BTF_TYPE_INT_ENC(1 /* "a" */, BTF_INT_SIGNED, 0, 32, 4),
465                 /* [2] PTR -> VOID */
466                 BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_PTR, 0, 0), 0),
467                 /* [3] FUNC_PROTO `int(void *a)` */
468                 BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_FUNC_PROTO, 0, 1), 1),
469                 BTF_PARAM_ENC(1 /* "a" */, 2),
470                 /* [4] FUNC 'a' -> FUNC_PROTO (main prog) */
471                 BTF_TYPE_ENC(1 /* "a" */, BTF_INFO_ENC(BTF_KIND_FUNC, 0, BTF_FUNC_GLOBAL), 3),
472                 /* [5] FUNC_PROTO `int(void *b __arg_ctx)` */
473                 BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_FUNC_PROTO, 0, 1), 1),
474                 BTF_PARAM_ENC(3 /* "b" */, 2),
475                 /* [6] FUNC 'b' -> FUNC_PROTO (subprog) */
476                 BTF_TYPE_ENC(3 /* "b" */, BTF_INFO_ENC(BTF_KIND_FUNC, 0, BTF_FUNC_GLOBAL), 5),
477                 /* [7] DECL_TAG 'arg:ctx' -> func 'b' arg 'b' */
478                 BTF_TYPE_DECL_TAG_ENC(5 /* "arg:ctx" */, 6, 0),
479         };
480         const struct bpf_insn insns[] = {
481                 /* main prog */
482                 BPF_CALL_REL(+1),
483                 BPF_EXIT_INSN(),
484                 /* global subprog */
485                 BPF_EMIT_CALL(BPF_FUNC_get_func_ip), /* needs PTR_TO_CTX */
486                 BPF_EXIT_INSN(),
487         };
488         const struct bpf_func_info_min func_infos[] = {
489                 { 0, 4 }, /* main prog -> FUNC 'a' */
490                 { 2, 6 }, /* subprog -> FUNC 'b' */
491         };
492         LIBBPF_OPTS(bpf_prog_load_opts, opts,
493                 .token_fd = token_fd,
494                 .prog_flags = token_fd ? BPF_F_TOKEN_FD : 0,
495         );
496         int prog_fd, btf_fd, insn_cnt = ARRAY_SIZE(insns);
497 
498         btf_fd = libbpf__load_raw_btf((char *)types, sizeof(types), strs, sizeof(strs), token_fd);
499         if (btf_fd < 0)
500                 return 0;
501 
502         opts.prog_btf_fd = btf_fd;
503         opts.func_info = &func_infos;
504         opts.func_info_cnt = ARRAY_SIZE(func_infos);
505         opts.func_info_rec_size = sizeof(func_infos[0]);
506 
507         prog_fd = bpf_prog_load(BPF_PROG_TYPE_KPROBE, "det_arg_ctx",
508                                 "GPL", insns, insn_cnt, &opts);
509         close(btf_fd);
510 
511         return probe_fd(prog_fd);
512 }
513 
514 typedef int (*feature_probe_fn)(int /* token_fd */);
515 
516 static struct kern_feature_cache feature_cache;
517 
518 static struct kern_feature_desc {
519         const char *desc;
520         feature_probe_fn probe;
521 } feature_probes[__FEAT_CNT] = {
522         [FEAT_PROG_NAME] = {
523                 "BPF program name", probe_kern_prog_name,
524         },
525         [FEAT_GLOBAL_DATA] = {
526                 "global variables", probe_kern_global_data,
527         },
528         [FEAT_BTF] = {
529                 "minimal BTF", probe_kern_btf,
530         },
531         [FEAT_BTF_FUNC] = {
532                 "BTF functions", probe_kern_btf_func,
533         },
534         [FEAT_BTF_GLOBAL_FUNC] = {
535                 "BTF global function", probe_kern_btf_func_global,
536         },
537         [FEAT_BTF_DATASEC] = {
538                 "BTF data section and variable", probe_kern_btf_datasec,
539         },
540         [FEAT_ARRAY_MMAP] = {
541                 "ARRAY map mmap()", probe_kern_array_mmap,
542         },
543         [FEAT_EXP_ATTACH_TYPE] = {
544                 "BPF_PROG_LOAD expected_attach_type attribute",
545                 probe_kern_exp_attach_type,
546         },
547         [FEAT_PROBE_READ_KERN] = {
548                 "bpf_probe_read_kernel() helper", probe_kern_probe_read_kernel,
549         },
550         [FEAT_PROG_BIND_MAP] = {
551                 "BPF_PROG_BIND_MAP support", probe_prog_bind_map,
552         },
553         [FEAT_MODULE_BTF] = {
554                 "module BTF support", probe_module_btf,
555         },
556         [FEAT_BTF_FLOAT] = {
557                 "BTF_KIND_FLOAT support", probe_kern_btf_float,
558         },
559         [FEAT_PERF_LINK] = {
560                 "BPF perf link support", probe_perf_link,
561         },
562         [FEAT_BTF_DECL_TAG] = {
563                 "BTF_KIND_DECL_TAG support", probe_kern_btf_decl_tag,
564         },
565         [FEAT_BTF_TYPE_TAG] = {
566                 "BTF_KIND_TYPE_TAG support", probe_kern_btf_type_tag,
567         },
568         [FEAT_MEMCG_ACCOUNT] = {
569                 "memcg-based memory accounting", probe_memcg_account,
570         },
571         [FEAT_BPF_COOKIE] = {
572                 "BPF cookie support", probe_kern_bpf_cookie,
573         },
574         [FEAT_BTF_ENUM64] = {
575                 "BTF_KIND_ENUM64 support", probe_kern_btf_enum64,
576         },
577         [FEAT_SYSCALL_WRAPPER] = {
578                 "Kernel using syscall wrapper", probe_kern_syscall_wrapper,
579         },
580         [FEAT_UPROBE_MULTI_LINK] = {
581                 "BPF multi-uprobe link support", probe_uprobe_multi_link,
582         },
583         [FEAT_ARG_CTX_TAG] = {
584                 "kernel-side __arg_ctx tag", probe_kern_arg_ctx_tag,
585         },
586         [FEAT_BTF_QMARK_DATASEC] = {
587                 "BTF DATASEC names starting from '?'", probe_kern_btf_qmark_datasec,
588         },
589 };
590 
591 bool feat_supported(struct kern_feature_cache *cache, enum kern_feature_id feat_id)
592 {
593         struct kern_feature_desc *feat = &feature_probes[feat_id];
594         int ret;
595 
596         /* assume global feature cache, unless custom one is provided */
597         if (!cache)
598                 cache = &feature_cache;
599 
600         if (READ_ONCE(cache->res[feat_id]) == FEAT_UNKNOWN) {
601                 ret = feat->probe(cache->token_fd);
602                 if (ret > 0) {
603                         WRITE_ONCE(cache->res[feat_id], FEAT_SUPPORTED);
604                 } else if (ret == 0) {
605                         WRITE_ONCE(cache->res[feat_id], FEAT_MISSING);
606                 } else {
607                         pr_warn("Detection of kernel %s support failed: %d\n", feat->desc, ret);
608                         WRITE_ONCE(cache->res[feat_id], FEAT_MISSING);
609                 }
610         }
611 
612         return READ_ONCE(cache->res[feat_id]) == FEAT_SUPPORTED;
613 }
614 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php