xref: /linux/tools/testing/selftests/user_events/abi_test.c (revision a5766cd479fd212e9831ceef8e9ab630c91445ab)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * User Events ABI Test Program
4  *
5  * Copyright (c) 2022 Beau Belgrave <beaub@linux.microsoft.com>
6  */
7 
8 #define _GNU_SOURCE
9 #include <sched.h>
10 
11 #include <errno.h>
12 #include <linux/user_events.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <fcntl.h>
16 #include <sys/ioctl.h>
17 #include <sys/stat.h>
18 #include <unistd.h>
19 #include <asm/unistd.h>
20 
21 #include "../kselftest_harness.h"
22 #include "user_events_selftests.h"
23 
24 const char *data_file = "/sys/kernel/tracing/user_events_data";
25 const char *enable_file = "/sys/kernel/tracing/events/user_events/__abi_event/enable";
26 
27 static bool event_exists(void)
28 {
29 	int fd = open(enable_file, O_RDWR);
30 
31 	if (fd < 0)
32 		return false;
33 
34 	close(fd);
35 
36 	return true;
37 }
38 
39 static int change_event(bool enable)
40 {
41 	int fd = open(enable_file, O_RDWR);
42 	int ret;
43 
44 	if (fd < 0)
45 		return -1;
46 
47 	if (enable)
48 		ret = write(fd, "1", 1);
49 	else
50 		ret = write(fd, "0", 1);
51 
52 	close(fd);
53 
54 	if (ret == 1)
55 		ret = 0;
56 	else
57 		ret = -1;
58 
59 	return ret;
60 }
61 
62 static int event_delete(void)
63 {
64 	int fd = open(data_file, O_RDWR);
65 	int ret;
66 
67 	if (fd < 0)
68 		return -1;
69 
70 	ret = ioctl(fd, DIAG_IOCSDEL, "__abi_event");
71 
72 	close(fd);
73 
74 	return ret;
75 }
76 
77 static int reg_enable_flags(void *enable, int size, int bit, int flags)
78 {
79 	struct user_reg reg = {0};
80 	int fd = open(data_file, O_RDWR);
81 	int ret;
82 
83 	if (fd < 0)
84 		return -1;
85 
86 	reg.size = sizeof(reg);
87 	reg.name_args = (__u64)"__abi_event";
88 	reg.flags = flags;
89 	reg.enable_bit = bit;
90 	reg.enable_addr = (__u64)enable;
91 	reg.enable_size = size;
92 
93 	ret = ioctl(fd, DIAG_IOCSREG, &reg);
94 
95 	close(fd);
96 
97 	return ret;
98 }
99 
100 static int reg_enable(void *enable, int size, int bit)
101 {
102 	return reg_enable_flags(enable, size, bit, 0);
103 }
104 
105 static int reg_disable(void *enable, int bit)
106 {
107 	struct user_unreg reg = {0};
108 	int fd = open(data_file, O_RDWR);
109 	int ret;
110 
111 	if (fd < 0)
112 		return -1;
113 
114 	reg.size = sizeof(reg);
115 	reg.disable_bit = bit;
116 	reg.disable_addr = (__u64)enable;
117 
118 	ret = ioctl(fd, DIAG_IOCSUNREG, &reg);
119 
120 	close(fd);
121 
122 	return ret;
123 }
124 
125 FIXTURE(user) {
126 	int check;
127 	long check_long;
128 	bool umount;
129 };
130 
131 FIXTURE_SETUP(user) {
132 	USER_EVENT_FIXTURE_SETUP(return, self->umount);
133 
134 	change_event(false);
135 	self->check = 0;
136 	self->check_long = 0;
137 }
138 
139 FIXTURE_TEARDOWN(user) {
140 	USER_EVENT_FIXTURE_TEARDOWN(self->umount);
141 }
142 
143 TEST_F(user, enablement) {
144 	/* Changes should be reflected immediately */
145 	ASSERT_EQ(0, self->check);
146 	ASSERT_EQ(0, reg_enable(&self->check, sizeof(int), 0));
147 	ASSERT_EQ(0, change_event(true));
148 	ASSERT_EQ(1, self->check);
149 	ASSERT_EQ(0, change_event(false));
150 	ASSERT_EQ(0, self->check);
151 
152 	/* Ensure kernel clears bit after disable */
153 	ASSERT_EQ(0, change_event(true));
154 	ASSERT_EQ(1, self->check);
155 	ASSERT_EQ(0, reg_disable(&self->check, 0));
156 	ASSERT_EQ(0, self->check);
157 
158 	/* Ensure doesn't change after unreg */
159 	ASSERT_EQ(0, change_event(true));
160 	ASSERT_EQ(0, self->check);
161 	ASSERT_EQ(0, change_event(false));
162 }
163 
164 TEST_F(user, flags) {
165 	/* USER_EVENT_REG_PERSIST is allowed */
166 	ASSERT_EQ(0, reg_enable_flags(&self->check, sizeof(int), 0,
167 				      USER_EVENT_REG_PERSIST));
168 	ASSERT_EQ(0, reg_disable(&self->check, 0));
169 
170 	/* Ensure it exists after close and disable */
171 	ASSERT_TRUE(event_exists());
172 
173 	/* Ensure we can delete it */
174 	ASSERT_EQ(0, event_delete());
175 
176 	/* USER_EVENT_REG_MAX or above is not allowed */
177 	ASSERT_EQ(-1, reg_enable_flags(&self->check, sizeof(int), 0,
178 				       USER_EVENT_REG_MAX));
179 
180 	/* Ensure it does not exist after invalid flags */
181 	ASSERT_FALSE(event_exists());
182 }
183 
184 TEST_F(user, bit_sizes) {
185 	/* Allow 0-31 bits for 32-bit */
186 	ASSERT_EQ(0, reg_enable(&self->check, sizeof(int), 0));
187 	ASSERT_EQ(0, reg_enable(&self->check, sizeof(int), 31));
188 	ASSERT_NE(0, reg_enable(&self->check, sizeof(int), 32));
189 	ASSERT_EQ(0, reg_disable(&self->check, 0));
190 	ASSERT_EQ(0, reg_disable(&self->check, 31));
191 
192 #if BITS_PER_LONG == 8
193 	/* Allow 0-64 bits for 64-bit */
194 	ASSERT_EQ(0, reg_enable(&self->check_long, sizeof(long), 63));
195 	ASSERT_NE(0, reg_enable(&self->check_long, sizeof(long), 64));
196 	ASSERT_EQ(0, reg_disable(&self->check_long, 63));
197 #endif
198 
199 	/* Disallowed sizes (everything beside 4 and 8) */
200 	ASSERT_NE(0, reg_enable(&self->check, 1, 0));
201 	ASSERT_NE(0, reg_enable(&self->check, 2, 0));
202 	ASSERT_NE(0, reg_enable(&self->check, 3, 0));
203 	ASSERT_NE(0, reg_enable(&self->check, 5, 0));
204 	ASSERT_NE(0, reg_enable(&self->check, 6, 0));
205 	ASSERT_NE(0, reg_enable(&self->check, 7, 0));
206 	ASSERT_NE(0, reg_enable(&self->check, 9, 0));
207 	ASSERT_NE(0, reg_enable(&self->check, 128, 0));
208 }
209 
210 TEST_F(user, forks) {
211 	int i;
212 
213 	/* Ensure COW pages get updated after fork */
214 	ASSERT_EQ(0, reg_enable(&self->check, sizeof(int), 0));
215 	ASSERT_EQ(0, self->check);
216 
217 	if (fork() == 0) {
218 		/* Force COW */
219 		self->check = 0;
220 
221 		/* Up to 1 sec for enablement */
222 		for (i = 0; i < 10; ++i) {
223 			usleep(100000);
224 
225 			if (self->check)
226 				exit(0);
227 		}
228 
229 		exit(1);
230 	}
231 
232 	/* Allow generous time for COW, then enable */
233 	usleep(100000);
234 	ASSERT_EQ(0, change_event(true));
235 
236 	ASSERT_NE(-1, wait(&i));
237 	ASSERT_EQ(0, WEXITSTATUS(i));
238 
239 	/* Ensure child doesn't disable parent */
240 	if (fork() == 0)
241 		exit(reg_disable(&self->check, 0));
242 
243 	ASSERT_NE(-1, wait(&i));
244 	ASSERT_EQ(0, WEXITSTATUS(i));
245 	ASSERT_EQ(1, self->check);
246 	ASSERT_EQ(0, change_event(false));
247 	ASSERT_EQ(0, self->check);
248 }
249 
250 /* Waits up to 1 sec for enablement */
251 static int clone_check(void *check)
252 {
253 	int i;
254 
255 	for (i = 0; i < 10; ++i) {
256 		usleep(100000);
257 
258 		if (*(int *)check)
259 			return 0;
260 	}
261 
262 	return 1;
263 }
264 
265 TEST_F(user, clones) {
266 	int i, stack_size = 4096;
267 	void *stack = mmap(NULL, stack_size, PROT_READ | PROT_WRITE,
268 			   MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK,
269 			   -1, 0);
270 
271 	ASSERT_NE(MAP_FAILED, stack);
272 	ASSERT_EQ(0, reg_enable(&self->check, sizeof(int), 0));
273 	ASSERT_EQ(0, self->check);
274 
275 	/* Shared VM should see enablements */
276 	ASSERT_NE(-1, clone(&clone_check, stack + stack_size,
277 			    CLONE_VM | SIGCHLD, &self->check));
278 
279 	ASSERT_EQ(0, change_event(true));
280 	ASSERT_NE(-1, wait(&i));
281 	ASSERT_EQ(0, WEXITSTATUS(i));
282 	munmap(stack, stack_size);
283 	ASSERT_EQ(0, change_event(false));
284 }
285 
286 int main(int argc, char **argv)
287 {
288 	return test_harness_run(argc, argv);
289 }
290