Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

tracing/user_events: Add ABI self-test

Add ABI specific self-test to ensure enablements work in various
scenarios such as fork, VM_CLONE, and basic event enable/disable.
Ensure ABI contracts/limits are also being upheld, such as bit limits
and data size limits.

Link: https://lkml.kernel.org/r/20230328235219.203-8-beaub@linux.microsoft.com

Signed-off-by: Beau Belgrave <beaub@linux.microsoft.com>
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>

authored by

Beau Belgrave and committed by
Steven Rostedt (Google)
60b1af8d 0d309f04

+227 -1
+1 -1
tools/testing/selftests/user_events/Makefile
··· 10 10 # This test will not compile until user_events.h is added 11 11 # back to uapi. 12 12 13 - TEST_GEN_PROGS = ftrace_test dyn_test perf_test 13 + TEST_GEN_PROGS = ftrace_test dyn_test perf_test abi_test 14 14 15 15 TEST_FILES := settings 16 16
+226
tools/testing/selftests/user_events/abi_test.c
··· 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, &reg); 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, &reg); 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 + /* Should not change 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, change_event(false)); 117 + ASSERT_EQ(1, self->check); 118 + self->check = 0; 119 + } 120 + 121 + TEST_F(user, bit_sizes) { 122 + /* Allow 0-31 bits for 32-bit */ 123 + ASSERT_EQ(0, reg_enable(&self->check, sizeof(int), 0)); 124 + ASSERT_EQ(0, reg_enable(&self->check, sizeof(int), 31)); 125 + ASSERT_NE(0, reg_enable(&self->check, sizeof(int), 32)); 126 + ASSERT_EQ(0, reg_disable(&self->check, 0)); 127 + ASSERT_EQ(0, reg_disable(&self->check, 31)); 128 + 129 + #if BITS_PER_LONG == 8 130 + /* Allow 0-64 bits for 64-bit */ 131 + ASSERT_EQ(0, reg_enable(&self->check, sizeof(long), 63)); 132 + ASSERT_NE(0, reg_enable(&self->check, sizeof(long), 64)); 133 + ASSERT_EQ(0, reg_disable(&self->check, 63)); 134 + #endif 135 + 136 + /* Disallowed sizes (everything beside 4 and 8) */ 137 + ASSERT_NE(0, reg_enable(&self->check, 1, 0)); 138 + ASSERT_NE(0, reg_enable(&self->check, 2, 0)); 139 + ASSERT_NE(0, reg_enable(&self->check, 3, 0)); 140 + ASSERT_NE(0, reg_enable(&self->check, 5, 0)); 141 + ASSERT_NE(0, reg_enable(&self->check, 6, 0)); 142 + ASSERT_NE(0, reg_enable(&self->check, 7, 0)); 143 + ASSERT_NE(0, reg_enable(&self->check, 9, 0)); 144 + ASSERT_NE(0, reg_enable(&self->check, 128, 0)); 145 + } 146 + 147 + TEST_F(user, forks) { 148 + int i; 149 + 150 + /* Ensure COW pages get updated after fork */ 151 + ASSERT_EQ(0, reg_enable(&self->check, sizeof(int), 0)); 152 + ASSERT_EQ(0, self->check); 153 + 154 + if (fork() == 0) { 155 + /* Force COW */ 156 + self->check = 0; 157 + 158 + /* Up to 1 sec for enablement */ 159 + for (i = 0; i < 10; ++i) { 160 + usleep(100000); 161 + 162 + if (self->check) 163 + exit(0); 164 + } 165 + 166 + exit(1); 167 + } 168 + 169 + /* Allow generous time for COW, then enable */ 170 + usleep(100000); 171 + ASSERT_EQ(0, change_event(true)); 172 + 173 + ASSERT_NE(-1, wait(&i)); 174 + ASSERT_EQ(0, WEXITSTATUS(i)); 175 + 176 + /* Ensure child doesn't disable parent */ 177 + if (fork() == 0) 178 + exit(reg_disable(&self->check, 0)); 179 + 180 + ASSERT_NE(-1, wait(&i)); 181 + ASSERT_EQ(0, WEXITSTATUS(i)); 182 + ASSERT_EQ(1, self->check); 183 + ASSERT_EQ(0, change_event(false)); 184 + ASSERT_EQ(0, self->check); 185 + } 186 + 187 + /* Waits up to 1 sec for enablement */ 188 + static int clone_check(void *check) 189 + { 190 + int i; 191 + 192 + for (i = 0; i < 10; ++i) { 193 + usleep(100000); 194 + 195 + if (*(long *)check) 196 + return 0; 197 + } 198 + 199 + return 1; 200 + } 201 + 202 + TEST_F(user, clones) { 203 + int i, stack_size = 4096; 204 + void *stack = mmap(NULL, stack_size, PROT_READ | PROT_WRITE, 205 + MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, 206 + -1, 0); 207 + 208 + ASSERT_NE(MAP_FAILED, stack); 209 + ASSERT_EQ(0, reg_enable(&self->check, sizeof(int), 0)); 210 + ASSERT_EQ(0, self->check); 211 + 212 + /* Shared VM should see enablements */ 213 + ASSERT_NE(-1, clone(&clone_check, stack + stack_size, 214 + CLONE_VM | SIGCHLD, &self->check)); 215 + 216 + ASSERT_EQ(0, change_event(true)); 217 + ASSERT_NE(-1, wait(&i)); 218 + ASSERT_EQ(0, WEXITSTATUS(i)); 219 + munmap(stack, stack_size); 220 + ASSERT_EQ(0, change_event(false)); 221 + } 222 + 223 + int main(int argc, char **argv) 224 + { 225 + return test_harness_run(argc, argv); 226 + }