1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Copyright (c) 2020 Viresh Kumar <viresh.kumar@linaro.org> 4 */ 5 6/*\ 7 * [Description] 8 * 9 * Basic clone3() test. 10 */ 11 12#define _GNU_SOURCE 13 14#include <stdlib.h> 15#include <sys/wait.h> 16 17#include "tst_test.h" 18#include "lapi/sched.h" 19#include "lapi/pidfd.h" 20 21#define CHILD_SIGNAL SIGUSR1 22#define DATA 777 23 24static int pidfd, child_tid, parent_tid, parent_received_signal; 25static volatile int child_received_signal, child_data; 26static struct clone_args *args; 27 28static struct tcase { 29 uint64_t flags; 30 int exit_signal; 31} tcases[] = { 32 {0, SIGCHLD}, 33 {0, SIGUSR2}, 34 {CLONE_FS, SIGCHLD}, 35 {CLONE_NEWPID, SIGCHLD}, 36 {CLONE_PARENT_SETTID | CLONE_CHILD_SETTID | CLONE_PIDFD, SIGCHLD}, 37}; 38 39static void parent_rx_signal(int sig) 40{ 41 parent_received_signal = sig; 42} 43 44static void child_rx_signal(int sig, siginfo_t *info, void *ucontext) 45{ 46 (void) ucontext; 47 48 child_received_signal = sig; 49 child_data = info->si_value.sival_int; 50} 51 52static struct sigaction psig_action = { 53 .sa_handler = parent_rx_signal, 54}; 55 56static struct sigaction csig_action = { 57 .sa_sigaction = child_rx_signal, 58 .sa_flags = SA_SIGINFO, 59}; 60 61static siginfo_t uinfo = { 62 .si_signo = CHILD_SIGNAL, 63 .si_code = SI_QUEUE, 64 .si_value.sival_int = DATA, 65}; 66 67 68static void do_child(int clone_pidfd) 69{ 70 int count = 1000; 71 72 if (clone_pidfd) { 73 child_received_signal = 0; 74 child_data = 0; 75 76 SAFE_SIGACTION(CHILD_SIGNAL, &csig_action, NULL); 77 78 TST_CHECKPOINT_WAKE(0); 79 80 while (child_received_signal != CHILD_SIGNAL && --count) 81 usleep(100); 82 83 if (!child_received_signal) { 84 tst_res(TFAIL, "Child haven't got signal"); 85 exit(0); 86 } 87 88 if (child_received_signal != CHILD_SIGNAL) { 89 tst_res(TFAIL, "Child got %s (%i) signal expected %s", 90 tst_strsig(child_received_signal), 91 child_received_signal, 92 tst_strsig(CHILD_SIGNAL)); 93 exit(0); 94 } 95 96 tst_res(TPASS, "Child got correct signal %s", 97 tst_strsig(CHILD_SIGNAL)); 98 99 if (child_data != DATA) { 100 tst_res(TFAIL, "Child got wrong si_value=%i expected %i", 101 child_data, DATA); 102 } else { 103 tst_res(TPASS, "Child got correct si_value"); 104 } 105 } 106 107 exit(0); 108} 109 110static void run(unsigned int n) 111{ 112 struct tcase *tc = &tcases[n]; 113 int status, clone_pidfd = tc->flags & CLONE_PIDFD; 114 pid_t pid; 115 116 args->flags = tc->flags; 117 args->pidfd = (uint64_t)(&pidfd); 118 args->child_tid = (uint64_t)(&child_tid); 119 args->parent_tid = (uint64_t)(&parent_tid); 120 args->exit_signal = tc->exit_signal; 121 args->stack = 0; 122 args->stack_size = 0; 123 args->tls = 0; 124 125 parent_received_signal = 0; 126 SAFE_SIGACTION(tc->exit_signal, &psig_action, NULL); 127 128 TEST(pid = clone3(args, sizeof(*args))); 129 if (pid < 0) { 130 tst_res(TFAIL | TTERRNO, "clone3() failed (%d)", n); 131 return; 132 } 133 134 if (!pid) 135 do_child(clone_pidfd); 136 137 /* Need to send signal to child process */ 138 if (clone_pidfd) { 139 TST_CHECKPOINT_WAIT(0); 140 141 TEST(pidfd_send_signal(pidfd, CHILD_SIGNAL, &uinfo, 0)); 142 if (TST_RET != 0) { 143 tst_res(TFAIL | TTERRNO, "pidfd_send_signal() failed"); 144 return; 145 } 146 } 147 148 SAFE_WAITPID(pid, &status, __WALL); 149 150 if (!parent_received_signal) { 151 tst_res(TFAIL, "Parent haven't got signal"); 152 return; 153 } 154 155 if (parent_received_signal != tc->exit_signal) { 156 tst_res(TFAIL, "Parent got %s (%i) signal expected %s", 157 tst_strsig(parent_received_signal), 158 parent_received_signal, 159 tst_strsig(tc->exit_signal)); 160 return; 161 } 162 163 tst_res(TPASS, "Parent got correct signal %s", 164 tst_strsig(parent_received_signal)); 165} 166 167static void setup(void) 168{ 169 clone3_supported_by_kernel(); 170 171 uinfo.si_pid = getpid(); 172 uinfo.si_uid = getuid(); 173} 174 175static struct tst_test test = { 176 .tcnt = ARRAY_SIZE(tcases), 177 .test = run, 178 .setup = setup, 179 .needs_root = 1, 180 .needs_checkpoints = 1, 181 .bufs = (struct tst_buffers []) { 182 {&args, .size = sizeof(*args)}, 183 {}, 184 } 185}; 186