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