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 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 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 191 static int reg_enable(void *enable, int size, int bit) 192 { 193 return reg_enable_flags(enable, size, bit, 0); 194 } 195 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 216 FIXTURE(user) { 217 int check; 218 long check_long; 219 bool umount; 220 }; 221 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 230 FIXTURE_TEARDOWN(user) { 231 USER_EVENT_FIXTURE_TEARDOWN(self->umount); 232 } 233 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 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 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 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 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 */ 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 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 420 int main(int argc, char **argv) 421 { 422 return test_harness_run(argc, argv); 423 } 424