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