xref: /linux/tools/testing/selftests/user_events/abi_test.c (revision d5859510d35d8e7d63fed5169f1775317f40fb03)
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 <glob.h>
20 #include <string.h>
21 #include <asm/unistd.h>
22 
23 #include "../kselftest_harness.h"
24 #include "user_events_selftests.h"
25 
26 const char *data_file = "/sys/kernel/tracing/user_events_data";
27 const char *enable_file = "/sys/kernel/tracing/events/user_events/__abi_event/enable";
28 const char *multi_dir_glob = "/sys/kernel/tracing/events/user_events_multi/__abi_event.*";
29 
30 static int wait_for_delete(char *dir)
31 {
32 	struct stat buf;
33 	int i;
34 
35 	for (i = 0; i < 10000; ++i) {
36 		if (stat(dir, &buf) == -1 && errno == ENOENT)
37 			return 0;
38 
39 		usleep(1000);
40 	}
41 
42 	return -1;
43 }
44 
45 static int find_multi_event_dir(char *unique_field, char *out_dir, int dir_len)
46 {
47 	char path[256];
48 	glob_t buf;
49 	int i, ret;
50 
51 	ret = glob(multi_dir_glob, GLOB_ONLYDIR, NULL, &buf);
52 
53 	if (ret)
54 		return -1;
55 
56 	ret = -1;
57 
58 	for (i = 0; i < buf.gl_pathc; ++i) {
59 		FILE *fp;
60 
61 		snprintf(path, sizeof(path), "%s/format", buf.gl_pathv[i]);
62 		fp = fopen(path, "r");
63 
64 		if (!fp)
65 			continue;
66 
67 		while (fgets(path, sizeof(path), fp) != NULL) {
68 			if (strstr(path, unique_field)) {
69 				fclose(fp);
70 				/* strscpy is not available, use snprintf */
71 				snprintf(out_dir, dir_len, "%s", buf.gl_pathv[i]);
72 				ret = 0;
73 				goto out;
74 			}
75 		}
76 
77 		fclose(fp);
78 	}
79 out:
80 	globfree(&buf);
81 
82 	return ret;
83 }
84 
85 static bool event_exists(void)
86 {
87 	int fd = open(enable_file, O_RDWR);
88 
89 	if (fd < 0)
90 		return false;
91 
92 	close(fd);
93 
94 	return true;
95 }
96 
97 static int change_event(bool enable)
98 {
99 	int fd = open(enable_file, O_RDWR);
100 	int ret;
101 
102 	if (fd < 0)
103 		return -1;
104 
105 	if (enable)
106 		ret = write(fd, "1", 1);
107 	else
108 		ret = write(fd, "0", 1);
109 
110 	close(fd);
111 
112 	if (ret == 1)
113 		ret = 0;
114 	else
115 		ret = -1;
116 
117 	return ret;
118 }
119 
120 static int event_delete(void)
121 {
122 	int fd = open(data_file, O_RDWR);
123 	int ret;
124 
125 	if (fd < 0)
126 		return -1;
127 
128 	ret = ioctl(fd, DIAG_IOCSDEL, "__abi_event");
129 
130 	close(fd);
131 
132 	return ret;
133 }
134 
135 static int reg_enable_multi(void *enable, int size, int bit, int flags,
136 			    char *args)
137 {
138 	struct user_reg reg = {0};
139 	char full_args[512] = {0};
140 	int fd = open(data_file, O_RDWR);
141 	int len;
142 	int ret;
143 
144 	if (fd < 0)
145 		return -1;
146 
147 	len = snprintf(full_args, sizeof(full_args), "__abi_event %s", args);
148 
149 	if (len > sizeof(full_args)) {
150 		ret = -E2BIG;
151 		goto out;
152 	}
153 
154 	reg.size = sizeof(reg);
155 	reg.name_args = (__u64)full_args;
156 	reg.flags = USER_EVENT_REG_MULTI_FORMAT | flags;
157 	reg.enable_bit = bit;
158 	reg.enable_addr = (__u64)enable;
159 	reg.enable_size = size;
160 
161 	ret = ioctl(fd, DIAG_IOCSREG, &reg);
162 out:
163 	close(fd);
164 
165 	return ret;
166 }
167 
168 static int reg_enable_flags(void *enable, int size, int bit, int flags)
169 {
170 	struct user_reg reg = {0};
171 	int fd = open(data_file, O_RDWR);
172 	int ret;
173 
174 	if (fd < 0)
175 		return -1;
176 
177 	reg.size = sizeof(reg);
178 	reg.name_args = (__u64)"__abi_event";
179 	reg.flags = flags;
180 	reg.enable_bit = bit;
181 	reg.enable_addr = (__u64)enable;
182 	reg.enable_size = size;
183 
184 	ret = ioctl(fd, DIAG_IOCSREG, &reg);
185 
186 	close(fd);
187 
188 	return ret;
189 }
190 
191 static int reg_enable(void *enable, int size, int bit)
192 {
193 	return reg_enable_flags(enable, size, bit, 0);
194 }
195 
196 static int reg_disable(void *enable, int bit)
197 {
198 	struct user_unreg reg = {0};
199 	int fd = open(data_file, O_RDWR);
200 	int ret;
201 
202 	if (fd < 0)
203 		return -1;
204 
205 	reg.size = sizeof(reg);
206 	reg.disable_bit = bit;
207 	reg.disable_addr = (__u64)enable;
208 
209 	ret = ioctl(fd, DIAG_IOCSUNREG, &reg);
210 
211 	close(fd);
212 
213 	return ret;
214 }
215 
216 FIXTURE(user) {
217 	int check;
218 	long check_long;
219 	bool umount;
220 };
221 
222 FIXTURE_SETUP(user) {
223 	USER_EVENT_FIXTURE_SETUP(return, self->umount);
224 
225 	change_event(false);
226 	self->check = 0;
227 	self->check_long = 0;
228 }
229 
230 FIXTURE_TEARDOWN(user) {
231 	USER_EVENT_FIXTURE_TEARDOWN(self->umount);
232 }
233 
234 TEST_F(user, enablement) {
235 	/* Changes should be reflected immediately */
236 	ASSERT_EQ(0, self->check);
237 	ASSERT_EQ(0, reg_enable(&self->check, sizeof(int), 0));
238 	ASSERT_EQ(0, change_event(true));
239 	ASSERT_EQ(1, self->check);
240 	ASSERT_EQ(0, change_event(false));
241 	ASSERT_EQ(0, self->check);
242 
243 	/* Ensure kernel clears bit after disable */
244 	ASSERT_EQ(0, change_event(true));
245 	ASSERT_EQ(1, self->check);
246 	ASSERT_EQ(0, reg_disable(&self->check, 0));
247 	ASSERT_EQ(0, self->check);
248 
249 	/* Ensure doesn't change after unreg */
250 	ASSERT_EQ(0, change_event(true));
251 	ASSERT_EQ(0, self->check);
252 	ASSERT_EQ(0, change_event(false));
253 }
254 
255 TEST_F(user, flags) {
256 	/* USER_EVENT_REG_PERSIST is allowed */
257 	ASSERT_EQ(0, reg_enable_flags(&self->check, sizeof(int), 0,
258 				      USER_EVENT_REG_PERSIST));
259 	ASSERT_EQ(0, reg_disable(&self->check, 0));
260 
261 	/* Ensure it exists after close and disable */
262 	ASSERT_TRUE(event_exists());
263 
264 	/* Ensure we can delete it */
265 	ASSERT_EQ(0, event_delete());
266 
267 	/* USER_EVENT_REG_MAX or above is not allowed */
268 	ASSERT_EQ(-1, reg_enable_flags(&self->check, sizeof(int), 0,
269 				       USER_EVENT_REG_MAX));
270 
271 	/* Ensure it does not exist after invalid flags */
272 	ASSERT_FALSE(event_exists());
273 }
274 
275 TEST_F(user, bit_sizes) {
276 	/* Allow 0-31 bits for 32-bit */
277 	ASSERT_EQ(0, reg_enable(&self->check, sizeof(int), 0));
278 	ASSERT_EQ(0, reg_enable(&self->check, sizeof(int), 31));
279 	ASSERT_NE(0, reg_enable(&self->check, sizeof(int), 32));
280 	ASSERT_EQ(0, reg_disable(&self->check, 0));
281 	ASSERT_EQ(0, reg_disable(&self->check, 31));
282 
283 #if BITS_PER_LONG == 8
284 	/* Allow 0-64 bits for 64-bit */
285 	ASSERT_EQ(0, reg_enable(&self->check_long, sizeof(long), 63));
286 	ASSERT_NE(0, reg_enable(&self->check_long, sizeof(long), 64));
287 	ASSERT_EQ(0, reg_disable(&self->check_long, 63));
288 #endif
289 
290 	/* Disallowed sizes (everything beside 4 and 8) */
291 	ASSERT_NE(0, reg_enable(&self->check, 1, 0));
292 	ASSERT_NE(0, reg_enable(&self->check, 2, 0));
293 	ASSERT_NE(0, reg_enable(&self->check, 3, 0));
294 	ASSERT_NE(0, reg_enable(&self->check, 5, 0));
295 	ASSERT_NE(0, reg_enable(&self->check, 6, 0));
296 	ASSERT_NE(0, reg_enable(&self->check, 7, 0));
297 	ASSERT_NE(0, reg_enable(&self->check, 9, 0));
298 	ASSERT_NE(0, reg_enable(&self->check, 128, 0));
299 }
300 
301 TEST_F(user, multi_format) {
302 	char first_dir[256];
303 	char second_dir[256];
304 	struct stat buf;
305 
306 	/* Multiple formats for the same name should work */
307 	ASSERT_EQ(0, reg_enable_multi(&self->check, sizeof(int), 0,
308 				      0, "u32 multi_first"));
309 
310 	ASSERT_EQ(0, reg_enable_multi(&self->check, sizeof(int), 1,
311 				      0, "u64 multi_second"));
312 
313 	/* Same name with same format should also work */
314 	ASSERT_EQ(0, reg_enable_multi(&self->check, sizeof(int), 2,
315 				      0, "u64 multi_second"));
316 
317 	ASSERT_EQ(0, find_multi_event_dir("multi_first",
318 					  first_dir, sizeof(first_dir)));
319 
320 	ASSERT_EQ(0, find_multi_event_dir("multi_second",
321 					  second_dir, sizeof(second_dir)));
322 
323 	/* Should not be found in the same dir */
324 	ASSERT_NE(0, strcmp(first_dir, second_dir));
325 
326 	/* First dir should still exist */
327 	ASSERT_EQ(0, stat(first_dir, &buf));
328 
329 	/* Disabling first register should remove first dir */
330 	ASSERT_EQ(0, reg_disable(&self->check, 0));
331 	ASSERT_EQ(0, wait_for_delete(first_dir));
332 
333 	/* Second dir should still exist */
334 	ASSERT_EQ(0, stat(second_dir, &buf));
335 
336 	/* Disabling second register should remove second dir */
337 	ASSERT_EQ(0, reg_disable(&self->check, 1));
338 	/* Ensure bit 1 and 2 are tied together, should not delete yet */
339 	ASSERT_EQ(0, stat(second_dir, &buf));
340 	ASSERT_EQ(0, reg_disable(&self->check, 2));
341 	ASSERT_EQ(0, wait_for_delete(second_dir));
342 }
343 
344 TEST_F(user, forks) {
345 	int i;
346 
347 	/* Ensure COW pages get updated after fork */
348 	ASSERT_EQ(0, reg_enable(&self->check, sizeof(int), 0));
349 	ASSERT_EQ(0, self->check);
350 
351 	if (fork() == 0) {
352 		/* Force COW */
353 		self->check = 0;
354 
355 		/* Up to 1 sec for enablement */
356 		for (i = 0; i < 10; ++i) {
357 			usleep(100000);
358 
359 			if (self->check)
360 				exit(0);
361 		}
362 
363 		exit(1);
364 	}
365 
366 	/* Allow generous time for COW, then enable */
367 	usleep(100000);
368 	ASSERT_EQ(0, change_event(true));
369 
370 	ASSERT_NE(-1, wait(&i));
371 	ASSERT_EQ(0, WEXITSTATUS(i));
372 
373 	/* Ensure child doesn't disable parent */
374 	if (fork() == 0)
375 		exit(reg_disable(&self->check, 0));
376 
377 	ASSERT_NE(-1, wait(&i));
378 	ASSERT_EQ(0, WEXITSTATUS(i));
379 	ASSERT_EQ(1, self->check);
380 	ASSERT_EQ(0, change_event(false));
381 	ASSERT_EQ(0, self->check);
382 }
383 
384 /* Waits up to 1 sec for enablement */
385 static int clone_check(void *check)
386 {
387 	int i;
388 
389 	for (i = 0; i < 10; ++i) {
390 		usleep(100000);
391 
392 		if (*(int *)check)
393 			return 0;
394 	}
395 
396 	return 1;
397 }
398 
399 TEST_F(user, clones) {
400 	int i, stack_size = 4096;
401 	void *stack = mmap(NULL, stack_size, PROT_READ | PROT_WRITE,
402 			   MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK,
403 			   -1, 0);
404 
405 	ASSERT_NE(MAP_FAILED, stack);
406 	ASSERT_EQ(0, reg_enable(&self->check, sizeof(int), 0));
407 	ASSERT_EQ(0, self->check);
408 
409 	/* Shared VM should see enablements */
410 	ASSERT_NE(-1, clone(&clone_check, stack + stack_size,
411 			    CLONE_VM | SIGCHLD, &self->check));
412 
413 	ASSERT_EQ(0, change_event(true));
414 	ASSERT_NE(-1, wait(&i));
415 	ASSERT_EQ(0, WEXITSTATUS(i));
416 	munmap(stack, stack_size);
417 	ASSERT_EQ(0, change_event(false));
418 }
419 
420 int main(int argc, char **argv)
421 {
422 	return test_harness_run(argc, argv);
423 }
424