features.c 17 KB

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