xref: /linux/tools/testing/selftests/user_events/abi_test.c (revision 702648721db590b3425c31ade294000e18808345)
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 <asm/unistd.h>
20 
21 #include "../kselftest_harness.h"
22 
23 const char *data_file = "/sys/kernel/tracing/user_events_data";
24 const char *enable_file = "/sys/kernel/tracing/events/user_events/__abi_event/enable";
25 
26 static int change_event(bool enable)
27 {
28 	int fd = open(enable_file, O_RDWR);
29 	int ret;
30 
31 	if (fd < 0)
32 		return -1;
33 
34 	if (enable)
35 		ret = write(fd, "1", 1);
36 	else
37 		ret = write(fd, "0", 1);
38 
39 	close(fd);
40 
41 	if (ret == 1)
42 		ret = 0;
43 	else
44 		ret = -1;
45 
46 	return ret;
47 }
48 
49 static int reg_enable(long *enable, int size, int bit)
50 {
51 	struct user_reg reg = {0};
52 	int fd = open(data_file, O_RDWR);
53 	int ret;
54 
55 	if (fd < 0)
56 		return -1;
57 
58 	reg.size = sizeof(reg);
59 	reg.name_args = (__u64)"__abi_event";
60 	reg.enable_bit = bit;
61 	reg.enable_addr = (__u64)enable;
62 	reg.enable_size = size;
63 
64 	ret = ioctl(fd, DIAG_IOCSREG, &reg);
65 
66 	close(fd);
67 
68 	return ret;
69 }
70 
71 static int reg_disable(long *enable, int bit)
72 {
73 	struct user_unreg reg = {0};
74 	int fd = open(data_file, O_RDWR);
75 	int ret;
76 
77 	if (fd < 0)
78 		return -1;
79 
80 	reg.size = sizeof(reg);
81 	reg.disable_bit = bit;
82 	reg.disable_addr = (__u64)enable;
83 
84 	ret = ioctl(fd, DIAG_IOCSUNREG, &reg);
85 
86 	close(fd);
87 
88 	return ret;
89 }
90 
91 FIXTURE(user) {
92 	long check;
93 };
94 
95 FIXTURE_SETUP(user) {
96 	change_event(false);
97 	self->check = 0;
98 }
99 
100 FIXTURE_TEARDOWN(user) {
101 }
102 
103 TEST_F(user, enablement) {
104 	/* Changes should be reflected immediately */
105 	ASSERT_EQ(0, self->check);
106 	ASSERT_EQ(0, reg_enable(&self->check, sizeof(int), 0));
107 	ASSERT_EQ(0, change_event(true));
108 	ASSERT_EQ(1, self->check);
109 	ASSERT_EQ(0, change_event(false));
110 	ASSERT_EQ(0, self->check);
111 
112 	/* Ensure kernel clears bit after disable */
113 	ASSERT_EQ(0, change_event(true));
114 	ASSERT_EQ(1, self->check);
115 	ASSERT_EQ(0, reg_disable(&self->check, 0));
116 	ASSERT_EQ(0, self->check);
117 
118 	/* Ensure doesn't change after unreg */
119 	ASSERT_EQ(0, change_event(true));
120 	ASSERT_EQ(0, self->check);
121 	ASSERT_EQ(0, change_event(false));
122 }
123 
124 TEST_F(user, bit_sizes) {
125 	/* Allow 0-31 bits for 32-bit */
126 	ASSERT_EQ(0, reg_enable(&self->check, sizeof(int), 0));
127 	ASSERT_EQ(0, reg_enable(&self->check, sizeof(int), 31));
128 	ASSERT_NE(0, reg_enable(&self->check, sizeof(int), 32));
129 	ASSERT_EQ(0, reg_disable(&self->check, 0));
130 	ASSERT_EQ(0, reg_disable(&self->check, 31));
131 
132 #if BITS_PER_LONG == 8
133 	/* Allow 0-64 bits for 64-bit */
134 	ASSERT_EQ(0, reg_enable(&self->check, sizeof(long), 63));
135 	ASSERT_NE(0, reg_enable(&self->check, sizeof(long), 64));
136 	ASSERT_EQ(0, reg_disable(&self->check, 63));
137 #endif
138 
139 	/* Disallowed sizes (everything beside 4 and 8) */
140 	ASSERT_NE(0, reg_enable(&self->check, 1, 0));
141 	ASSERT_NE(0, reg_enable(&self->check, 2, 0));
142 	ASSERT_NE(0, reg_enable(&self->check, 3, 0));
143 	ASSERT_NE(0, reg_enable(&self->check, 5, 0));
144 	ASSERT_NE(0, reg_enable(&self->check, 6, 0));
145 	ASSERT_NE(0, reg_enable(&self->check, 7, 0));
146 	ASSERT_NE(0, reg_enable(&self->check, 9, 0));
147 	ASSERT_NE(0, reg_enable(&self->check, 128, 0));
148 }
149 
150 TEST_F(user, forks) {
151 	int i;
152 
153 	/* Ensure COW pages get updated after fork */
154 	ASSERT_EQ(0, reg_enable(&self->check, sizeof(int), 0));
155 	ASSERT_EQ(0, self->check);
156 
157 	if (fork() == 0) {
158 		/* Force COW */
159 		self->check = 0;
160 
161 		/* Up to 1 sec for enablement */
162 		for (i = 0; i < 10; ++i) {
163 			usleep(100000);
164 
165 			if (self->check)
166 				exit(0);
167 		}
168 
169 		exit(1);
170 	}
171 
172 	/* Allow generous time for COW, then enable */
173 	usleep(100000);
174 	ASSERT_EQ(0, change_event(true));
175 
176 	ASSERT_NE(-1, wait(&i));
177 	ASSERT_EQ(0, WEXITSTATUS(i));
178 
179 	/* Ensure child doesn't disable parent */
180 	if (fork() == 0)
181 		exit(reg_disable(&self->check, 0));
182 
183 	ASSERT_NE(-1, wait(&i));
184 	ASSERT_EQ(0, WEXITSTATUS(i));
185 	ASSERT_EQ(1, self->check);
186 	ASSERT_EQ(0, change_event(false));
187 	ASSERT_EQ(0, self->check);
188 }
189 
190 /* Waits up to 1 sec for enablement */
191 static int clone_check(void *check)
192 {
193 	int i;
194 
195 	for (i = 0; i < 10; ++i) {
196 		usleep(100000);
197 
198 		if (*(long *)check)
199 			return 0;
200 	}
201 
202 	return 1;
203 }
204 
205 TEST_F(user, clones) {
206 	int i, stack_size = 4096;
207 	void *stack = mmap(NULL, stack_size, PROT_READ | PROT_WRITE,
208 			   MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK,
209 			   -1, 0);
210 
211 	ASSERT_NE(MAP_FAILED, stack);
212 	ASSERT_EQ(0, reg_enable(&self->check, sizeof(int), 0));
213 	ASSERT_EQ(0, self->check);
214 
215 	/* Shared VM should see enablements */
216 	ASSERT_NE(-1, clone(&clone_check, stack + stack_size,
217 			    CLONE_VM | SIGCHLD, &self->check));
218 
219 	ASSERT_EQ(0, change_event(true));
220 	ASSERT_NE(-1, wait(&i));
221 	ASSERT_EQ(0, WEXITSTATUS(i));
222 	munmap(stack, stack_size);
223 	ASSERT_EQ(0, change_event(false));
224 }
225 
226 int main(int argc, char **argv)
227 {
228 	return test_harness_run(argc, argv);
229 }
230