xref: /linux/tools/testing/selftests/bpf/prog_tests/cgroup_dev.c (revision 566ab427f827b0256d3e8ce0235d088e6a9c28bd)
1 // SPDX-License-Identifier: GPL-2.0
2 
3 #include <sys/stat.h>
4 #include <sys/sysmacros.h>
5 #include <errno.h>
6 #include "test_progs.h"
7 #include "cgroup_helpers.h"
8 #include "dev_cgroup.skel.h"
9 
10 #define TEST_CGROUP "/test-bpf-based-device-cgroup/"
11 #define TEST_BUFFER_SIZE 64
12 
13 static void test_mknod(const char *path, mode_t mode, int dev_major,
14 		       int dev_minor, int expected_ret, int expected_errno)
15 {
16 	int ret;
17 
18 	unlink(path);
19 	ret = mknod(path, mode, makedev(dev_major, dev_minor));
20 	ASSERT_EQ(ret, expected_ret, "mknod");
21 	if (expected_ret)
22 		ASSERT_EQ(errno, expected_errno, "mknod errno");
23 	else
24 		unlink(path);
25 }
26 
27 static void test_read(const char *path, char *buf, int buf_size,
28 		      int expected_ret, int expected_errno)
29 {
30 	int ret, fd;
31 
32 	fd = open(path, O_RDONLY);
33 
34 	/* A bare open on unauthorized device should fail */
35 	if (expected_ret < 0) {
36 		ASSERT_EQ(fd, expected_ret, "open ret for read");
37 		ASSERT_EQ(errno, expected_errno, "open errno for read");
38 		if (fd >= 0)
39 			close(fd);
40 		return;
41 	}
42 
43 	if (!ASSERT_OK_FD(fd, "open ret for read"))
44 		return;
45 
46 	ret = read(fd, buf, buf_size);
47 	ASSERT_EQ(ret, expected_ret, "read");
48 
49 	close(fd);
50 }
51 
52 static void test_write(const char *path, char *buf, int buf_size,
53 		       int expected_ret, int expected_errno)
54 {
55 	int ret, fd;
56 
57 	fd = open(path, O_WRONLY);
58 
59 	/* A bare open on unauthorized device should fail */
60 	if (expected_ret < 0) {
61 		ASSERT_EQ(fd, expected_ret, "open ret for write");
62 		ASSERT_EQ(errno, expected_errno, "open errno for write");
63 		if (fd >= 0)
64 			close(fd);
65 		return;
66 	}
67 
68 	if (!ASSERT_OK_FD(fd, "open ret for write"))
69 		return;
70 
71 	ret = write(fd, buf, buf_size);
72 	ASSERT_EQ(ret, expected_ret, "write");
73 
74 	close(fd);
75 }
76 
77 void test_cgroup_dev(void)
78 {
79 	char buf[TEST_BUFFER_SIZE] = "some random test data";
80 	struct dev_cgroup *skel;
81 	int cgroup_fd;
82 
83 	cgroup_fd = cgroup_setup_and_join(TEST_CGROUP);
84 	if (!ASSERT_OK_FD(cgroup_fd, "cgroup switch"))
85 		return;
86 
87 	skel = dev_cgroup__open_and_load();
88 	if (!ASSERT_OK_PTR(skel, "load program"))
89 		goto cleanup_cgroup;
90 
91 	skel->links.bpf_prog1 =
92 		bpf_program__attach_cgroup(skel->progs.bpf_prog1, cgroup_fd);
93 	if (!ASSERT_OK_PTR(skel->links.bpf_prog1, "attach_program"))
94 		goto cleanup_progs;
95 
96 	if (test__start_subtest("allow-mknod"))
97 		test_mknod("/dev/test_dev_cgroup_null", S_IFCHR, 1, 3, 0, 0);
98 
99 	if (test__start_subtest("allow-read"))
100 		test_read("/dev/urandom", buf, TEST_BUFFER_SIZE,
101 			  TEST_BUFFER_SIZE, 0);
102 
103 	if (test__start_subtest("allow-write"))
104 		test_write("/dev/null", buf, TEST_BUFFER_SIZE,
105 			   TEST_BUFFER_SIZE, 0);
106 
107 	if (test__start_subtest("deny-mknod"))
108 		test_mknod("/dev/test_dev_cgroup_zero", S_IFCHR, 1, 5, -1,
109 			   EPERM);
110 
111 	if (test__start_subtest("deny-read"))
112 		test_read("/dev/random", buf, TEST_BUFFER_SIZE, -1, EPERM);
113 
114 	if (test__start_subtest("deny-write"))
115 		test_write("/dev/zero", buf, TEST_BUFFER_SIZE, -1, EPERM);
116 
117 	if (test__start_subtest("deny-mknod-wrong-type"))
118 		test_mknod("/dev/test_dev_cgroup_block", S_IFBLK, 1, 3, -1,
119 			   EPERM);
120 
121 cleanup_progs:
122 	dev_cgroup__destroy(skel);
123 cleanup_cgroup:
124 	cleanup_cgroup_environment();
125 }
126