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
reg_enable_multi(void * enable,int size,int bit,int flags,char * args)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, ®);
162 out:
163 close(fd);
164
165 return ret;
166 }
167
reg_enable_flags(void * enable,int size,int bit,int flags)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, ®);
185
186 close(fd);
187
188 return ret;
189 }
190
reg_enable(void * enable,int size,int bit)191 static int reg_enable(void *enable, int size, int bit)
192 {
193 return reg_enable_flags(enable, size, bit, 0);
194 }
195
reg_disable(void * enable,int bit)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, ®);
210
211 close(fd);
212
213 return ret;
214 }
215
FIXTURE(user)216 FIXTURE(user) {
217 int check;
218 long check_long;
219 bool umount;
220 };
221
FIXTURE_SETUP(user)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
FIXTURE_TEARDOWN(user)230 FIXTURE_TEARDOWN(user) {
231 USER_EVENT_FIXTURE_TEARDOWN(self->umount);
232 }
233
TEST_F(user,enablement)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
TEST_F(user,flags)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
TEST_F(user,bit_sizes)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
TEST_F(user,multi_format)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
TEST_F(user,forks)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 */
clone_check(void * check)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
TEST_F(user,clones)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
main(int argc,char ** argv)420 int main(int argc, char **argv)
421 {
422 return test_harness_run(argc, argv);
423 }
424