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);
316fcd486bSAlexei Starovoitov 	bpf_program__set_autoload(skel->progs.task_trusted_non_rcuptr, true);
32*8be6a014SKumar Kartikeya Dwivedi 	bpf_program__set_autoload(skel->progs.rcu_read_lock_subprog, true);
33*8be6a014SKumar Kartikeya Dwivedi 	bpf_program__set_autoload(skel->progs.rcu_read_lock_global_subprog, true);
34*8be6a014SKumar Kartikeya Dwivedi 	bpf_program__set_autoload(skel->progs.rcu_read_lock_subprog_lock, true);
35*8be6a014SKumar Kartikeya Dwivedi 	bpf_program__set_autoload(skel->progs.rcu_read_lock_subprog_unlock, true);
3648671232SYonghong Song 	err = rcu_read_lock__load(skel);
3748671232SYonghong Song 	if (!ASSERT_OK(err, "skel_load"))
3848671232SYonghong Song 		goto out;
3948671232SYonghong Song 
4048671232SYonghong Song 	err = rcu_read_lock__attach(skel);
4148671232SYonghong Song 	if (!ASSERT_OK(err, "skel_attach"))
4248671232SYonghong Song 		goto out;
4348671232SYonghong Song 
4448671232SYonghong Song 	syscall(SYS_getpgid);
4548671232SYonghong Song 
4648671232SYonghong Song 	ASSERT_EQ(skel->bss->task_storage_val, 2, "task_storage_val");
4748671232SYonghong Song 	ASSERT_EQ(skel->bss->cgroup_id, cgroup_id, "cgroup_id");
4848671232SYonghong Song out:
4948671232SYonghong Song 	rcu_read_lock__destroy(skel);
5048671232SYonghong Song }
5148671232SYonghong Song 
test_rcuptr_acquire(void)5248671232SYonghong Song static void test_rcuptr_acquire(void)
5348671232SYonghong Song {
5448671232SYonghong Song 	struct rcu_read_lock *skel;
5548671232SYonghong Song 	int err;
5648671232SYonghong Song 
5748671232SYonghong Song 	skel = rcu_read_lock__open();
5848671232SYonghong Song 	if (!ASSERT_OK_PTR(skel, "skel_open"))
5948671232SYonghong Song 		return;
6048671232SYonghong Song 
6148671232SYonghong Song 	skel->bss->target_pid = syscall(SYS_gettid);
6248671232SYonghong Song 
6348671232SYonghong Song 	bpf_program__set_autoload(skel->progs.task_acquire, true);
6448671232SYonghong Song 	err = rcu_read_lock__load(skel);
6548671232SYonghong Song 	if (!ASSERT_OK(err, "skel_load"))
6648671232SYonghong Song 		goto out;
6748671232SYonghong Song 
6848671232SYonghong Song 	err = rcu_read_lock__attach(skel);
6948671232SYonghong Song 	ASSERT_OK(err, "skel_attach");
7048671232SYonghong Song out:
7148671232SYonghong Song 	rcu_read_lock__destroy(skel);
7248671232SYonghong Song }
7348671232SYonghong Song 
7448671232SYonghong Song static const char * const inproper_region_tests[] = {
7548671232SYonghong Song 	"miss_lock",
766fcd486bSAlexei Starovoitov 	"no_lock",
7748671232SYonghong Song 	"miss_unlock",
7848671232SYonghong Song 	"non_sleepable_rcu_mismatch",
7948671232SYonghong Song 	"inproper_sleepable_helper",
8048671232SYonghong Song 	"inproper_sleepable_kfunc",
8148671232SYonghong Song 	"nested_rcu_region",
82*8be6a014SKumar Kartikeya Dwivedi 	"rcu_read_lock_global_subprog_lock",
83*8be6a014SKumar Kartikeya Dwivedi 	"rcu_read_lock_global_subprog_unlock",
8448671232SYonghong Song };
8548671232SYonghong Song 
test_inproper_region(void)8648671232SYonghong Song static void test_inproper_region(void)
8748671232SYonghong Song {
8848671232SYonghong Song 	struct rcu_read_lock *skel;
8948671232SYonghong Song 	struct bpf_program *prog;
9048671232SYonghong Song 	int i, err;
9148671232SYonghong Song 
9248671232SYonghong Song 	for (i = 0; i < ARRAY_SIZE(inproper_region_tests); i++) {
9348671232SYonghong Song 		skel = rcu_read_lock__open();
9448671232SYonghong Song 		if (!ASSERT_OK_PTR(skel, "skel_open"))
9548671232SYonghong Song 			return;
9648671232SYonghong Song 
9748671232SYonghong Song 		prog = bpf_object__find_program_by_name(skel->obj, inproper_region_tests[i]);
9848671232SYonghong Song 		if (!ASSERT_OK_PTR(prog, "bpf_object__find_program_by_name"))
9948671232SYonghong Song 			goto out;
10048671232SYonghong Song 		bpf_program__set_autoload(prog, true);
10148671232SYonghong Song 		err = rcu_read_lock__load(skel);
10248671232SYonghong Song 		ASSERT_ERR(err, "skel_load");
10348671232SYonghong Song out:
10448671232SYonghong Song 		rcu_read_lock__destroy(skel);
10548671232SYonghong Song 	}
10648671232SYonghong Song }
10748671232SYonghong Song 
10848671232SYonghong Song static const char * const rcuptr_misuse_tests[] = {
10948671232SYonghong Song 	"task_untrusted_rcuptr",
11048671232SYonghong Song 	"cross_rcu_region",
11148671232SYonghong Song };
11248671232SYonghong Song 
test_rcuptr_misuse(void)11348671232SYonghong Song static void test_rcuptr_misuse(void)
11448671232SYonghong Song {
11548671232SYonghong Song 	struct rcu_read_lock *skel;
11648671232SYonghong Song 	struct bpf_program *prog;
11748671232SYonghong Song 	int i, err;
11848671232SYonghong Song 
11948671232SYonghong Song 	for (i = 0; i < ARRAY_SIZE(rcuptr_misuse_tests); i++) {
12048671232SYonghong Song 		skel = rcu_read_lock__open();
12148671232SYonghong Song 		if (!ASSERT_OK_PTR(skel, "skel_open"))
12248671232SYonghong Song 			return;
12348671232SYonghong Song 
12448671232SYonghong Song 		prog = bpf_object__find_program_by_name(skel->obj, rcuptr_misuse_tests[i]);
12548671232SYonghong Song 		if (!ASSERT_OK_PTR(prog, "bpf_object__find_program_by_name"))
12648671232SYonghong Song 			goto out;
12748671232SYonghong Song 		bpf_program__set_autoload(prog, true);
12848671232SYonghong Song 		err = rcu_read_lock__load(skel);
12948671232SYonghong Song 		ASSERT_ERR(err, "skel_load");
13048671232SYonghong Song out:
13148671232SYonghong Song 		rcu_read_lock__destroy(skel);
13248671232SYonghong Song 	}
13348671232SYonghong Song }
13448671232SYonghong Song 
test_rcu_read_lock(void)13548671232SYonghong Song void test_rcu_read_lock(void)
13648671232SYonghong Song {
13748671232SYonghong Song 	int cgroup_fd;
13848671232SYonghong Song 
13948671232SYonghong Song 	cgroup_fd = test__join_cgroup("/rcu_read_lock");
14048671232SYonghong Song 	if (!ASSERT_GE(cgroup_fd, 0, "join_cgroup /rcu_read_lock"))
14148671232SYonghong Song 		goto out;
14248671232SYonghong Song 
14348671232SYonghong Song 	cgroup_id = get_cgroup_id("/rcu_read_lock");
14448671232SYonghong Song 	if (test__start_subtest("success"))
14548671232SYonghong Song 		test_success();
14648671232SYonghong Song 	if (test__start_subtest("rcuptr_acquire"))
14748671232SYonghong Song 		test_rcuptr_acquire();
14848671232SYonghong Song 	if (test__start_subtest("negative_tests_inproper_region"))
14948671232SYonghong Song 		test_inproper_region();
15048671232SYonghong Song 	if (test__start_subtest("negative_tests_rcuptr_misuse"))
15148671232SYonghong Song 		test_rcuptr_misuse();
15248671232SYonghong Song 	close(cgroup_fd);
1536fcd486bSAlexei Starovoitov out:;
15448671232SYonghong Song }
155