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