1/* 2 * Check decoding of threads when a non-leader thread invokes execve. 3 * 4 * Copyright (c) 2016 Dmitry V. Levin <ldv@altlinux.org> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. The name of the author may not be used to endorse or promote products 16 * derived from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30#include "tests.h" 31#include <asm/unistd.h> 32#include <errno.h> 33#include <pthread.h> 34#include <signal.h> 35#include <stdio.h> 36#include <stdlib.h> 37#include <time.h> 38#include <unistd.h> 39 40static pid_t leader; 41static pid_t tid; 42 43static void 44handler(int signo) 45{ 46} 47 48static unsigned int sigsetsize; 49static long 50k_sigsuspend(const sigset_t *const set) 51{ 52 return syscall(__NR_rt_sigsuspend, set, sigsetsize); 53} 54 55static pid_t 56k_gettid(void) 57{ 58 return syscall(__NR_gettid); 59} 60 61static void 62get_sigsetsize(void) 63{ 64 static const struct sigaction sa = { .sa_handler = handler }; 65 if (sigaction(SIGUSR1, &sa, NULL)) 66 perror_msg_and_fail("sigaction"); 67 68 sigset_t mask; 69 sigemptyset(&mask); 70 sigaddset(&mask, SIGUSR1); 71 if (sigprocmask(SIG_BLOCK, &mask, NULL)) 72 perror_msg_and_fail("sigprocmask"); 73 74 raise(SIGUSR1); 75 76 sigemptyset(&mask); 77 for (sigsetsize = sizeof(mask) / sizeof(long); 78 sigsetsize; sigsetsize >>= 1) { 79 long rc = k_sigsuspend(&mask); 80 if (!rc) 81 error_msg_and_fail("rt_sigsuspend"); 82 if (EINTR == errno) 83 break; 84 printf("%-5d rt_sigsuspend(%p, %u) = %s\n", 85 leader, &mask, sigsetsize, sprintrc(rc)); 86 } 87 if (!sigsetsize) 88 perror_msg_and_fail("rt_sigsuspend"); 89 printf("%-5d rt_sigsuspend([], %u) = ? ERESTARTNOHAND" 90 " (To be restarted if no handler)\n", leader, sigsetsize); 91} 92 93enum { 94 ACTION_exit = 0, 95 ACTION_rt_sigsuspend, 96 ACTION_nanosleep, 97 NUMBER_OF_ACTIONS 98}; 99 100static const unsigned int NUMBER_OF_ITERATIONS = 1; 101static unsigned int action; 102static int fds[2]; 103 104static unsigned int 105arglen(char **args) 106{ 107 char **p; 108 109 for (p = args; *p; ++p) 110 ; 111 112 return p - args; 113} 114 115static void * 116thread(void *arg) 117{ 118 tid = k_gettid(); 119 120 static char buf[sizeof(action) * 3]; 121 sprintf(buf, "%u", action + 1); 122 123 char **argv = arg; 124 argv[2] = buf; 125 126 if (read(fds[0], fds, sizeof(fds[0]))) 127 perror_msg_and_fail("execve"); 128 129 struct timespec ts = { .tv_nsec = 100000000 }; 130 (void) clock_nanosleep(CLOCK_REALTIME, 0, &ts, NULL); 131 132 ts.tv_nsec = 12345; 133 printf("%-5d nanosleep({tv_sec=0, tv_nsec=%u}, NULL) = 0\n", 134 tid, (unsigned int) ts.tv_nsec); 135 136 switch (action % NUMBER_OF_ACTIONS) { 137 case ACTION_exit: 138 printf("%-5d execve(\"%s\", [\"%s\", \"%s\", \"%s\"]" 139 ", [/* %u vars */] <pid changed to %u ...>\n", 140 tid, argv[0], argv[0], argv[1], argv[2], 141 arglen(environ), leader); 142 break; 143 case ACTION_rt_sigsuspend: 144 printf("%-5d execve(\"%s\", [\"%s\", \"%s\", \"%s\"]" 145 ", [/* %u vars */] <unfinished ...>\n" 146 "%-5d <... rt_sigsuspend resumed>) = ?\n", 147 tid, argv[0], argv[0], argv[1], argv[2], 148 arglen(environ), 149 leader); 150 break; 151 case ACTION_nanosleep: 152 printf("%-5d execve(\"%s\", [\"%s\", \"%s\", \"%s\"]" 153 ", [/* %u vars */] <unfinished ...>\n" 154 "%-5d <... nanosleep resumed> <unfinished ...>)" 155 " = ?\n", 156 tid, argv[0], argv[0], argv[1], argv[2], 157 arglen(environ), 158 leader); 159 break; 160 } 161 162 printf("%-5d +++ superseded by execve in pid %u +++\n" 163 "%-5d <... execve resumed> ) = 0\n", 164 leader, tid, 165 leader); 166 167 (void) nanosleep(&ts, NULL); 168 execve(argv[0], argv, environ); 169 perror_msg_and_fail("execve"); 170} 171 172int 173main(int ac, char **av) 174{ 175 setvbuf(stdout, NULL, _IONBF, 0); 176 leader = getpid(); 177 178 if (ac < 3) { 179 struct timespec ts = { .tv_nsec = 1 }; 180 if (clock_nanosleep(CLOCK_REALTIME, 0, &ts, NULL)) 181 perror_msg_and_skip("clock_nanosleep CLOCK_REALTIME"); 182 183 printf("%-5d execve(\"%s\", [\"%s\"], [/* %u vars */]) = 0\n", 184 leader, av[0], av[0], arglen(environ)); 185 186 get_sigsetsize(); 187 static char buf[sizeof(sigsetsize) * 3]; 188 sprintf(buf, "%u", sigsetsize); 189 190 char *argv[] = { av[0], buf, (char *) "0", NULL }; 191 printf("%-5d execve(\"%s\", [\"%s\", \"%s\", \"%s\"]" 192 ", [/* %u vars */]) = 0\n", 193 leader, argv[0], argv[0], argv[1], argv[2], 194 arglen(environ)); 195 execve(argv[0], argv, environ); 196 perror_msg_and_fail("execve"); 197 } 198 199 sigsetsize = atoi(av[1]); 200 action = atoi(av[2]); 201 202 if (action >= NUMBER_OF_ACTIONS * NUMBER_OF_ITERATIONS) { 203 printf("%-5d +++ exited with 0 +++\n", leader); 204 return 0; 205 } 206 207 if (pipe(fds)) 208 perror_msg_and_fail("pipe"); 209 210 pthread_t t; 211 errno = pthread_create(&t, NULL, thread, av); 212 if (errno) 213 perror_msg_and_fail("pthread_create"); 214 215 struct timespec ts = { .tv_sec = 123 }; 216 sigset_t mask; 217 sigemptyset(&mask); 218 219 static char leader_str[sizeof(leader) * 3]; 220 int leader_str_len = 221 snprintf(leader_str, sizeof(leader_str), "%-5d", leader); 222 223 switch (action % NUMBER_OF_ACTIONS) { 224 case ACTION_exit: 225 printf("%s exit(42)%*s= ?\n", leader_str, 226 (int) sizeof(leader_str) - leader_str_len, " "); 227 close(fds[1]); 228 (void) syscall(__NR_exit, 42); 229 break; 230 case ACTION_rt_sigsuspend: 231 printf("%s rt_sigsuspend([], %u <unfinished ...>\n", 232 leader_str, sigsetsize); 233 close(fds[1]); 234 (void) k_sigsuspend(&mask); 235 break; 236 case ACTION_nanosleep: 237 printf("%s nanosleep({tv_sec=%u, tv_nsec=0}" 238 ", <unfinished ...>\n", 239 leader_str, (unsigned int) ts.tv_sec); 240 close(fds[1]); 241 (void) nanosleep(&ts, 0); 242 break; 243 } 244 245 return 1; 246} 247