1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * User Events FTrace Test Program
4 *
5 * Copyright (c) 2021 Beau Belgrave <beaub@linux.microsoft.com>
6 */
7
8 #include <errno.h>
9 #include <linux/user_events.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <fcntl.h>
13 #include <sys/ioctl.h>
14 #include <sys/stat.h>
15 #include <unistd.h>
16
17 #include "../kselftest_harness.h"
18
19 const char *data_file = "/sys/kernel/debug/tracing/user_events_data";
20 const char *status_file = "/sys/kernel/debug/tracing/user_events_status";
21 const char *enable_file = "/sys/kernel/debug/tracing/events/user_events/__test_event/enable";
22 const char *trace_file = "/sys/kernel/debug/tracing/trace";
23 const char *fmt_file = "/sys/kernel/debug/tracing/events/user_events/__test_event/format";
24
trace_bytes(void)25 static int trace_bytes(void)
26 {
27 int fd = open(trace_file, O_RDONLY);
28 char buf[256];
29 int bytes = 0, got;
30
31 if (fd == -1)
32 return -1;
33
34 while (true) {
35 got = read(fd, buf, sizeof(buf));
36
37 if (got == -1)
38 return -1;
39
40 if (got == 0)
41 break;
42
43 bytes += got;
44 }
45
46 close(fd);
47
48 return bytes;
49 }
50
skip_until_empty_line(FILE * fp)51 static int skip_until_empty_line(FILE *fp)
52 {
53 int c, last = 0;
54
55 while (true) {
56 c = getc(fp);
57
58 if (c == EOF)
59 break;
60
61 if (last == '\n' && c == '\n')
62 return 0;
63
64 last = c;
65 }
66
67 return -1;
68 }
69
get_print_fmt(char * buffer,int len)70 static int get_print_fmt(char *buffer, int len)
71 {
72 FILE *fp = fopen(fmt_file, "r");
73 char *newline;
74
75 if (!fp)
76 return -1;
77
78 /* Read until empty line (Skip Common) */
79 if (skip_until_empty_line(fp) < 0)
80 goto err;
81
82 /* Read until empty line (Skip Properties) */
83 if (skip_until_empty_line(fp) < 0)
84 goto err;
85
86 /* Read in print_fmt: */
87 if (fgets(buffer, len, fp) == NULL)
88 goto err;
89
90 newline = strchr(buffer, '\n');
91
92 if (newline)
93 *newline = '\0';
94
95 fclose(fp);
96
97 return 0;
98 err:
99 fclose(fp);
100
101 return -1;
102 }
103
clear(void)104 static int clear(void)
105 {
106 int fd = open(data_file, O_RDWR);
107
108 if (fd == -1)
109 return -1;
110
111 if (ioctl(fd, DIAG_IOCSDEL, "__test_event") == -1)
112 if (errno != ENOENT)
113 return -1;
114
115 close(fd);
116
117 return 0;
118 }
119
check_print_fmt(const char * event,const char * expected)120 static int check_print_fmt(const char *event, const char *expected)
121 {
122 struct user_reg reg = {0};
123 char print_fmt[256];
124 int ret;
125 int fd;
126
127 /* Ensure cleared */
128 ret = clear();
129
130 if (ret != 0)
131 return ret;
132
133 fd = open(data_file, O_RDWR);
134
135 if (fd == -1)
136 return fd;
137
138 reg.size = sizeof(reg);
139 reg.name_args = (__u64)event;
140
141 /* Register should work */
142 ret = ioctl(fd, DIAG_IOCSREG, ®);
143
144 close(fd);
145
146 if (ret != 0)
147 return ret;
148
149 /* Ensure correct print_fmt */
150 ret = get_print_fmt(print_fmt, sizeof(print_fmt));
151
152 if (ret != 0)
153 return ret;
154
155 return strcmp(print_fmt, expected);
156 }
157
FIXTURE(user)158 FIXTURE(user) {
159 int status_fd;
160 int data_fd;
161 int enable_fd;
162 };
163
FIXTURE_SETUP(user)164 FIXTURE_SETUP(user) {
165 self->status_fd = open(status_file, O_RDONLY);
166 ASSERT_NE(-1, self->status_fd);
167
168 self->data_fd = open(data_file, O_RDWR);
169 ASSERT_NE(-1, self->data_fd);
170
171 self->enable_fd = -1;
172 }
173
FIXTURE_TEARDOWN(user)174 FIXTURE_TEARDOWN(user) {
175 close(self->status_fd);
176 close(self->data_fd);
177
178 if (self->enable_fd != -1) {
179 write(self->enable_fd, "0", sizeof("0"));
180 close(self->enable_fd);
181 }
182
183 ASSERT_EQ(0, clear());
184 }
185
TEST_F(user,register_events)186 TEST_F(user, register_events) {
187 struct user_reg reg = {0};
188 int page_size = sysconf(_SC_PAGESIZE);
189 char *status_page;
190
191 reg.size = sizeof(reg);
192 reg.name_args = (__u64)"__test_event u32 field1; u32 field2";
193
194 status_page = mmap(NULL, page_size, PROT_READ, MAP_SHARED,
195 self->status_fd, 0);
196
197 /* Register should work */
198 ASSERT_EQ(0, ioctl(self->data_fd, DIAG_IOCSREG, ®));
199 ASSERT_EQ(0, reg.write_index);
200 ASSERT_NE(0, reg.status_index);
201
202 /* Multiple registers should result in same index */
203 ASSERT_EQ(0, ioctl(self->data_fd, DIAG_IOCSREG, ®));
204 ASSERT_EQ(0, reg.write_index);
205 ASSERT_NE(0, reg.status_index);
206
207 /* Ensure disabled */
208 self->enable_fd = open(enable_file, O_RDWR);
209 ASSERT_NE(-1, self->enable_fd);
210 ASSERT_NE(-1, write(self->enable_fd, "0", sizeof("0")))
211
212 /* MMAP should work and be zero'd */
213 ASSERT_NE(MAP_FAILED, status_page);
214 ASSERT_NE(NULL, status_page);
215 ASSERT_EQ(0, status_page[reg.status_index]);
216
217 /* Enable event and ensure bits updated in status */
218 ASSERT_NE(-1, write(self->enable_fd, "1", sizeof("1")))
219 ASSERT_EQ(EVENT_STATUS_FTRACE, status_page[reg.status_index]);
220
221 /* Disable event and ensure bits updated in status */
222 ASSERT_NE(-1, write(self->enable_fd, "0", sizeof("0")))
223 ASSERT_EQ(0, status_page[reg.status_index]);
224
225 /* File still open should return -EBUSY for delete */
226 ASSERT_EQ(-1, ioctl(self->data_fd, DIAG_IOCSDEL, "__test_event"));
227 ASSERT_EQ(EBUSY, errno);
228
229 /* Delete should work only after close */
230 close(self->data_fd);
231 self->data_fd = open(data_file, O_RDWR);
232 ASSERT_EQ(0, ioctl(self->data_fd, DIAG_IOCSDEL, "__test_event"));
233
234 /* Unmap should work */
235 ASSERT_EQ(0, munmap(status_page, page_size));
236 }
237
TEST_F(user,write_events)238 TEST_F(user, write_events) {
239 struct user_reg reg = {0};
240 struct iovec io[3];
241 __u32 field1, field2;
242 int before = 0, after = 0;
243
244 reg.size = sizeof(reg);
245 reg.name_args = (__u64)"__test_event u32 field1; u32 field2";
246
247 field1 = 1;
248 field2 = 2;
249
250 io[0].iov_base = ®.write_index;
251 io[0].iov_len = sizeof(reg.write_index);
252 io[1].iov_base = &field1;
253 io[1].iov_len = sizeof(field1);
254 io[2].iov_base = &field2;
255 io[2].iov_len = sizeof(field2);
256
257 /* Register should work */
258 ASSERT_EQ(0, ioctl(self->data_fd, DIAG_IOCSREG, ®));
259 ASSERT_EQ(0, reg.write_index);
260 ASSERT_NE(0, reg.status_index);
261
262 /* Write should fail on invalid slot with ENOENT */
263 io[0].iov_base = &field2;
264 io[0].iov_len = sizeof(field2);
265 ASSERT_EQ(-1, writev(self->data_fd, (const struct iovec *)io, 3));
266 ASSERT_EQ(ENOENT, errno);
267 io[0].iov_base = ®.write_index;
268 io[0].iov_len = sizeof(reg.write_index);
269
270 /* Enable event */
271 self->enable_fd = open(enable_file, O_RDWR);
272 ASSERT_NE(-1, write(self->enable_fd, "1", sizeof("1")))
273
274 /* Write should make it out to ftrace buffers */
275 before = trace_bytes();
276 ASSERT_NE(-1, writev(self->data_fd, (const struct iovec *)io, 3));
277 after = trace_bytes();
278 ASSERT_GT(after, before);
279 }
280
TEST_F(user,write_fault)281 TEST_F(user, write_fault) {
282 struct user_reg reg = {0};
283 struct iovec io[2];
284 int l = sizeof(__u64);
285 void *anon;
286
287 reg.size = sizeof(reg);
288 reg.name_args = (__u64)"__test_event u64 anon";
289
290 anon = mmap(NULL, l, PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
291 ASSERT_NE(MAP_FAILED, anon);
292
293 io[0].iov_base = ®.write_index;
294 io[0].iov_len = sizeof(reg.write_index);
295 io[1].iov_base = anon;
296 io[1].iov_len = l;
297
298 /* Register should work */
299 ASSERT_EQ(0, ioctl(self->data_fd, DIAG_IOCSREG, ®));
300 ASSERT_EQ(0, reg.write_index);
301 ASSERT_NE(0, reg.status_index);
302
303 /* Write should work normally */
304 ASSERT_NE(-1, writev(self->data_fd, (const struct iovec *)io, 2));
305
306 /* Faulted data should zero fill and work */
307 ASSERT_EQ(0, madvise(anon, l, MADV_DONTNEED));
308 ASSERT_NE(-1, writev(self->data_fd, (const struct iovec *)io, 2));
309 ASSERT_EQ(0, munmap(anon, l));
310 }
311
TEST_F(user,write_validator)312 TEST_F(user, write_validator) {
313 struct user_reg reg = {0};
314 struct iovec io[3];
315 int loc, bytes;
316 char data[8];
317 int before = 0, after = 0;
318
319 reg.size = sizeof(reg);
320 reg.name_args = (__u64)"__test_event __rel_loc char[] data";
321
322 /* Register should work */
323 ASSERT_EQ(0, ioctl(self->data_fd, DIAG_IOCSREG, ®));
324 ASSERT_EQ(0, reg.write_index);
325 ASSERT_NE(0, reg.status_index);
326
327 io[0].iov_base = ®.write_index;
328 io[0].iov_len = sizeof(reg.write_index);
329 io[1].iov_base = &loc;
330 io[1].iov_len = sizeof(loc);
331 io[2].iov_base = data;
332 bytes = snprintf(data, sizeof(data), "Test") + 1;
333 io[2].iov_len = bytes;
334
335 /* Undersized write should fail */
336 ASSERT_EQ(-1, writev(self->data_fd, (const struct iovec *)io, 1));
337 ASSERT_EQ(EINVAL, errno);
338
339 /* Enable event */
340 self->enable_fd = open(enable_file, O_RDWR);
341 ASSERT_NE(-1, write(self->enable_fd, "1", sizeof("1")))
342
343 /* Full in-bounds write should work */
344 before = trace_bytes();
345 loc = DYN_LOC(0, bytes);
346 ASSERT_NE(-1, writev(self->data_fd, (const struct iovec *)io, 3));
347 after = trace_bytes();
348 ASSERT_GT(after, before);
349
350 /* Out of bounds write should fault (offset way out) */
351 loc = DYN_LOC(1024, bytes);
352 ASSERT_EQ(-1, writev(self->data_fd, (const struct iovec *)io, 3));
353 ASSERT_EQ(EFAULT, errno);
354
355 /* Out of bounds write should fault (offset 1 byte out) */
356 loc = DYN_LOC(1, bytes);
357 ASSERT_EQ(-1, writev(self->data_fd, (const struct iovec *)io, 3));
358 ASSERT_EQ(EFAULT, errno);
359
360 /* Out of bounds write should fault (size way out) */
361 loc = DYN_LOC(0, bytes + 1024);
362 ASSERT_EQ(-1, writev(self->data_fd, (const struct iovec *)io, 3));
363 ASSERT_EQ(EFAULT, errno);
364
365 /* Out of bounds write should fault (size 1 byte out) */
366 loc = DYN_LOC(0, bytes + 1);
367 ASSERT_EQ(-1, writev(self->data_fd, (const struct iovec *)io, 3));
368 ASSERT_EQ(EFAULT, errno);
369
370 /* Non-Null should fault */
371 memset(data, 'A', sizeof(data));
372 loc = DYN_LOC(0, bytes);
373 ASSERT_EQ(-1, writev(self->data_fd, (const struct iovec *)io, 3));
374 ASSERT_EQ(EFAULT, errno);
375 }
376
TEST_F(user,print_fmt)377 TEST_F(user, print_fmt) {
378 int ret;
379
380 ret = check_print_fmt("__test_event __rel_loc char[] data",
381 "print fmt: \"data=%s\", __get_rel_str(data)");
382 ASSERT_EQ(0, ret);
383
384 ret = check_print_fmt("__test_event __data_loc char[] data",
385 "print fmt: \"data=%s\", __get_str(data)");
386 ASSERT_EQ(0, ret);
387
388 ret = check_print_fmt("__test_event s64 data",
389 "print fmt: \"data=%lld\", REC->data");
390 ASSERT_EQ(0, ret);
391
392 ret = check_print_fmt("__test_event u64 data",
393 "print fmt: \"data=%llu\", REC->data");
394 ASSERT_EQ(0, ret);
395
396 ret = check_print_fmt("__test_event s32 data",
397 "print fmt: \"data=%d\", REC->data");
398 ASSERT_EQ(0, ret);
399
400 ret = check_print_fmt("__test_event u32 data",
401 "print fmt: \"data=%u\", REC->data");
402 ASSERT_EQ(0, ret);
403
404 ret = check_print_fmt("__test_event int data",
405 "print fmt: \"data=%d\", REC->data");
406 ASSERT_EQ(0, ret);
407
408 ret = check_print_fmt("__test_event unsigned int data",
409 "print fmt: \"data=%u\", REC->data");
410 ASSERT_EQ(0, ret);
411
412 ret = check_print_fmt("__test_event s16 data",
413 "print fmt: \"data=%d\", REC->data");
414 ASSERT_EQ(0, ret);
415
416 ret = check_print_fmt("__test_event u16 data",
417 "print fmt: \"data=%u\", REC->data");
418 ASSERT_EQ(0, ret);
419
420 ret = check_print_fmt("__test_event short data",
421 "print fmt: \"data=%d\", REC->data");
422 ASSERT_EQ(0, ret);
423
424 ret = check_print_fmt("__test_event unsigned short data",
425 "print fmt: \"data=%u\", REC->data");
426 ASSERT_EQ(0, ret);
427
428 ret = check_print_fmt("__test_event s8 data",
429 "print fmt: \"data=%d\", REC->data");
430 ASSERT_EQ(0, ret);
431
432 ret = check_print_fmt("__test_event u8 data",
433 "print fmt: \"data=%u\", REC->data");
434 ASSERT_EQ(0, ret);
435
436 ret = check_print_fmt("__test_event char data",
437 "print fmt: \"data=%d\", REC->data");
438 ASSERT_EQ(0, ret);
439
440 ret = check_print_fmt("__test_event unsigned char data",
441 "print fmt: \"data=%u\", REC->data");
442 ASSERT_EQ(0, ret);
443
444 ret = check_print_fmt("__test_event char[4] data",
445 "print fmt: \"data=%s\", REC->data");
446 ASSERT_EQ(0, ret);
447 }
448
main(int argc,char ** argv)449 int main(int argc, char **argv)
450 {
451 return test_harness_run(argc, argv);
452 }
453