xref: /linux/tools/testing/selftests/user_events/abi_test.c (revision fafb66e5903c2bcfc7b7e259042a8282f18a6faa)
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 /*
136  * Deleting an event drops its last reference, but an unregister may defer
137  * that put (and the freeing of the associated enabler) past an RCU grace
138  * period. The delete can therefore transiently fail with -EBUSY while the
139  * previous reference is still being dropped. Retry only on that transient
140  * failure; treat an already-deleted event (-ENOENT) as success and return
141  * any other error immediately rather than spinning for the full timeout.
142  */
143 static int wait_for_event_delete(void)
144 {
145 	int i, ret;
146 
147 	for (i = 0; i < 10000; ++i) {
148 		ret = event_delete();
149 
150 		if (ret == 0 || errno == ENOENT)
151 			return 0;
152 
153 		if (errno != EBUSY)
154 			return ret;
155 
156 		usleep(1000);
157 	}
158 
159 	return ret;
160 }
161 
162 static int reg_enable_multi(void *enable, int size, int bit, int flags,
163 			    char *args)
164 {
165 	struct user_reg reg = {0};
166 	char full_args[512] = {0};
167 	int fd = open(data_file, O_RDWR);
168 	int len;
169 	int ret;
170 
171 	if (fd < 0)
172 		return -1;
173 
174 	len = snprintf(full_args, sizeof(full_args), "__abi_event %s", args);
175 
176 	if (len > sizeof(full_args)) {
177 		ret = -E2BIG;
178 		goto out;
179 	}
180 
181 	reg.size = sizeof(reg);
182 	reg.name_args = (__u64)full_args;
183 	reg.flags = USER_EVENT_REG_MULTI_FORMAT | flags;
184 	reg.enable_bit = bit;
185 	reg.enable_addr = (__u64)enable;
186 	reg.enable_size = size;
187 
188 	ret = ioctl(fd, DIAG_IOCSREG, &reg);
189 out:
190 	close(fd);
191 
192 	return ret;
193 }
194 
195 static int reg_enable_flags(void *enable, int size, int bit, int flags)
196 {
197 	struct user_reg reg = {0};
198 	int fd = open(data_file, O_RDWR);
199 	int ret;
200 
201 	if (fd < 0)
202 		return -1;
203 
204 	reg.size = sizeof(reg);
205 	reg.name_args = (__u64)"__abi_event";
206 	reg.flags = flags;
207 	reg.enable_bit = bit;
208 	reg.enable_addr = (__u64)enable;
209 	reg.enable_size = size;
210 
211 	ret = ioctl(fd, DIAG_IOCSREG, &reg);
212 
213 	close(fd);
214 
215 	return ret;
216 }
217 
218 static int reg_enable(void *enable, int size, int bit)
219 {
220 	return reg_enable_flags(enable, size, bit, 0);
221 }
222 
223 static int reg_disable(void *enable, int bit)
224 {
225 	struct user_unreg reg = {0};
226 	int fd = open(data_file, O_RDWR);
227 	int ret;
228 
229 	if (fd < 0)
230 		return -1;
231 
232 	reg.size = sizeof(reg);
233 	reg.disable_bit = bit;
234 	reg.disable_addr = (__u64)enable;
235 
236 	ret = ioctl(fd, DIAG_IOCSUNREG, &reg);
237 
238 	close(fd);
239 
240 	return ret;
241 }
242 
243 FIXTURE(user) {
244 	int check;
245 	long check_long;
246 	bool umount;
247 };
248 
249 FIXTURE_SETUP(user) {
250 	USER_EVENT_FIXTURE_SETUP(return, self->umount);
251 
252 	change_event(false);
253 	self->check = 0;
254 	self->check_long = 0;
255 }
256 
257 FIXTURE_TEARDOWN(user) {
258 	USER_EVENT_FIXTURE_TEARDOWN(self->umount);
259 }
260 
261 TEST_F(user, enablement) {
262 	/* Changes should be reflected immediately */
263 	ASSERT_EQ(0, self->check);
264 	ASSERT_EQ(0, reg_enable(&self->check, sizeof(int), 0));
265 	ASSERT_EQ(0, change_event(true));
266 	ASSERT_EQ(1, self->check);
267 	ASSERT_EQ(0, change_event(false));
268 	ASSERT_EQ(0, self->check);
269 
270 	/* Ensure kernel clears bit after disable */
271 	ASSERT_EQ(0, change_event(true));
272 	ASSERT_EQ(1, self->check);
273 	ASSERT_EQ(0, reg_disable(&self->check, 0));
274 	ASSERT_EQ(0, self->check);
275 
276 	/* Ensure doesn't change after unreg */
277 	ASSERT_EQ(0, change_event(true));
278 	ASSERT_EQ(0, self->check);
279 	ASSERT_EQ(0, change_event(false));
280 }
281 
282 TEST_F(user, flags) {
283 	/* USER_EVENT_REG_PERSIST is allowed */
284 	ASSERT_EQ(0, reg_enable_flags(&self->check, sizeof(int), 0,
285 				      USER_EVENT_REG_PERSIST));
286 	ASSERT_EQ(0, reg_disable(&self->check, 0));
287 
288 	/* Ensure it exists after close and disable */
289 	ASSERT_TRUE(event_exists());
290 
291 	/* Ensure we can delete it */
292 	ASSERT_EQ(0, wait_for_event_delete());
293 
294 	/* USER_EVENT_REG_MAX or above is not allowed */
295 	ASSERT_EQ(-1, reg_enable_flags(&self->check, sizeof(int), 0,
296 				       USER_EVENT_REG_MAX));
297 
298 	/* Ensure it does not exist after invalid flags */
299 	ASSERT_FALSE(event_exists());
300 }
301 
302 TEST_F(user, bit_sizes) {
303 	/* Allow 0-31 bits for 32-bit */
304 	ASSERT_EQ(0, reg_enable(&self->check, sizeof(int), 0));
305 	ASSERT_EQ(0, reg_enable(&self->check, sizeof(int), 31));
306 	ASSERT_NE(0, reg_enable(&self->check, sizeof(int), 32));
307 	ASSERT_EQ(0, reg_disable(&self->check, 0));
308 	ASSERT_EQ(0, reg_disable(&self->check, 31));
309 
310 #if BITS_PER_LONG == 8
311 	/* Allow 0-64 bits for 64-bit */
312 	ASSERT_EQ(0, reg_enable(&self->check_long, sizeof(long), 63));
313 	ASSERT_NE(0, reg_enable(&self->check_long, sizeof(long), 64));
314 	ASSERT_EQ(0, reg_disable(&self->check_long, 63));
315 #endif
316 
317 	/* Disallowed sizes (everything beside 4 and 8) */
318 	ASSERT_NE(0, reg_enable(&self->check, 1, 0));
319 	ASSERT_NE(0, reg_enable(&self->check, 2, 0));
320 	ASSERT_NE(0, reg_enable(&self->check, 3, 0));
321 	ASSERT_NE(0, reg_enable(&self->check, 5, 0));
322 	ASSERT_NE(0, reg_enable(&self->check, 6, 0));
323 	ASSERT_NE(0, reg_enable(&self->check, 7, 0));
324 	ASSERT_NE(0, reg_enable(&self->check, 9, 0));
325 	ASSERT_NE(0, reg_enable(&self->check, 128, 0));
326 }
327 
328 TEST_F(user, multi_format) {
329 	char first_dir[256];
330 	char second_dir[256];
331 	struct stat buf;
332 
333 	/* Multiple formats for the same name should work */
334 	ASSERT_EQ(0, reg_enable_multi(&self->check, sizeof(int), 0,
335 				      0, "u32 multi_first"));
336 
337 	ASSERT_EQ(0, reg_enable_multi(&self->check, sizeof(int), 1,
338 				      0, "u64 multi_second"));
339 
340 	/* Same name with same format should also work */
341 	ASSERT_EQ(0, reg_enable_multi(&self->check, sizeof(int), 2,
342 				      0, "u64 multi_second"));
343 
344 	ASSERT_EQ(0, find_multi_event_dir("multi_first",
345 					  first_dir, sizeof(first_dir)));
346 
347 	ASSERT_EQ(0, find_multi_event_dir("multi_second",
348 					  second_dir, sizeof(second_dir)));
349 
350 	/* Should not be found in the same dir */
351 	ASSERT_NE(0, strcmp(first_dir, second_dir));
352 
353 	/* First dir should still exist */
354 	ASSERT_EQ(0, stat(first_dir, &buf));
355 
356 	/* Disabling first register should remove first dir */
357 	ASSERT_EQ(0, reg_disable(&self->check, 0));
358 	ASSERT_EQ(0, wait_for_delete(first_dir));
359 
360 	/* Second dir should still exist */
361 	ASSERT_EQ(0, stat(second_dir, &buf));
362 
363 	/* Disabling second register should remove second dir */
364 	ASSERT_EQ(0, reg_disable(&self->check, 1));
365 	/* Ensure bit 1 and 2 are tied together, should not delete yet */
366 	ASSERT_EQ(0, stat(second_dir, &buf));
367 	ASSERT_EQ(0, reg_disable(&self->check, 2));
368 	ASSERT_EQ(0, wait_for_delete(second_dir));
369 }
370 
371 TEST_F(user, forks) {
372 	int i;
373 
374 	/* Ensure COW pages get updated after fork */
375 	ASSERT_EQ(0, reg_enable(&self->check, sizeof(int), 0));
376 	ASSERT_EQ(0, self->check);
377 
378 	if (fork() == 0) {
379 		/* Force COW */
380 		self->check = 0;
381 
382 		/* Up to 1 sec for enablement */
383 		for (i = 0; i < 10; ++i) {
384 			usleep(100000);
385 
386 			if (self->check)
387 				exit(0);
388 		}
389 
390 		exit(1);
391 	}
392 
393 	/* Allow generous time for COW, then enable */
394 	usleep(100000);
395 	ASSERT_EQ(0, change_event(true));
396 
397 	ASSERT_NE(-1, wait(&i));
398 	ASSERT_EQ(0, WEXITSTATUS(i));
399 
400 	/* Ensure child doesn't disable parent */
401 	if (fork() == 0)
402 		exit(reg_disable(&self->check, 0));
403 
404 	ASSERT_NE(-1, wait(&i));
405 	ASSERT_EQ(0, WEXITSTATUS(i));
406 	ASSERT_EQ(1, self->check);
407 	ASSERT_EQ(0, change_event(false));
408 	ASSERT_EQ(0, self->check);
409 }
410 
411 /* Waits up to 1 sec for enablement */
412 static int clone_check(void *check)
413 {
414 	int i;
415 
416 	for (i = 0; i < 10; ++i) {
417 		usleep(100000);
418 
419 		if (*(int *)check)
420 			return 0;
421 	}
422 
423 	return 1;
424 }
425 
426 TEST_F(user, clones) {
427 	int i, stack_size = 4096;
428 	void *stack = mmap(NULL, stack_size, PROT_READ | PROT_WRITE,
429 			   MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK,
430 			   -1, 0);
431 
432 	ASSERT_NE(MAP_FAILED, stack);
433 	ASSERT_EQ(0, reg_enable(&self->check, sizeof(int), 0));
434 	ASSERT_EQ(0, self->check);
435 
436 	/* Shared VM should see enablements */
437 	ASSERT_NE(-1, clone(&clone_check, stack + stack_size,
438 			    CLONE_VM | SIGCHLD, &self->check));
439 
440 	ASSERT_EQ(0, change_event(true));
441 	ASSERT_NE(-1, wait(&i));
442 	ASSERT_EQ(0, WEXITSTATUS(i));
443 	munmap(stack, stack_size);
444 	ASSERT_EQ(0, change_event(false));
445 }
446 
447 int main(int argc, char **argv)
448 {
449 	return test_harness_run(argc, argv);
450 }
451