test_cgrp2_attach2.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443
  1. /* eBPF example program:
  2. *
  3. * - Creates arraymap in kernel with 4 bytes keys and 8 byte values
  4. *
  5. * - Loads eBPF program
  6. *
  7. * The eBPF program accesses the map passed in to store two pieces of
  8. * information. The number of invocations of the program, which maps
  9. * to the number of packets received, is stored to key 0. Key 1 is
  10. * incremented on each iteration by the number of bytes stored in
  11. * the skb. The program also stores the number of received bytes
  12. * in the cgroup storage.
  13. *
  14. * - Attaches the new program to a cgroup using BPF_PROG_ATTACH
  15. *
  16. * - Every second, reads map[0] and map[1] to see how many bytes and
  17. * packets were seen on any socket of tasks in the given cgroup.
  18. */
  19. #define _GNU_SOURCE
  20. #include <stdio.h>
  21. #include <stdlib.h>
  22. #include <assert.h>
  23. #include <sys/resource.h>
  24. #include <sys/time.h>
  25. #include <unistd.h>
  26. #include <linux/bpf.h>
  27. #include <bpf/bpf.h>
  28. #include "bpf_insn.h"
  29. #include "bpf_rlimit.h"
  30. #include "cgroup_helpers.h"
  31. #define FOO "/foo"
  32. #define BAR "/foo/bar/"
  33. #define PING_CMD "ping -c1 -w1 127.0.0.1 > /dev/null"
  34. char bpf_log_buf[BPF_LOG_BUF_SIZE];
  35. static int prog_load(int verdict)
  36. {
  37. int ret;
  38. struct bpf_insn prog[] = {
  39. BPF_MOV64_IMM(BPF_REG_0, verdict), /* r0 = verdict */
  40. BPF_EXIT_INSN(),
  41. };
  42. size_t insns_cnt = sizeof(prog) / sizeof(struct bpf_insn);
  43. ret = bpf_load_program(BPF_PROG_TYPE_CGROUP_SKB,
  44. prog, insns_cnt, "GPL", 0,
  45. bpf_log_buf, BPF_LOG_BUF_SIZE);
  46. if (ret < 0) {
  47. log_err("Loading program");
  48. printf("Output from verifier:\n%s\n-------\n", bpf_log_buf);
  49. return 0;
  50. }
  51. return ret;
  52. }
  53. static int test_foo_bar(void)
  54. {
  55. int drop_prog, allow_prog, foo = 0, bar = 0, rc = 0;
  56. allow_prog = prog_load(1);
  57. if (!allow_prog)
  58. goto err;
  59. drop_prog = prog_load(0);
  60. if (!drop_prog)
  61. goto err;
  62. if (setup_cgroup_environment())
  63. goto err;
  64. /* Create cgroup /foo, get fd, and join it */
  65. foo = create_and_get_cgroup(FOO);
  66. if (!foo)
  67. goto err;
  68. if (join_cgroup(FOO))
  69. goto err;
  70. if (bpf_prog_attach(drop_prog, foo, BPF_CGROUP_INET_EGRESS,
  71. BPF_F_ALLOW_OVERRIDE)) {
  72. log_err("Attaching prog to /foo");
  73. goto err;
  74. }
  75. printf("Attached DROP prog. This ping in cgroup /foo should fail...\n");
  76. assert(system(PING_CMD) != 0);
  77. /* Create cgroup /foo/bar, get fd, and join it */
  78. bar = create_and_get_cgroup(BAR);
  79. if (!bar)
  80. goto err;
  81. if (join_cgroup(BAR))
  82. goto err;
  83. printf("Attached DROP prog. This ping in cgroup /foo/bar should fail...\n");
  84. assert(system(PING_CMD) != 0);
  85. if (bpf_prog_attach(allow_prog, bar, BPF_CGROUP_INET_EGRESS,
  86. BPF_F_ALLOW_OVERRIDE)) {
  87. log_err("Attaching prog to /foo/bar");
  88. goto err;
  89. }
  90. printf("Attached PASS prog. This ping in cgroup /foo/bar should pass...\n");
  91. assert(system(PING_CMD) == 0);
  92. if (bpf_prog_detach(bar, BPF_CGROUP_INET_EGRESS)) {
  93. log_err("Detaching program from /foo/bar");
  94. goto err;
  95. }
  96. printf("Detached PASS from /foo/bar while DROP is attached to /foo.\n"
  97. "This ping in cgroup /foo/bar should fail...\n");
  98. assert(system(PING_CMD) != 0);
  99. if (bpf_prog_attach(allow_prog, bar, BPF_CGROUP_INET_EGRESS,
  100. BPF_F_ALLOW_OVERRIDE)) {
  101. log_err("Attaching prog to /foo/bar");
  102. goto err;
  103. }
  104. if (bpf_prog_detach(foo, BPF_CGROUP_INET_EGRESS)) {
  105. log_err("Detaching program from /foo");
  106. goto err;
  107. }
  108. printf("Attached PASS from /foo/bar and detached DROP from /foo.\n"
  109. "This ping in cgroup /foo/bar should pass...\n");
  110. assert(system(PING_CMD) == 0);
  111. if (bpf_prog_attach(allow_prog, bar, BPF_CGROUP_INET_EGRESS,
  112. BPF_F_ALLOW_OVERRIDE)) {
  113. log_err("Attaching prog to /foo/bar");
  114. goto err;
  115. }
  116. if (!bpf_prog_attach(allow_prog, bar, BPF_CGROUP_INET_EGRESS, 0)) {
  117. errno = 0;
  118. log_err("Unexpected success attaching prog to /foo/bar");
  119. goto err;
  120. }
  121. if (bpf_prog_detach(bar, BPF_CGROUP_INET_EGRESS)) {
  122. log_err("Detaching program from /foo/bar");
  123. goto err;
  124. }
  125. if (!bpf_prog_detach(foo, BPF_CGROUP_INET_EGRESS)) {
  126. errno = 0;
  127. log_err("Unexpected success in double detach from /foo");
  128. goto err;
  129. }
  130. if (bpf_prog_attach(allow_prog, foo, BPF_CGROUP_INET_EGRESS, 0)) {
  131. log_err("Attaching non-overridable prog to /foo");
  132. goto err;
  133. }
  134. if (!bpf_prog_attach(allow_prog, bar, BPF_CGROUP_INET_EGRESS, 0)) {
  135. errno = 0;
  136. log_err("Unexpected success attaching non-overridable prog to /foo/bar");
  137. goto err;
  138. }
  139. if (!bpf_prog_attach(allow_prog, bar, BPF_CGROUP_INET_EGRESS,
  140. BPF_F_ALLOW_OVERRIDE)) {
  141. errno = 0;
  142. log_err("Unexpected success attaching overridable prog to /foo/bar");
  143. goto err;
  144. }
  145. if (!bpf_prog_attach(allow_prog, foo, BPF_CGROUP_INET_EGRESS,
  146. BPF_F_ALLOW_OVERRIDE)) {
  147. errno = 0;
  148. log_err("Unexpected success attaching overridable prog to /foo");
  149. goto err;
  150. }
  151. if (bpf_prog_attach(drop_prog, foo, BPF_CGROUP_INET_EGRESS, 0)) {
  152. log_err("Attaching different non-overridable prog to /foo");
  153. goto err;
  154. }
  155. goto out;
  156. err:
  157. rc = 1;
  158. out:
  159. close(foo);
  160. close(bar);
  161. cleanup_cgroup_environment();
  162. if (!rc)
  163. printf("### override:PASS\n");
  164. else
  165. printf("### override:FAIL\n");
  166. return rc;
  167. }
  168. static int map_fd = -1;
  169. static int prog_load_cnt(int verdict, int val)
  170. {
  171. int cgroup_storage_fd;
  172. if (map_fd < 0)
  173. map_fd = bpf_create_map(BPF_MAP_TYPE_ARRAY, 4, 8, 1, 0);
  174. if (map_fd < 0) {
  175. printf("failed to create map '%s'\n", strerror(errno));
  176. return -1;
  177. }
  178. cgroup_storage_fd = bpf_create_map(BPF_MAP_TYPE_CGROUP_STORAGE,
  179. sizeof(struct bpf_cgroup_storage_key), 8, 0, 0);
  180. if (cgroup_storage_fd < 0) {
  181. printf("failed to create map '%s'\n", strerror(errno));
  182. return -1;
  183. }
  184. struct bpf_insn prog[] = {
  185. BPF_MOV32_IMM(BPF_REG_0, 0),
  186. BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_0, -4), /* *(u32 *)(fp - 4) = r0 */
  187. BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
  188. BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -4), /* r2 = fp - 4 */
  189. BPF_LD_MAP_FD(BPF_REG_1, map_fd),
  190. BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
  191. BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 2),
  192. BPF_MOV64_IMM(BPF_REG_1, val), /* r1 = 1 */
  193. BPF_RAW_INSN(BPF_STX | BPF_XADD | BPF_DW, BPF_REG_0, BPF_REG_1, 0, 0), /* xadd r0 += r1 */
  194. BPF_LD_MAP_FD(BPF_REG_1, cgroup_storage_fd),
  195. BPF_MOV64_IMM(BPF_REG_2, 0),
  196. BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_get_local_storage),
  197. BPF_MOV64_IMM(BPF_REG_1, val),
  198. BPF_RAW_INSN(BPF_STX | BPF_XADD | BPF_W, BPF_REG_0, BPF_REG_1, 0, 0),
  199. BPF_MOV64_IMM(BPF_REG_0, verdict), /* r0 = verdict */
  200. BPF_EXIT_INSN(),
  201. };
  202. size_t insns_cnt = sizeof(prog) / sizeof(struct bpf_insn);
  203. int ret;
  204. ret = bpf_load_program(BPF_PROG_TYPE_CGROUP_SKB,
  205. prog, insns_cnt, "GPL", 0,
  206. bpf_log_buf, BPF_LOG_BUF_SIZE);
  207. if (ret < 0) {
  208. log_err("Loading program");
  209. printf("Output from verifier:\n%s\n-------\n", bpf_log_buf);
  210. return 0;
  211. }
  212. close(cgroup_storage_fd);
  213. return ret;
  214. }
  215. static int test_multiprog(void)
  216. {
  217. __u32 prog_ids[4], prog_cnt = 0, attach_flags, saved_prog_id;
  218. int cg1 = 0, cg2 = 0, cg3 = 0, cg4 = 0, cg5 = 0, key = 0;
  219. int drop_prog, allow_prog[6] = {}, rc = 0;
  220. unsigned long long value;
  221. int i = 0;
  222. for (i = 0; i < 6; i++) {
  223. allow_prog[i] = prog_load_cnt(1, 1 << i);
  224. if (!allow_prog[i])
  225. goto err;
  226. }
  227. drop_prog = prog_load_cnt(0, 1);
  228. if (!drop_prog)
  229. goto err;
  230. if (setup_cgroup_environment())
  231. goto err;
  232. cg1 = create_and_get_cgroup("/cg1");
  233. if (!cg1)
  234. goto err;
  235. cg2 = create_and_get_cgroup("/cg1/cg2");
  236. if (!cg2)
  237. goto err;
  238. cg3 = create_and_get_cgroup("/cg1/cg2/cg3");
  239. if (!cg3)
  240. goto err;
  241. cg4 = create_and_get_cgroup("/cg1/cg2/cg3/cg4");
  242. if (!cg4)
  243. goto err;
  244. cg5 = create_and_get_cgroup("/cg1/cg2/cg3/cg4/cg5");
  245. if (!cg5)
  246. goto err;
  247. if (join_cgroup("/cg1/cg2/cg3/cg4/cg5"))
  248. goto err;
  249. if (bpf_prog_attach(allow_prog[0], cg1, BPF_CGROUP_INET_EGRESS,
  250. BPF_F_ALLOW_MULTI)) {
  251. log_err("Attaching prog to cg1");
  252. goto err;
  253. }
  254. if (!bpf_prog_attach(allow_prog[0], cg1, BPF_CGROUP_INET_EGRESS,
  255. BPF_F_ALLOW_MULTI)) {
  256. log_err("Unexpected success attaching the same prog to cg1");
  257. goto err;
  258. }
  259. if (bpf_prog_attach(allow_prog[1], cg1, BPF_CGROUP_INET_EGRESS,
  260. BPF_F_ALLOW_MULTI)) {
  261. log_err("Attaching prog2 to cg1");
  262. goto err;
  263. }
  264. if (bpf_prog_attach(allow_prog[2], cg2, BPF_CGROUP_INET_EGRESS,
  265. BPF_F_ALLOW_OVERRIDE)) {
  266. log_err("Attaching prog to cg2");
  267. goto err;
  268. }
  269. if (bpf_prog_attach(allow_prog[3], cg3, BPF_CGROUP_INET_EGRESS,
  270. BPF_F_ALLOW_MULTI)) {
  271. log_err("Attaching prog to cg3");
  272. goto err;
  273. }
  274. if (bpf_prog_attach(allow_prog[4], cg4, BPF_CGROUP_INET_EGRESS,
  275. BPF_F_ALLOW_OVERRIDE)) {
  276. log_err("Attaching prog to cg4");
  277. goto err;
  278. }
  279. if (bpf_prog_attach(allow_prog[5], cg5, BPF_CGROUP_INET_EGRESS, 0)) {
  280. log_err("Attaching prog to cg5");
  281. goto err;
  282. }
  283. assert(system(PING_CMD) == 0);
  284. assert(bpf_map_lookup_elem(map_fd, &key, &value) == 0);
  285. assert(value == 1 + 2 + 8 + 32);
  286. /* query the number of effective progs in cg5 */
  287. assert(bpf_prog_query(cg5, BPF_CGROUP_INET_EGRESS, BPF_F_QUERY_EFFECTIVE,
  288. NULL, NULL, &prog_cnt) == 0);
  289. assert(prog_cnt == 4);
  290. /* retrieve prog_ids of effective progs in cg5 */
  291. assert(bpf_prog_query(cg5, BPF_CGROUP_INET_EGRESS, BPF_F_QUERY_EFFECTIVE,
  292. &attach_flags, prog_ids, &prog_cnt) == 0);
  293. assert(prog_cnt == 4);
  294. assert(attach_flags == 0);
  295. saved_prog_id = prog_ids[0];
  296. /* check enospc handling */
  297. prog_ids[0] = 0;
  298. prog_cnt = 2;
  299. assert(bpf_prog_query(cg5, BPF_CGROUP_INET_EGRESS, BPF_F_QUERY_EFFECTIVE,
  300. &attach_flags, prog_ids, &prog_cnt) == -1 &&
  301. errno == ENOSPC);
  302. assert(prog_cnt == 4);
  303. /* check that prog_ids are returned even when buffer is too small */
  304. assert(prog_ids[0] == saved_prog_id);
  305. /* retrieve prog_id of single attached prog in cg5 */
  306. prog_ids[0] = 0;
  307. assert(bpf_prog_query(cg5, BPF_CGROUP_INET_EGRESS, 0,
  308. NULL, prog_ids, &prog_cnt) == 0);
  309. assert(prog_cnt == 1);
  310. assert(prog_ids[0] == saved_prog_id);
  311. /* detach bottom program and ping again */
  312. if (bpf_prog_detach2(-1, cg5, BPF_CGROUP_INET_EGRESS)) {
  313. log_err("Detaching prog from cg5");
  314. goto err;
  315. }
  316. value = 0;
  317. assert(bpf_map_update_elem(map_fd, &key, &value, 0) == 0);
  318. assert(system(PING_CMD) == 0);
  319. assert(bpf_map_lookup_elem(map_fd, &key, &value) == 0);
  320. assert(value == 1 + 2 + 8 + 16);
  321. /* detach 3rd from bottom program and ping again */
  322. errno = 0;
  323. if (!bpf_prog_detach2(0, cg3, BPF_CGROUP_INET_EGRESS)) {
  324. log_err("Unexpected success on detach from cg3");
  325. goto err;
  326. }
  327. if (bpf_prog_detach2(allow_prog[3], cg3, BPF_CGROUP_INET_EGRESS)) {
  328. log_err("Detaching from cg3");
  329. goto err;
  330. }
  331. value = 0;
  332. assert(bpf_map_update_elem(map_fd, &key, &value, 0) == 0);
  333. assert(system(PING_CMD) == 0);
  334. assert(bpf_map_lookup_elem(map_fd, &key, &value) == 0);
  335. assert(value == 1 + 2 + 16);
  336. /* detach 2nd from bottom program and ping again */
  337. if (bpf_prog_detach2(-1, cg4, BPF_CGROUP_INET_EGRESS)) {
  338. log_err("Detaching prog from cg4");
  339. goto err;
  340. }
  341. value = 0;
  342. assert(bpf_map_update_elem(map_fd, &key, &value, 0) == 0);
  343. assert(system(PING_CMD) == 0);
  344. assert(bpf_map_lookup_elem(map_fd, &key, &value) == 0);
  345. assert(value == 1 + 2 + 4);
  346. prog_cnt = 4;
  347. assert(bpf_prog_query(cg5, BPF_CGROUP_INET_EGRESS, BPF_F_QUERY_EFFECTIVE,
  348. &attach_flags, prog_ids, &prog_cnt) == 0);
  349. assert(prog_cnt == 3);
  350. assert(attach_flags == 0);
  351. assert(bpf_prog_query(cg5, BPF_CGROUP_INET_EGRESS, 0,
  352. NULL, prog_ids, &prog_cnt) == 0);
  353. assert(prog_cnt == 0);
  354. goto out;
  355. err:
  356. rc = 1;
  357. out:
  358. for (i = 0; i < 6; i++)
  359. if (allow_prog[i] > 0)
  360. close(allow_prog[i]);
  361. close(cg1);
  362. close(cg2);
  363. close(cg3);
  364. close(cg4);
  365. close(cg5);
  366. cleanup_cgroup_environment();
  367. if (!rc)
  368. printf("### multi:PASS\n");
  369. else
  370. printf("### multi:FAIL\n");
  371. return rc;
  372. }
  373. int main(int argc, char **argv)
  374. {
  375. int rc = 0;
  376. rc = test_foo_bar();
  377. if (rc)
  378. return rc;
  379. return test_multiprog();
  380. }