Home | History | Annotate | Download | only in bpf
      1 // SPDX-License-Identifier: GPL-2.0
      2 // Copyright (c) 2018 Facebook
      3 
      4 #include <stdio.h>
      5 #include <stdlib.h>
      6 #include <string.h>
      7 #include <errno.h>
      8 #include <fcntl.h>
      9 #include <syscall.h>
     10 #include <unistd.h>
     11 #include <linux/perf_event.h>
     12 #include <sys/ioctl.h>
     13 #include <sys/time.h>
     14 #include <sys/types.h>
     15 #include <sys/stat.h>
     16 
     17 #include <linux/bpf.h>
     18 #include <bpf/bpf.h>
     19 #include <bpf/libbpf.h>
     20 
     21 #include "cgroup_helpers.h"
     22 #include "bpf_rlimit.h"
     23 
     24 #define CHECK(condition, tag, format...) ({		\
     25 	int __ret = !!(condition);			\
     26 	if (__ret) {					\
     27 		printf("%s:FAIL:%s ", __func__, tag);	\
     28 		printf(format);				\
     29 	} else {					\
     30 		printf("%s:PASS:%s\n", __func__, tag);	\
     31 	}						\
     32 	__ret;						\
     33 })
     34 
     35 static int bpf_find_map(const char *test, struct bpf_object *obj,
     36 			const char *name)
     37 {
     38 	struct bpf_map *map;
     39 
     40 	map = bpf_object__find_map_by_name(obj, name);
     41 	if (!map)
     42 		return -1;
     43 	return bpf_map__fd(map);
     44 }
     45 
     46 #define TEST_CGROUP "/test-bpf-get-cgroup-id/"
     47 
     48 int main(int argc, char **argv)
     49 {
     50 	const char *probe_name = "syscalls/sys_enter_nanosleep";
     51 	const char *file = "get_cgroup_id_kern.o";
     52 	int err, bytes, efd, prog_fd, pmu_fd;
     53 	int cgroup_fd, cgidmap_fd, pidmap_fd;
     54 	struct perf_event_attr attr = {};
     55 	struct bpf_object *obj;
     56 	__u64 kcgid = 0, ucgid;
     57 	__u32 key = 0, pid;
     58 	int exit_code = 1;
     59 	char buf[256];
     60 
     61 	err = setup_cgroup_environment();
     62 	if (CHECK(err, "setup_cgroup_environment", "err %d errno %d\n", err,
     63 		  errno))
     64 		return 1;
     65 
     66 	cgroup_fd = create_and_get_cgroup(TEST_CGROUP);
     67 	if (CHECK(cgroup_fd < 0, "create_and_get_cgroup", "err %d errno %d\n",
     68 		  cgroup_fd, errno))
     69 		goto cleanup_cgroup_env;
     70 
     71 	err = join_cgroup(TEST_CGROUP);
     72 	if (CHECK(err, "join_cgroup", "err %d errno %d\n", err, errno))
     73 		goto cleanup_cgroup_env;
     74 
     75 	err = bpf_prog_load(file, BPF_PROG_TYPE_TRACEPOINT, &obj, &prog_fd);
     76 	if (CHECK(err, "bpf_prog_load", "err %d errno %d\n", err, errno))
     77 		goto cleanup_cgroup_env;
     78 
     79 	cgidmap_fd = bpf_find_map(__func__, obj, "cg_ids");
     80 	if (CHECK(cgidmap_fd < 0, "bpf_find_map", "err %d errno %d\n",
     81 		  cgidmap_fd, errno))
     82 		goto close_prog;
     83 
     84 	pidmap_fd = bpf_find_map(__func__, obj, "pidmap");
     85 	if (CHECK(pidmap_fd < 0, "bpf_find_map", "err %d errno %d\n",
     86 		  pidmap_fd, errno))
     87 		goto close_prog;
     88 
     89 	pid = getpid();
     90 	bpf_map_update_elem(pidmap_fd, &key, &pid, 0);
     91 
     92 	snprintf(buf, sizeof(buf),
     93 		 "/sys/kernel/debug/tracing/events/%s/id", probe_name);
     94 	efd = open(buf, O_RDONLY, 0);
     95 	if (CHECK(efd < 0, "open", "err %d errno %d\n", efd, errno))
     96 		goto close_prog;
     97 	bytes = read(efd, buf, sizeof(buf));
     98 	close(efd);
     99 	if (CHECK(bytes <= 0 || bytes >= sizeof(buf), "read",
    100 		  "bytes %d errno %d\n", bytes, errno))
    101 		goto close_prog;
    102 
    103 	attr.config = strtol(buf, NULL, 0);
    104 	attr.type = PERF_TYPE_TRACEPOINT;
    105 	attr.sample_type = PERF_SAMPLE_RAW;
    106 	attr.sample_period = 1;
    107 	attr.wakeup_events = 1;
    108 
    109 	/* attach to this pid so the all bpf invocations will be in the
    110 	 * cgroup associated with this pid.
    111 	 */
    112 	pmu_fd = syscall(__NR_perf_event_open, &attr, getpid(), -1, -1, 0);
    113 	if (CHECK(pmu_fd < 0, "perf_event_open", "err %d errno %d\n", pmu_fd,
    114 		  errno))
    115 		goto close_prog;
    116 
    117 	err = ioctl(pmu_fd, PERF_EVENT_IOC_ENABLE, 0);
    118 	if (CHECK(err, "perf_event_ioc_enable", "err %d errno %d\n", err,
    119 		  errno))
    120 		goto close_pmu;
    121 
    122 	err = ioctl(pmu_fd, PERF_EVENT_IOC_SET_BPF, prog_fd);
    123 	if (CHECK(err, "perf_event_ioc_set_bpf", "err %d errno %d\n", err,
    124 		  errno))
    125 		goto close_pmu;
    126 
    127 	/* trigger some syscalls */
    128 	sleep(1);
    129 
    130 	err = bpf_map_lookup_elem(cgidmap_fd, &key, &kcgid);
    131 	if (CHECK(err, "bpf_map_lookup_elem", "err %d errno %d\n", err, errno))
    132 		goto close_pmu;
    133 
    134 	ucgid = get_cgroup_id(TEST_CGROUP);
    135 	if (CHECK(kcgid != ucgid, "compare_cgroup_id",
    136 		  "kern cgid %llx user cgid %llx", kcgid, ucgid))
    137 		goto close_pmu;
    138 
    139 	exit_code = 0;
    140 	printf("%s:PASS\n", argv[0]);
    141 
    142 close_pmu:
    143 	close(pmu_fd);
    144 close_prog:
    145 	bpf_object__close(obj);
    146 cleanup_cgroup_env:
    147 	cleanup_cgroup_environment();
    148 	return exit_code;
    149 }
    150