(root)/
strace-6.5/
tests/
threads-execve.c
       1  /*
       2   * Check decoding of threads when a non-leader thread invokes execve.
       3   *
       4   * Copyright (c) 2016 Dmitry V. Levin <ldv@strace.io>
       5   * Copyright (c) 2016-2023 The strace developers.
       6   * All rights reserved.
       7   *
       8   * SPDX-License-Identifier: GPL-2.0-or-later
       9   */
      10  
      11  #include "tests.h"
      12  #include "scno.h"
      13  
      14  #ifdef __NR_nanosleep
      15  
      16  # include <errno.h>
      17  # include <pthread.h>
      18  # include <signal.h>
      19  # include <stdio.h>
      20  # include <stdlib.h>
      21  # include <time.h>
      22  # include <unistd.h>
      23  
      24  # include "kernel_old_timespec.h"
      25  
      26  # ifndef PRINT_EXITED
      27  #  define PRINT_EXITED 1
      28  # endif
      29  # ifndef PRINT_SUPERSEDED
      30  #  define PRINT_SUPERSEDED 1
      31  # endif
      32  
      33  static pid_t leader;
      34  static pid_t tid;
      35  
      36  static void
      37  handler(int signo)
      38  {
      39  }
      40  
      41  static unsigned int sigsetsize;
      42  static long
      43  k_sigsuspend(const sigset_t *const set)
      44  {
      45  	return syscall(__NR_rt_sigsuspend, set, sigsetsize);
      46  }
      47  
      48  static pid_t
      49  k_gettid(void)
      50  {
      51  	return syscall(__NR_gettid);
      52  }
      53  
      54  static void
      55  get_sigsetsize(void)
      56  {
      57  	static const struct sigaction sa = { .sa_handler = handler };
      58  	if (sigaction(SIGUSR1, &sa, NULL))
      59  		perror_msg_and_fail("sigaction");
      60  
      61  	sigset_t mask;
      62  	sigemptyset(&mask);
      63  	sigaddset(&mask, SIGUSR1);
      64  	if (sigprocmask(SIG_BLOCK, &mask, NULL))
      65  		perror_msg_and_fail("sigprocmask");
      66  
      67  	raise(SIGUSR1);
      68  
      69  	sigemptyset(&mask);
      70  	for (sigsetsize = sizeof(mask) / sizeof(long);
      71  	     sigsetsize; sigsetsize >>= 1) {
      72  		long rc = k_sigsuspend(&mask);
      73  		if (!rc)
      74  			error_msg_and_fail("rt_sigsuspend");
      75  		if (EINTR == errno)
      76  			break;
      77  		printf("%-5d rt_sigsuspend(%p, %u) = %s\n",
      78  		       leader, &mask, sigsetsize, sprintrc(rc));
      79  	}
      80  	if (!sigsetsize)
      81  		perror_msg_and_fail("rt_sigsuspend");
      82  	printf("%-5d rt_sigsuspend([], %u) = ? ERESTARTNOHAND"
      83  	       " (To be restarted if no handler)\n", leader, sigsetsize);
      84  }
      85  
      86  enum {
      87  	ACTION_exit = 0,
      88  	ACTION_rt_sigsuspend,
      89  	ACTION_nanosleep,
      90  	NUMBER_OF_ACTIONS
      91  };
      92  
      93  static const unsigned int NUMBER_OF_ITERATIONS = 1;
      94  static unsigned int action;
      95  static int fds[2];
      96  
      97  static unsigned int
      98  arglen(char **args)
      99  {
     100  	char **p;
     101  
     102  	for (p = args; *p; ++p)
     103  		;
     104  
     105  	return p - args;
     106  }
     107  
     108  static void *
     109  thread(void *arg)
     110  {
     111  	tid = k_gettid();
     112  
     113  	static char buf[sizeof(action) * 3];
     114  	sprintf(buf, "%u", action + 1);
     115  
     116  	char **argv = arg;
     117  	argv[2] = buf;
     118  
     119  	if (read(fds[0], fds, sizeof(fds[0])))
     120  		perror_msg_and_fail("execve");
     121  
     122  	kernel_old_timespec_t ts = { .tv_nsec = 100000000 };
     123  	(void) syscall(__NR_clock_nanosleep, CLOCK_REALTIME, 0, &ts, NULL);
     124  
     125  	kernel_old_timespec_t ots = { .tv_nsec = 12345 };
     126  	printf("%-5d nanosleep({tv_sec=0, tv_nsec=%u}, NULL) = 0\n",
     127  	       tid, (unsigned int) ots.tv_nsec);
     128  
     129  	switch (action % NUMBER_OF_ACTIONS) {
     130  		case ACTION_exit:
     131  			printf("%-5d execve(\"%s\", [\"%s\", \"%s\", \"%s\"]"
     132  			       ", %p /* %u vars */ <pid changed to %u ...>\n",
     133  			       tid, argv[0], argv[0], argv[1], argv[2],
     134  			       environ, arglen(environ), leader);
     135  			break;
     136  		case ACTION_rt_sigsuspend:
     137  			printf("%-5d execve(\"%s\", [\"%s\", \"%s\", \"%s\"]"
     138  			       ", %p /* %u vars */ <unfinished ...>\n"
     139  			       "%-5d <... rt_sigsuspend resumed>) = ?\n",
     140  			       tid, argv[0], argv[0], argv[1], argv[2],
     141  			       environ, arglen(environ),
     142  			       leader);
     143  			break;
     144  		case ACTION_nanosleep:
     145  			printf("%-5d execve(\"%s\", [\"%s\", \"%s\", \"%s\"]"
     146  			       ", %p /* %u vars */ <unfinished ...>\n"
     147  			       "%-5d <... nanosleep resumed> <unfinished ...>)"
     148  			       " = ?\n",
     149  			       tid, argv[0], argv[0], argv[1], argv[2],
     150  			       environ, arglen(environ),
     151  			       leader);
     152  			break;
     153  	}
     154  
     155  # if PRINT_SUPERSEDED
     156  	printf("%-5d +++ superseded by execve in pid %u +++\n", leader, tid);
     157  # endif
     158  	printf("%-5d <... execve resumed>) = 0\n", leader);
     159  
     160  	(void) syscall(__NR_nanosleep, (unsigned long) &ots, 0UL);
     161  	execve(argv[0], argv, environ);
     162  	perror_msg_and_fail("execve");
     163  }
     164  
     165  int
     166  main(int ac, char **av)
     167  {
     168  	setvbuf(stdout, NULL, _IONBF, 0);
     169  	leader = getpid();
     170  
     171  	if (ac < 3) {
     172  		kernel_old_timespec_t ts = { .tv_nsec = 1 };
     173  		if (syscall(__NR_clock_nanosleep, CLOCK_REALTIME, 0, &ts, NULL))
     174  			perror_msg_and_skip("clock_nanosleep CLOCK_REALTIME");
     175  
     176  		get_sigsetsize();
     177  		static char buf[sizeof(sigsetsize) * 3];
     178  		sprintf(buf, "%u", sigsetsize);
     179  
     180  		char *argv[] = { av[0], buf, (char *) "0", NULL };
     181  		printf("%-5d execve(\"%s\", [\"%s\", \"%s\", \"%s\"]"
     182  		       ", %p /* %u vars */) = 0\n",
     183  		       leader, argv[0], argv[0], argv[1], argv[2],
     184  		       environ, arglen(environ));
     185  		execve(argv[0], argv, environ);
     186  		perror_msg_and_fail("execve");
     187  	}
     188  
     189  	sigsetsize = atoi(av[1]);
     190  	action = atoi(av[2]);
     191  
     192  	if (action >= NUMBER_OF_ACTIONS * NUMBER_OF_ITERATIONS) {
     193  # if PRINT_EXITED
     194  		printf("%-5d +++ exited with 0 +++\n", leader);
     195  # endif
     196  		return 0;
     197  	}
     198  
     199  	if (pipe(fds))
     200  		perror_msg_and_fail("pipe");
     201  
     202  	pthread_t t;
     203  	errno = pthread_create(&t, NULL, thread, av);
     204  	if (errno)
     205  		perror_msg_and_fail("pthread_create");
     206  
     207  	kernel_old_timespec_t ots = { .tv_sec = 123 };
     208  	sigset_t mask;
     209  	sigemptyset(&mask);
     210  
     211  	static char leader_str[sizeof(leader) * 3];
     212  	int leader_str_len =
     213  		snprintf(leader_str, sizeof(leader_str), "%-5d", leader);
     214  
     215  	switch (action % NUMBER_OF_ACTIONS) {
     216  		case ACTION_exit:
     217  			printf("%s exit(42)%*s= ?\n", leader_str,
     218  			       (int) sizeof(leader_str) - leader_str_len, " ");
     219  			close(fds[1]);
     220  			(void) syscall(__NR_exit, 42);
     221  			break;
     222  		case ACTION_rt_sigsuspend:
     223  			printf("%s rt_sigsuspend([], %u <unfinished ...>\n",
     224  			       leader_str, sigsetsize);
     225  			close(fds[1]);
     226  			(void) k_sigsuspend(&mask);
     227  			break;
     228  		case ACTION_nanosleep:
     229  			printf("%s nanosleep({tv_sec=%u, tv_nsec=0}"
     230  			       ",  <unfinished ...>\n",
     231  			       leader_str, (unsigned int) ots.tv_sec);
     232  			close(fds[1]);
     233  			(void) syscall(__NR_nanosleep,
     234  				       (unsigned long) &ots, 0UL);
     235  			break;
     236  	}
     237  
     238  	return 1;
     239  }
     240  
     241  #else
     242  
     243  SKIP_MAIN_UNDEFINED("__NR_nanosleep")
     244  
     245  #endif