148671232SYonghong Song // SPDX-License-Identifier: GPL-2.0
248671232SYonghong Song /* Copyright (c) 2022 Meta Platforms, Inc. and affiliates.*/
348671232SYonghong Song 
448671232SYonghong Song #define _GNU_SOURCE
548671232SYonghong Song #include <unistd.h>
648671232SYonghong Song #include <sys/syscall.h>
748671232SYonghong Song #include <sys/types.h>
848671232SYonghong Song #include <test_progs.h>
948671232SYonghong Song #include <bpf/btf.h>
1048671232SYonghong Song #include "rcu_read_lock.skel.h"
1148671232SYonghong Song #include "cgroup_helpers.h"
1248671232SYonghong Song 
1348671232SYonghong Song static unsigned long long cgroup_id;
1448671232SYonghong Song 
test_success(void)1548671232SYonghong Song static void test_success(void)
1648671232SYonghong Song {
1748671232SYonghong Song 	struct rcu_read_lock *skel;
1848671232SYonghong Song 	int err;
1948671232SYonghong Song 
2048671232SYonghong Song 	skel = rcu_read_lock__open();
2148671232SYonghong Song 	if (!ASSERT_OK_PTR(skel, "skel_open"))
2248671232SYonghong Song 		return;
2348671232SYonghong Song 
2448671232SYonghong Song 	skel->bss->target_pid = syscall(SYS_gettid);
2548671232SYonghong Song 
2648671232SYonghong Song 	bpf_program__set_autoload(skel->progs.get_cgroup_id, true);
2748671232SYonghong Song 	bpf_program__set_autoload(skel->progs.task_succ, true);
2848671232SYonghong Song 	bpf_program__set_autoload(skel->progs.two_regions, true);
2948671232SYonghong Song 	bpf_program__set_autoload(skel->progs.non_sleepable_1, true);
3048671232SYonghong Song 	bpf_program__set_autoload(skel->progs.non_sleepable_2, true);
31*6fcd486bSAlexei Starovoitov 	bpf_program__set_autoload(skel->progs.task_trusted_non_rcuptr, true);
3248671232SYonghong Song 	err = rcu_read_lock__load(skel);
3348671232SYonghong Song 	if (!ASSERT_OK(err, "skel_load"))
3448671232SYonghong Song 		goto out;
3548671232SYonghong Song 
3648671232SYonghong Song 	err = rcu_read_lock__attach(skel);
3748671232SYonghong Song 	if (!ASSERT_OK(err, "skel_attach"))
3848671232SYonghong Song 		goto out;
3948671232SYonghong Song 
4048671232SYonghong Song 	syscall(SYS_getpgid);
4148671232SYonghong Song 
4248671232SYonghong Song 	ASSERT_EQ(skel->bss->task_storage_val, 2, "task_storage_val");
4348671232SYonghong Song 	ASSERT_EQ(skel->bss->cgroup_id, cgroup_id, "cgroup_id");
4448671232SYonghong Song out:
4548671232SYonghong Song 	rcu_read_lock__destroy(skel);
4648671232SYonghong Song }
4748671232SYonghong Song 
test_rcuptr_acquire(void)4848671232SYonghong Song static void test_rcuptr_acquire(void)
4948671232SYonghong Song {
5048671232SYonghong Song 	struct rcu_read_lock *skel;
5148671232SYonghong Song 	int err;
5248671232SYonghong Song 
5348671232SYonghong Song 	skel = rcu_read_lock__open();
5448671232SYonghong Song 	if (!ASSERT_OK_PTR(skel, "skel_open"))
5548671232SYonghong Song 		return;
5648671232SYonghong Song 
5748671232SYonghong Song 	skel->bss->target_pid = syscall(SYS_gettid);
5848671232SYonghong Song 
5948671232SYonghong Song 	bpf_program__set_autoload(skel->progs.task_acquire, true);
6048671232SYonghong Song 	err = rcu_read_lock__load(skel);
6148671232SYonghong Song 	if (!ASSERT_OK(err, "skel_load"))
6248671232SYonghong Song 		goto out;
6348671232SYonghong Song 
6448671232SYonghong Song 	err = rcu_read_lock__attach(skel);
6548671232SYonghong Song 	ASSERT_OK(err, "skel_attach");
6648671232SYonghong Song out:
6748671232SYonghong Song 	rcu_read_lock__destroy(skel);
6848671232SYonghong Song }
6948671232SYonghong Song 
7048671232SYonghong Song static const char * const inproper_region_tests[] = {
7148671232SYonghong Song 	"miss_lock",
72*6fcd486bSAlexei Starovoitov 	"no_lock",
7348671232SYonghong Song 	"miss_unlock",
7448671232SYonghong Song 	"non_sleepable_rcu_mismatch",
7548671232SYonghong Song 	"inproper_sleepable_helper",
7648671232SYonghong Song 	"inproper_sleepable_kfunc",
7748671232SYonghong Song 	"nested_rcu_region",
7848671232SYonghong Song };
7948671232SYonghong Song 
test_inproper_region(void)8048671232SYonghong Song static void test_inproper_region(void)
8148671232SYonghong Song {
8248671232SYonghong Song 	struct rcu_read_lock *skel;
8348671232SYonghong Song 	struct bpf_program *prog;
8448671232SYonghong Song 	int i, err;
8548671232SYonghong Song 
8648671232SYonghong Song 	for (i = 0; i < ARRAY_SIZE(inproper_region_tests); i++) {
8748671232SYonghong Song 		skel = rcu_read_lock__open();
8848671232SYonghong Song 		if (!ASSERT_OK_PTR(skel, "skel_open"))
8948671232SYonghong Song 			return;
9048671232SYonghong Song 
9148671232SYonghong Song 		prog = bpf_object__find_program_by_name(skel->obj, inproper_region_tests[i]);
9248671232SYonghong Song 		if (!ASSERT_OK_PTR(prog, "bpf_object__find_program_by_name"))
9348671232SYonghong Song 			goto out;
9448671232SYonghong Song 		bpf_program__set_autoload(prog, true);
9548671232SYonghong Song 		err = rcu_read_lock__load(skel);
9648671232SYonghong Song 		ASSERT_ERR(err, "skel_load");
9748671232SYonghong Song out:
9848671232SYonghong Song 		rcu_read_lock__destroy(skel);
9948671232SYonghong Song 	}
10048671232SYonghong Song }
10148671232SYonghong Song 
10248671232SYonghong Song static const char * const rcuptr_misuse_tests[] = {
10348671232SYonghong Song 	"task_untrusted_rcuptr",
10448671232SYonghong Song 	"cross_rcu_region",
10548671232SYonghong Song };
10648671232SYonghong Song 
test_rcuptr_misuse(void)10748671232SYonghong Song static void test_rcuptr_misuse(void)
10848671232SYonghong Song {
10948671232SYonghong Song 	struct rcu_read_lock *skel;
11048671232SYonghong Song 	struct bpf_program *prog;
11148671232SYonghong Song 	int i, err;
11248671232SYonghong Song 
11348671232SYonghong Song 	for (i = 0; i < ARRAY_SIZE(rcuptr_misuse_tests); i++) {
11448671232SYonghong Song 		skel = rcu_read_lock__open();
11548671232SYonghong Song 		if (!ASSERT_OK_PTR(skel, "skel_open"))
11648671232SYonghong Song 			return;
11748671232SYonghong Song 
11848671232SYonghong Song 		prog = bpf_object__find_program_by_name(skel->obj, rcuptr_misuse_tests[i]);
11948671232SYonghong Song 		if (!ASSERT_OK_PTR(prog, "bpf_object__find_program_by_name"))
12048671232SYonghong Song 			goto out;
12148671232SYonghong Song 		bpf_program__set_autoload(prog, true);
12248671232SYonghong Song 		err = rcu_read_lock__load(skel);
12348671232SYonghong Song 		ASSERT_ERR(err, "skel_load");
12448671232SYonghong Song out:
12548671232SYonghong Song 		rcu_read_lock__destroy(skel);
12648671232SYonghong Song 	}
12748671232SYonghong Song }
12848671232SYonghong Song 
test_rcu_read_lock(void)12948671232SYonghong Song void test_rcu_read_lock(void)
13048671232SYonghong Song {
13148671232SYonghong Song 	int cgroup_fd;
13248671232SYonghong Song 
13348671232SYonghong Song 	cgroup_fd = test__join_cgroup("/rcu_read_lock");
13448671232SYonghong Song 	if (!ASSERT_GE(cgroup_fd, 0, "join_cgroup /rcu_read_lock"))
13548671232SYonghong Song 		goto out;
13648671232SYonghong Song 
13748671232SYonghong Song 	cgroup_id = get_cgroup_id("/rcu_read_lock");
13848671232SYonghong Song 	if (test__start_subtest("success"))
13948671232SYonghong Song 		test_success();
14048671232SYonghong Song 	if (test__start_subtest("rcuptr_acquire"))
14148671232SYonghong Song 		test_rcuptr_acquire();
14248671232SYonghong Song 	if (test__start_subtest("negative_tests_inproper_region"))
14348671232SYonghong Song 		test_inproper_region();
14448671232SYonghong Song 	if (test__start_subtest("negative_tests_rcuptr_misuse"))
14548671232SYonghong Song 		test_rcuptr_misuse();
14648671232SYonghong Song 	close(cgroup_fd);
147*6fcd486bSAlexei Starovoitov out:;
14848671232SYonghong Song }
149