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
test_mknod(const char * path,mode_t mode,int dev_major,int dev_minor,int expected_ret,int expected_errno)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
test_read(const char * path,char * buf,int buf_size,int expected_ret,int expected_errno)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
test_write(const char * path,char * buf,int buf_size,int expected_ret,int expected_errno)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
test_cgroup_dev(void)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