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
wait_for_delete(char * dir)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
find_multi_event_dir(char * unique_field,char * out_dir,int dir_len)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
event_exists(void)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
change_event(bool enable)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
event_delete(void)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 */
wait_for_event_delete(void)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
reg_enable_multi(void * enable,int size,int bit,int flags,char * args)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, ®);
189 out:
190 close(fd);
191
192 return ret;
193 }
194
reg_enable_flags(void * enable,int size,int bit,int flags)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, ®);
212
213 close(fd);
214
215 return ret;
216 }
217
reg_enable(void * enable,int size,int bit)218 static int reg_enable(void *enable, int size, int bit)
219 {
220 return reg_enable_flags(enable, size, bit, 0);
221 }
222
reg_disable(void * enable,int bit)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, ®);
237
238 close(fd);
239
240 return ret;
241 }
242
FIXTURE(user)243 FIXTURE(user) {
244 int check;
245 long check_long;
246 bool umount;
247 };
248
FIXTURE_SETUP(user)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
FIXTURE_TEARDOWN(user)257 FIXTURE_TEARDOWN(user) {
258 USER_EVENT_FIXTURE_TEARDOWN(self->umount);
259 }
260
TEST_F(user,enablement)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
TEST_F(user,flags)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
TEST_F(user,bit_sizes)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
TEST_F(user,multi_format)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
TEST_F(user,forks)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 */
clone_check(void * check)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
TEST_F(user,clones)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
main(int argc,char ** argv)447 int main(int argc, char **argv)
448 {
449 return test_harness_run(argc, argv);
450 }
451