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(long *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(long *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 long check; 94 }; 95 96 FIXTURE_SETUP(user) { 97 USER_EVENT_FIXTURE_SETUP(return); 98 99 change_event(false); 100 self->check = 0; 101 } 102 103 FIXTURE_TEARDOWN(user) { 104 } 105 106 TEST_F(user, enablement) { 107 /* Changes should be reflected immediately */ 108 ASSERT_EQ(0, self->check); 109 ASSERT_EQ(0, reg_enable(&self->check, sizeof(int), 0)); 110 ASSERT_EQ(0, change_event(true)); 111 ASSERT_EQ(1, self->check); 112 ASSERT_EQ(0, change_event(false)); 113 ASSERT_EQ(0, self->check); 114 115 /* Ensure kernel clears bit after disable */ 116 ASSERT_EQ(0, change_event(true)); 117 ASSERT_EQ(1, self->check); 118 ASSERT_EQ(0, reg_disable(&self->check, 0)); 119 ASSERT_EQ(0, self->check); 120 121 /* Ensure doesn't change after unreg */ 122 ASSERT_EQ(0, change_event(true)); 123 ASSERT_EQ(0, self->check); 124 ASSERT_EQ(0, change_event(false)); 125 } 126 127 TEST_F(user, bit_sizes) { 128 /* Allow 0-31 bits for 32-bit */ 129 ASSERT_EQ(0, reg_enable(&self->check, sizeof(int), 0)); 130 ASSERT_EQ(0, reg_enable(&self->check, sizeof(int), 31)); 131 ASSERT_NE(0, reg_enable(&self->check, sizeof(int), 32)); 132 ASSERT_EQ(0, reg_disable(&self->check, 0)); 133 ASSERT_EQ(0, reg_disable(&self->check, 31)); 134 135 #if BITS_PER_LONG == 8 136 /* Allow 0-64 bits for 64-bit */ 137 ASSERT_EQ(0, reg_enable(&self->check, sizeof(long), 63)); 138 ASSERT_NE(0, reg_enable(&self->check, sizeof(long), 64)); 139 ASSERT_EQ(0, reg_disable(&self->check, 63)); 140 #endif 141 142 /* Disallowed sizes (everything beside 4 and 8) */ 143 ASSERT_NE(0, reg_enable(&self->check, 1, 0)); 144 ASSERT_NE(0, reg_enable(&self->check, 2, 0)); 145 ASSERT_NE(0, reg_enable(&self->check, 3, 0)); 146 ASSERT_NE(0, reg_enable(&self->check, 5, 0)); 147 ASSERT_NE(0, reg_enable(&self->check, 6, 0)); 148 ASSERT_NE(0, reg_enable(&self->check, 7, 0)); 149 ASSERT_NE(0, reg_enable(&self->check, 9, 0)); 150 ASSERT_NE(0, reg_enable(&self->check, 128, 0)); 151 } 152 153 TEST_F(user, forks) { 154 int i; 155 156 /* Ensure COW pages get updated after fork */ 157 ASSERT_EQ(0, reg_enable(&self->check, sizeof(int), 0)); 158 ASSERT_EQ(0, self->check); 159 160 if (fork() == 0) { 161 /* Force COW */ 162 self->check = 0; 163 164 /* Up to 1 sec for enablement */ 165 for (i = 0; i < 10; ++i) { 166 usleep(100000); 167 168 if (self->check) 169 exit(0); 170 } 171 172 exit(1); 173 } 174 175 /* Allow generous time for COW, then enable */ 176 usleep(100000); 177 ASSERT_EQ(0, change_event(true)); 178 179 ASSERT_NE(-1, wait(&i)); 180 ASSERT_EQ(0, WEXITSTATUS(i)); 181 182 /* Ensure child doesn't disable parent */ 183 if (fork() == 0) 184 exit(reg_disable(&self->check, 0)); 185 186 ASSERT_NE(-1, wait(&i)); 187 ASSERT_EQ(0, WEXITSTATUS(i)); 188 ASSERT_EQ(1, self->check); 189 ASSERT_EQ(0, change_event(false)); 190 ASSERT_EQ(0, self->check); 191 } 192 193 /* Waits up to 1 sec for enablement */ 194 static int clone_check(void *check) 195 { 196 int i; 197 198 for (i = 0; i < 10; ++i) { 199 usleep(100000); 200 201 if (*(long *)check) 202 return 0; 203 } 204 205 return 1; 206 } 207 208 TEST_F(user, clones) { 209 int i, stack_size = 4096; 210 void *stack = mmap(NULL, stack_size, PROT_READ | PROT_WRITE, 211 MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, 212 -1, 0); 213 214 ASSERT_NE(MAP_FAILED, stack); 215 ASSERT_EQ(0, reg_enable(&self->check, sizeof(int), 0)); 216 ASSERT_EQ(0, self->check); 217 218 /* Shared VM should see enablements */ 219 ASSERT_NE(-1, clone(&clone_check, stack + stack_size, 220 CLONE_VM | SIGCHLD, &self->check)); 221 222 ASSERT_EQ(0, change_event(true)); 223 ASSERT_NE(-1, wait(&i)); 224 ASSERT_EQ(0, WEXITSTATUS(i)); 225 munmap(stack, stack_size); 226 ASSERT_EQ(0, change_event(false)); 227 } 228 229 int main(int argc, char **argv) 230 { 231 return test_harness_run(argc, argv); 232 } 233