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, ®); 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, ®); 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