(root)/
strace-6.5/
tests-m32/
pselect6-common.c
       1  /*
       2   * This file is part of pselect6* strace tests.
       3   *
       4   * Copyright (c) 2015-2021 Dmitry V. Levin <ldv@strace.io>
       5   * All rights reserved.
       6   *
       7   * SPDX-License-Identifier: GPL-2.0-or-later
       8   */
       9  
      10  /*
      11   * Based on test by Dr. David Alan Gilbert <dave@treblig.org>
      12   */
      13  
      14  #include "nsig.h"
      15  #include <assert.h>
      16  #include <stdio.h>
      17  #include <unistd.h>
      18  #include <sys/select.h>
      19  #include <sys/time.h>
      20  #include "kernel_timespec.h"
      21  
      22  static const char *errstr;
      23  
      24  static long
      25  pselect6(const unsigned int nfds,
      26  	 void *const rfds,
      27  	 void *const wfds,
      28  	 void *const efds,
      29  	 void *const timeout,
      30  	 void *const sigmask)
      31  {
      32  	static const kernel_ulong_t fill =
      33  		(kernel_ulong_t) 0xdefaced00000000ULL;
      34  	const kernel_ulong_t arg1 = nfds | fill;
      35  	const kernel_ulong_t arg2 = f8ill_ptr_to_kulong(rfds);
      36  	const kernel_ulong_t arg3 = f8ill_ptr_to_kulong(wfds);
      37  	const kernel_ulong_t arg4 = f8ill_ptr_to_kulong(efds);
      38  	const kernel_ulong_t arg5 = f8ill_ptr_to_kulong(timeout);
      39  	const kernel_ulong_t arg6 = f8ill_ptr_to_kulong(sigmask);
      40  	const long rc = syscall(SYSCALL_NR, arg1, arg2, arg3, arg4, arg5, arg6);
      41  	errstr = sprintrc(rc);
      42  	return rc;
      43  }
      44  
      45  static fd_set set[3][0x1000000 / sizeof(fd_set)];
      46  
      47  static void
      48  handler(int signo)
      49  {
      50  }
      51  
      52  struct sigset_argpack {
      53  	kernel_ulong_t p, size;
      54  };
      55  
      56  int main(int ac, char **av)
      57  {
      58  	static const pselect6_timespec_t ts_in = {
      59  		.tv_sec = 0xc0de1, .tv_nsec = 0xc0de2
      60  	};
      61  	pselect6_timespec_t *const ts = tail_memdup(&ts_in, sizeof(ts_in));
      62  
      63  	sigset_t mask;
      64  	sigemptyset(&mask);
      65  	sigaddset(&mask, SIGHUP);
      66  	sigaddset(&mask, SIGCHLD);
      67  
      68  	TAIL_ALLOC_OBJECT_CONST_PTR(struct sigset_argpack, sigmask_arg);
      69  	sigmask_arg->p = (uintptr_t) &mask;
      70  	sigmask_arg->size = NSIG_BYTES;
      71  
      72  	TAIL_ALLOC_OBJECT_CONST_PTR(struct sigset_argpack, nullmask_arg);
      73  	nullmask_arg->p = 0;
      74  	nullmask_arg->size = NSIG_BYTES;
      75  
      76  	int fds[2];
      77  	if (pipe(fds))
      78  		perror_msg_and_fail("pipe");
      79  
      80  	/*
      81  	 * Start with a nice simple pselect6.
      82  	 */
      83  	FD_SET(fds[0], set[0]);
      84  	FD_SET(fds[1], set[0]);
      85  	FD_SET(fds[0], set[1]);
      86  	FD_SET(fds[1], set[1]);
      87  	FD_SET(1, set[2]);
      88  	FD_SET(2, set[2]);
      89  	int rc = pselect6(fds[1] + 1, set[0], set[1], set[2], NULL, nullmask_arg);
      90  	if (rc < 0)
      91  		perror_msg_and_skip("pselect6");
      92  	assert(rc == 1);
      93  	printf("%s(%d, [%d %d], [%d %d], [1 2], NULL"
      94  	       ", {sigmask=NULL, sigsetsize=%u}) = 1 (out [%d])\n",
      95  	       SYSCALL_NAME, fds[1] + 1, fds[0], fds[1],
      96  	       fds[0], fds[1],
      97  	       NSIG_BYTES, fds[1]);
      98  
      99  	/*
     100  	 * Another simple one, with a timeout.
     101  	 */
     102  	FD_SET(1, set[1]);
     103  	FD_SET(2, set[1]);
     104  	FD_SET(fds[0], set[1]);
     105  	FD_SET(fds[1], set[1]);
     106  	assert(pselect6(fds[1] + 1, NULL, set[1], NULL, ts, NULL) == 3);
     107  	printf("%s(%d, NULL, [1 2 %d %d], NULL"
     108  	       ", {tv_sec=%lld, tv_nsec=%llu}, NULL) = 3 (out [1 2 %d]"
     109  	       ", left {tv_sec=%lld, tv_nsec=%llu})\n",
     110  	       SYSCALL_NAME,
     111  	       fds[1] + 1, fds[0], fds[1], (long long) ts_in.tv_sec,
     112  	       zero_extend_signed_to_ull(ts_in.tv_nsec),
     113  	       fds[1], (long long) ts->tv_sec,
     114  	       zero_extend_signed_to_ull(ts->tv_nsec));
     115  
     116  	/*
     117  	 * Now the crash case that trinity found, negative nfds
     118  	 * but with a pointer to a large chunk of valid memory.
     119  	 */
     120  	FD_ZERO(set[0]);
     121  	FD_SET(fds[1], set[0]);
     122  	assert(pselect6(-1, NULL, set[0], NULL, NULL, sigmask_arg) == -1);
     123  	printf("%s(-1, NULL, %p, NULL, NULL"
     124  	       ", {sigmask=[HUP CHLD], sigsetsize=%u}) = %s\n",
     125  	       SYSCALL_NAME, set[0], NSIG_BYTES, errstr);
     126  
     127  	/*
     128  	 * Another variant, with nfds exceeding FD_SETSIZE limit.
     129  	 */
     130  	FD_ZERO(set[0]);
     131  	FD_SET(fds[0], set[0]);
     132  	FD_ZERO(set[1]);
     133  	ts->tv_sec = 0;
     134  	ts->tv_nsec = 123;
     135  	assert(pselect6(FD_SETSIZE + 1, set[0], set[1], NULL, ts, sigmask_arg) == 0);
     136  	printf("%s(%d, [%d], [], NULL, {tv_sec=0, tv_nsec=123}"
     137  	       ", {sigmask=[HUP CHLD], sigsetsize=%u}) = 0 (Timeout)\n",
     138  	       SYSCALL_NAME, FD_SETSIZE + 1, fds[0], NSIG_BYTES);
     139  
     140  	/*
     141  	 * See how timeouts are decoded.
     142  	 */
     143  	ts->tv_sec = 0xdeadbeefU;
     144  	ts->tv_nsec = 0xfacefeedU;
     145  	assert(pselect6(0, NULL, NULL, NULL, ts, nullmask_arg) == -1);
     146  	printf("%s(0, NULL, NULL, NULL, {tv_sec=%lld, tv_nsec=%llu}"
     147  	       ", {sigmask=NULL, sigsetsize=%u}) = %s\n",
     148  	       SYSCALL_NAME, (long long) ts->tv_sec,
     149  	       zero_extend_signed_to_ull(ts->tv_nsec),
     150  	       NSIG_BYTES, errstr);
     151  
     152  	ts->tv_sec = (typeof(ts->tv_sec)) 0xcafef00ddeadbeefLL;
     153  	ts->tv_nsec = (typeof(ts->tv_nsec)) 0xbadc0dedfacefeedLL;
     154  	assert(pselect6(0, NULL, NULL, NULL, ts, nullmask_arg) == -1);
     155  	printf("%s(0, NULL, NULL, NULL, {tv_sec=%lld, tv_nsec=%llu}"
     156  	       ", {sigmask=NULL, sigsetsize=%u}) = %s\n",
     157  	       SYSCALL_NAME, (long long) ts->tv_sec,
     158  	       zero_extend_signed_to_ull(ts->tv_nsec),
     159  	       NSIG_BYTES, errstr);
     160  
     161  	const struct sigaction act = { .sa_handler = handler };
     162  	if (sigaction(SIGALRM, &act, NULL))
     163  		perror_msg_and_fail("sigaction SIGALRM");
     164  
     165  	const struct itimerval itv = { .it_value.tv_usec = 111111 };
     166  	if (setitimer(ITIMER_REAL, &itv, NULL))
     167  		perror_msg_and_fail("setitimer ITIMER_REAL");
     168  
     169  	ts->tv_sec = 0;
     170  	ts->tv_nsec = 222222222;
     171  	assert(pselect6(0, NULL, NULL, NULL, ts, sigmask_arg) == -1);
     172  	printf("%s(0, NULL, NULL, NULL, {tv_sec=0, tv_nsec=222222222}"
     173  	       ", {sigmask=[HUP CHLD], sigsetsize=%u})"
     174  	       " = ? ERESTARTNOHAND (To be restarted if no handler)\n",
     175  	       SYSCALL_NAME, NSIG_BYTES);
     176  	puts("--- SIGALRM {si_signo=SIGALRM, si_code=SI_KERNEL} ---");
     177  
     178  	puts("+++ exited with 0 +++");
     179  	return 0;
     180  }