From: Ren Zhijie renzhijie2@huawei.com
maillist inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I5F6X6 CVE: NA
Reference: https://lore.kernel.org/all/20210916162451.709260-1-guro@fb.com/
-------------------
* Load/attach a BPF program that hooks to 3 BPF_SCHED_HOOK functions: cfs_check_preempt_tick, cfs_check_preempt_wakeup, cfs_wakeup_preempt_entity * Create a child process as prioritize task which will be captured by bpf test prog. * Create cgroup in cgroupv2 and join it which will be captured by bpf test prog. * Verify 3 helpers can trace task with the specified tgidpid or belongs to specified cgroup,using the shared global variables for the bpf program loaded and attached.
Signed-off-by: Ren Zhijie renzhijie2@huawei.com --- .../selftests/bpf/prog_tests/test_sched.c | 160 ++++++++++++++ tools/testing/selftests/bpf/progs/sched.c | 203 ++++++++++++++++++ 2 files changed, 363 insertions(+) create mode 100644 tools/testing/selftests/bpf/prog_tests/test_sched.c create mode 100644 tools/testing/selftests/bpf/progs/sched.c
diff --git a/tools/testing/selftests/bpf/prog_tests/test_sched.c b/tools/testing/selftests/bpf/prog_tests/test_sched.c new file mode 100644 index 000000000000..dc1fdbab3ce0 --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/test_sched.c @@ -0,0 +1,160 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* + * Copyright (C) 2022 Huawei LLC. + */ + +#include <test_progs.h> + +#include "sched.skel.h" +#include "cgroup_helpers.h" + +// #define debug(args...) printf(args) +#define debug(args...) + +#define CHECK_TGIDPID_MODE(HOOKNAME, TGIDPID) \ + do { \ + if (skel->bss->HOOKNAME##_tgidpid_ret) { \ + CHECK(skel->bss->HOOKNAME##_tgidpid_ret != TGIDPID, \ + #HOOKNAME"_tgidpid", #HOOKNAME"_tgidpid_ret %lu\n", \ + skel->bss->HOOKNAME##_tgidpid_ret); \ + } \ + } while (0) + +#define CHECK_CGID_MODE(HOOKNAME, PID, CGID) \ + do { \ + if (skel->bss->HOOKNAME##_cgid_ret) { \ + if (skel->bss->HOOKNAME##_cgid_ret) { \ + CHECK(skel->bss->HOOKNAME##_cgid_pid_ret != PID, \ + #HOOKNAME"_cgid_pid", #HOOKNAME"_cgid_pid_ret %u\n", \ + skel->bss->HOOKNAME##_cgid_pid_ret); \ + } \ + if (skel->bss->HOOKNAME##_cgid_se_to_cgid_ret) { \ + CHECK(skel->bss->HOOKNAME##_cgid_se_to_cgid_ret != CGID, \ + #HOOKNAME"_cgid_se_to_cgid", \ + #HOOKNAME"_cgid_se_to_cgid_ret %lu\n", \ + skel->bss->HOOKNAME##_cgid_se_to_cgid_ret); \ + } \ + } \ + } while (0) + +static void work(void) +{ + int i; + + for (i = 0; i < 1000; i++) + usleep(1000); +} + +int create_prioritize_task(int *child_pid) +{ + int cpid; + + cpid = fork(); + if (cpid == -1) { + return -ECHILD; + } else if (cpid == 0) { + work(); + exit(0); + } else { + *child_pid = cpid; + debug("prioritize task(s) with pid %d\n", *child_pid); + return 0; + } + return -EINVAL; +} + +void test_sched_tgidpid_mode(void) +{ + struct sched *skel = NULL; + int err, duration = 0, child_pid = 0, tgid = 0, cgid = 0; + int status = 0; + + skel = sched__open(); + if (CHECK(!skel, "open", "sched open failed\n")) + goto close_prog; + + err = sched__load(skel); + if (CHECK(err, "load", "sched load failed: %d\n", err)) + goto close_prog; + + err = sched__attach(skel); + if (CHECK(err, "attach", "sched attach failed: %d\n", err)) + goto close_prog; + + err = create_prioritize_task(&child_pid); + if (CHECK(err < 0, "create_prior_task", "err %d errno %d\n", err, errno)) + goto close_prog; + + tgid = child_pid; + debug("prioritize task(s) with tgid %d\n", tgid); + skel->bss->tgidpid = (unsigned long)tgid << 32 | child_pid; + debug("prioritize task(s) with tgidpid %lu\n", skel->bss->tgidpid); + skel->bss->cgid = cgid; + + if (child_pid) + err = waitpid(child_pid, &status, 0); + if (CHECK(err == -1 && errno != ECHILD, "waitpid", "failed %d", errno)) + return; + + CHECK_TGIDPID_MODE(tick, skel->bss->tgidpid); + CHECK_TGIDPID_MODE(wakeup, skel->bss->tgidpid); + CHECK_TGIDPID_MODE(entity, skel->bss->tgidpid); + +close_prog: + sched__destroy(skel); +} + +#define TEST_CGROUP "/test-bpf-sched-cgid-mode/" + +void test_sched_cgid_mode(void) +{ + struct sched *skel = NULL; + int err, duration = 0, cgid = 0, cgroup_fd = 0, pid = 0; + + skel = sched__open(); + if (CHECK(!skel, "open", "sched open failed\n")) + goto close_prog; + + err = sched__load(skel); + if (CHECK(err, "load", "sched load failed: %d\n", err)) + goto close_prog; + + err = sched__attach(skel); + if (CHECK(err, "attach", "sched attach failed: %d\n", err)) + goto close_prog; + + cgroup_fd = cgroup_setup_and_join(TEST_CGROUP); + if (CHECK(cgroup_fd < 0, "cgroup_setup_and_join", "err %d errno %d\n", cgroup_fd, errno)) + goto cleanup_cgroup_env; + + cgid = get_cgroup_id(TEST_CGROUP); + if (CHECK(!cgid, "get_cgroup_id", "err %d", cgid)) + goto cleanup_cgroup_env; + + skel->bss->tgidpid = 0; + skel->bss->cgid = cgid; + debug("cgid %d\n", cgid); + + /* trigger sched hook */ + work(); + + pid = getpid(); + + CHECK_CGID_MODE(tick, pid, cgid); + CHECK_CGID_MODE(wakeup, pid, cgid); + CHECK_CGID_MODE(entity, pid, cgid); + +cleanup_cgroup_env: + cleanup_cgroup_environment(); +close_prog: + sched__destroy(skel); +} + +void test_test_sched(int argc, char **argv) +{ + if (test__start_subtest("sched_tgidpid_mode")) + test_sched_tgidpid_mode(); + if (test__start_subtest("sched_cgid_mode")) + test_sched_cgid_mode(); +} diff --git a/tools/testing/selftests/bpf/progs/sched.c b/tools/testing/selftests/bpf/progs/sched.c new file mode 100644 index 000000000000..23b057b1d155 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/sched.c @@ -0,0 +1,203 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* + * Copyright 2022 Huawei LLC. + */ + +#include "vmlinux.h" +#include <bpf/bpf_helpers.h> +#include <bpf/bpf_tracing.h> +#include <errno.h> + +#ifndef NULL +#define NULL 0 +#endif + +struct { + __uint(type, BPF_MAP_TYPE_ARRAY); + __uint(max_entries, 1); + __type(key, __u32); + __type(value, __u64); +} array SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_HASH); + __uint(max_entries, 1); + __type(key, __u32); + __type(value, __u64); +} hash SEC(".maps"); + +char _license[] SEC("license") = "GPL"; + +unsigned long tgidpid; +unsigned long cgid; + +unsigned long tick_tgidpid_ret; +unsigned int tick_cgid_ret; +unsigned int tick_cgid_pid_ret; +unsigned long tick_cgid_se_to_cgid_ret; + +unsigned long wakeup_tgidpid_ret; +unsigned int wakeup_cgid_ret; +unsigned int wakeup_cgid_pid_ret; +unsigned long wakeup_cgid_se_to_cgid_ret; + +unsigned long entity_tgidpid_ret; +unsigned int entity_cgid_ret; +unsigned int entity_cgid_pid_ret; +unsigned long entity_cgid_se_to_cgid_ret; + +// #define debug(args...) bpf_printk(args) +#define debug(args...) + +SEC("sched/cfs_check_preempt_tick") +int BPF_PROG(test_check_preempt_tick, struct sched_entity *curr, unsigned long delta_exec) +{ + if (curr == NULL) + return 0; + + if (tgidpid) { + unsigned long curr_tgidpid; + + curr_tgidpid = bpf_sched_entity_to_tgidpid(curr); + + if (curr_tgidpid == tgidpid) { + tick_tgidpid_ret = curr_tgidpid; + debug("tick tgid %d pid %d tick_tgidpid_ret %lu", curr_tgidpid >> 32, + curr_tgidpid & 0xFFFFFFFF, tick_tgidpid_ret); + } + } else if (cgid) { + if (bpf_sched_entity_belongs_to_cgrp(curr, cgid)) { + unsigned long curr_tgidpid; + + tick_cgid_ret = 1; + + if (!curr->my_q) { + curr_tgidpid = bpf_sched_entity_to_tgidpid(curr); + tick_cgid_pid_ret = curr_tgidpid & 0xFFFFFFFF; + debug("tick tick_cgid_ret %d curr_pid %d", tick_cgid_ret, + tick_cgid_pid_ret); + } + + if (curr->my_q) { + tick_cgid_se_to_cgid_ret = bpf_sched_entity_to_cgrpid(curr); + debug("tick tick_cgid_ret %d curr_se_to_cgid %d", tick_cgid_ret, + tick_cgid_se_to_cgid_ret); + } + + } + } + return 0; +} + +SEC("sched/cfs_check_preempt_wakeup") +int BPF_PROG(test_check_preempt_wakeup, struct task_struct *curr, struct task_struct *p) +{ + __u64 *value = NULL; + __u32 key = 0; + + if (curr == NULL || p == NULL) + return 0; + + value = bpf_map_lookup_elem(&array, &key); + if (value) + *value = 0; + value = bpf_map_lookup_elem(&hash, &key); + if (value) + *value = 0; + + if (tgidpid) { + unsigned long curr_tgidpid, p_tgidpid; + + curr_tgidpid = bpf_sched_entity_to_tgidpid(&curr->se); + p_tgidpid = bpf_sched_entity_to_tgidpid(&p->se); + + if (curr_tgidpid == tgidpid) { + wakeup_tgidpid_ret = curr_tgidpid; + + debug("wakeup curr_tgid %d curr_pid %d wakeup_tgidpid_ret %lu", + curr_tgidpid >> 32, curr_tgidpid & 0xFFFFFFFF, wakeup_tgidpid_ret); + } else if (p_tgidpid == tgidpid) { + wakeup_tgidpid_ret = p_tgidpid; + + debug("wakeup p_tgid %d p_pid %d wakeup_tgidpid_ret %lu", p_tgidpid >> 32, + p_tgidpid & 0xFFFFFFFF, wakeup_tgidpid_ret); + } + } else if (cgid) { + if (bpf_sched_entity_belongs_to_cgrp(&curr->se, cgid)) { + wakeup_cgid_ret = 1; + wakeup_cgid_pid_ret = curr->pid; + + debug("wakeup wakeup_cgid_ret %d curr_pid %d", wakeup_cgid_ret, + wakeup_cgid_pid_ret); + } else if (bpf_sched_entity_belongs_to_cgrp(&p->se, cgid)) { + wakeup_cgid_ret = 1; + wakeup_cgid_pid_ret = p->pid; + + debug("wakeup wakeup_cgid_ret %d p_pid %d", wakeup_cgid_ret, + wakeup_cgid_pid_ret); + } + } + return 0; +} + +SEC("sched/cfs_wakeup_preempt_entity") +int BPF_PROG(test_wakeup_preempt_entity, struct sched_entity *curr, struct sched_entity *se) +{ + if (curr == NULL || se == NULL) + return 0; + + if (tgidpid) { + unsigned long curr_tgidpid, se_tgidpid; + + curr_tgidpid = bpf_sched_entity_to_tgidpid(curr); + se_tgidpid = bpf_sched_entity_to_tgidpid(se); + + if (curr_tgidpid == tgidpid) { + entity_tgidpid_ret = curr_tgidpid; + debug("entity curr_tgid %d curr_pid %d entity_tgidpid_ret %lu", + curr_tgidpid >> 32, curr_tgidpid & 0xFFFFFFFF, entity_tgidpid_ret); + } else if (se_tgidpid == tgidpid) { + entity_tgidpid_ret = se_tgidpid; + debug("entity se_tgid %d se_pid %d entity_tgidpid_ret %lu", + se_tgidpid >> 32, se_tgidpid & 0xFFFFFFFF, entity_tgidpid_ret); + } + } else if (cgid) { + if (bpf_sched_entity_belongs_to_cgrp(curr, cgid)) { + unsigned long curr_tgidpid; + + entity_cgid_ret = 1; + + if (!curr->my_q) { + curr_tgidpid = bpf_sched_entity_to_tgidpid(curr); + entity_cgid_pid_ret = curr_tgidpid & 0xFFFFFFFF; + debug("entity entity_cgid_ret %d curr_pid %d", + entity_cgid_ret, entity_cgid_pid_ret); + } + + if (curr->my_q) { + entity_cgid_se_to_cgid_ret = bpf_sched_entity_to_cgrpid(curr); + debug("entity entity_cgid_ret %d curr_se_to_cgid %d", + entity_cgid_ret, entity_cgid_se_to_cgid_ret); + } + } else if (bpf_sched_entity_belongs_to_cgrp(se, cgid)) { + unsigned long se_tgidpid; + + entity_cgid_ret = 1; + + if (!se->my_q) { + se_tgidpid = bpf_sched_entity_to_tgidpid(se); + entity_cgid_pid_ret = se_tgidpid & 0xFFFFFFFF; + debug("entity entity_cgid_ret %d se_pid %d", entity_cgid_ret, + entity_cgid_pid_ret); + } + + if (se->my_q) { + entity_cgid_se_to_cgid_ret = bpf_sched_entity_to_cgrpid(se); + debug("entity entity_cgid_ret %d se_se_to_cgid %d", entity_cgid_ret, + entity_cgid_se_to_cgid_ret); + } + } + } + return 0; +}