1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * This test is intended to reproduce a crash that happens when 4 * kvm_arch_hardware_disable is called and it attempts to unregister the user 5 * return notifiers. 6 */ 7 8 #define _GNU_SOURCE 9 10 #include <fcntl.h> 11 #include <pthread.h> 12 #include <semaphore.h> 13 #include <stdint.h> 14 #include <stdlib.h> 15 #include <unistd.h> 16 #include <sys/wait.h> 17 18 #include <test_util.h> 19 20 #include "kvm_util.h" 21 22 #define VCPU_NUM 4 23 #define SLEEPING_THREAD_NUM (1 << 4) 24 #define FORK_NUM (1ULL << 9) 25 #define DELAY_US_MAX 2000 26 #define GUEST_CODE_PIO_PORT 4 27 28 sem_t *sem; 29 30 static void guest_code(void) 31 { 32 for (;;) 33 ; /* Some busy work */ 34 printf("Should not be reached.\n"); 35 } 36 37 static void *run_vcpu(void *arg) 38 { 39 struct kvm_vcpu *vcpu = arg; 40 struct kvm_run *run = vcpu->run; 41 42 vcpu_run(vcpu); 43 44 TEST_ASSERT(false, "%s: exited with reason %d: %s\n", 45 __func__, run->exit_reason, 46 exit_reason_str(run->exit_reason)); 47 pthread_exit(NULL); 48 } 49 50 static void *sleeping_thread(void *arg) 51 { 52 int fd; 53 54 while (true) { 55 fd = open("/dev/null", O_RDWR); 56 close(fd); 57 } 58 TEST_ASSERT(false, "%s: exited\n", __func__); 59 pthread_exit(NULL); 60 } 61 62 static inline void check_create_thread(pthread_t *thread, pthread_attr_t *attr, 63 void *(*f)(void *), void *arg) 64 { 65 int r; 66 67 r = pthread_create(thread, attr, f, arg); 68 TEST_ASSERT(r == 0, "%s: failed to create thread", __func__); 69 } 70 71 static inline void check_set_affinity(pthread_t thread, cpu_set_t *cpu_set) 72 { 73 int r; 74 75 r = pthread_setaffinity_np(thread, sizeof(cpu_set_t), cpu_set); 76 TEST_ASSERT(r == 0, "%s: failed set affinity", __func__); 77 } 78 79 static inline void check_join(pthread_t thread, void **retval) 80 { 81 int r; 82 83 r = pthread_join(thread, retval); 84 TEST_ASSERT(r == 0, "%s: failed to join thread", __func__); 85 } 86 87 static void run_test(uint32_t run) 88 { 89 struct kvm_vcpu *vcpu; 90 struct kvm_vm *vm; 91 cpu_set_t cpu_set; 92 pthread_t threads[VCPU_NUM]; 93 pthread_t throw_away; 94 void *b; 95 uint32_t i, j; 96 97 CPU_ZERO(&cpu_set); 98 for (i = 0; i < VCPU_NUM; i++) 99 CPU_SET(i, &cpu_set); 100 101 vm = vm_create(VCPU_NUM); 102 103 pr_debug("%s: [%d] start vcpus\n", __func__, run); 104 for (i = 0; i < VCPU_NUM; ++i) { 105 vcpu = vm_vcpu_add(vm, i, guest_code); 106 107 check_create_thread(&threads[i], NULL, run_vcpu, vcpu); 108 check_set_affinity(threads[i], &cpu_set); 109 110 for (j = 0; j < SLEEPING_THREAD_NUM; ++j) { 111 check_create_thread(&throw_away, NULL, sleeping_thread, 112 (void *)NULL); 113 check_set_affinity(throw_away, &cpu_set); 114 } 115 } 116 pr_debug("%s: [%d] all threads launched\n", __func__, run); 117 sem_post(sem); 118 for (i = 0; i < VCPU_NUM; ++i) 119 check_join(threads[i], &b); 120 /* Should not be reached */ 121 TEST_ASSERT(false, "%s: [%d] child escaped the ninja\n", __func__, run); 122 } 123 124 void wait_for_child_setup(pid_t pid) 125 { 126 /* 127 * Wait for the child to post to the semaphore, but wake up periodically 128 * to check if the child exited prematurely. 129 */ 130 for (;;) { 131 const struct timespec wait_period = { .tv_sec = 1 }; 132 int status; 133 134 if (!sem_timedwait(sem, &wait_period)) 135 return; 136 137 /* Child is still running, keep waiting. */ 138 if (pid != waitpid(pid, &status, WNOHANG)) 139 continue; 140 141 /* 142 * Child is no longer running, which is not expected. 143 * 144 * If it exited with a non-zero status, we explicitly forward 145 * the child's status in case it exited with KSFT_SKIP. 146 */ 147 if (WIFEXITED(status)) 148 exit(WEXITSTATUS(status)); 149 else 150 TEST_ASSERT(false, "Child exited unexpectedly"); 151 } 152 } 153 154 int main(int argc, char **argv) 155 { 156 uint32_t i; 157 int s, r; 158 pid_t pid; 159 160 sem = sem_open("vm_sem", O_CREAT | O_EXCL, 0644, 0); 161 sem_unlink("vm_sem"); 162 163 for (i = 0; i < FORK_NUM; ++i) { 164 pid = fork(); 165 TEST_ASSERT(pid >= 0, "%s: unable to fork", __func__); 166 if (pid == 0) 167 run_test(i); /* This function always exits */ 168 169 pr_debug("%s: [%d] waiting semaphore\n", __func__, i); 170 wait_for_child_setup(pid); 171 r = (rand() % DELAY_US_MAX) + 1; 172 pr_debug("%s: [%d] waiting %dus\n", __func__, i, r); 173 usleep(r); 174 r = waitpid(pid, &s, WNOHANG); 175 TEST_ASSERT(r != pid, 176 "%s: [%d] child exited unexpectedly status: [%d]", 177 __func__, i, s); 178 pr_debug("%s: [%d] killing child\n", __func__, i); 179 kill(pid, SIGKILL); 180 } 181 182 sem_destroy(sem); 183 exit(0); 184 } 185