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