(root)/
strace-6.5/
src/
ptrace_syscall_info.c
       1  /*
       2   * Copyright (c) 2018 Dmitry V. Levin <ldv@strace.io>
       3   * Copyright (c) 2018-2021 The strace developers.
       4   * All rights reserved.
       5   *
       6   * SPDX-License-Identifier: LGPL-2.1-or-later
       7   */
       8  
       9  #include "defs.h"
      10  #include "kill_save_errno.h"
      11  #include "ptrace.h"
      12  #include "ptrace_syscall_info.h"
      13  #include "scno.h"
      14  
      15  #include <signal.h>
      16  #include <sys/wait.h>
      17  
      18  #include "xlat/ptrace_syscall_info_op.h"
      19  
      20  bool ptrace_get_syscall_info_supported;
      21  
      22  #define FAIL	do { ptrace_stop = -1U; goto done; } while (0)
      23  
      24  #ifdef HAVE_FORK
      25  static int
      26  kill_tracee(pid_t pid)
      27  {
      28  	return kill_save_errno(pid, SIGKILL);
      29  }
      30  
      31  static const unsigned int expected_none_size =
      32  	offsetof(struct_ptrace_syscall_info, entry);
      33  static const unsigned int expected_entry_size =
      34  	offsetofend(struct_ptrace_syscall_info, entry.args);
      35  #endif /* HAVE_FORK */
      36  static const unsigned int expected_exit_size =
      37  	offsetofend(struct_ptrace_syscall_info, exit.is_error);
      38  static const unsigned int expected_seccomp_size =
      39  	offsetofend(struct_ptrace_syscall_info, seccomp.ret_data);
      40  
      41  /*
      42   * Test that PTRACE_GET_SYSCALL_INFO API is supported by the kernel, and
      43   * that the semantics implemented in the kernel matches our expectations.
      44   */
      45  bool
      46  test_ptrace_get_syscall_info(void)
      47  {
      48  	/*
      49  	 * NOMMU provides no forks necessary for PTRACE_GET_SYSCALL_INFO test,
      50  	 * leave the default unchanged.
      51  	 */
      52  #ifdef HAVE_FORK
      53  	static const unsigned long args[][7] = {
      54  		/* a sequence of architecture-agnostic syscalls */
      55  		{
      56  			__NR_chdir,
      57  			(unsigned long) "",
      58  			0xbad1fed1,
      59  			0xbad2fed2,
      60  			0xbad3fed3,
      61  			0xbad4fed4,
      62  			0xbad5fed5
      63  		},
      64  		{
      65  			__NR_gettid,
      66  			0xcaf0bea0,
      67  			0xcaf1bea1,
      68  			0xcaf2bea2,
      69  			0xcaf3bea3,
      70  			0xcaf4bea4,
      71  			0xcaf5bea5
      72  		},
      73  		{
      74  			__NR_exit_group,
      75  			0,
      76  			0xfac1c0d1,
      77  			0xfac2c0d2,
      78  			0xfac3c0d3,
      79  			0xfac4c0d4,
      80  			0xfac5c0d5
      81  		}
      82  	};
      83  	const unsigned long *exp_args;
      84  
      85  # if SIZEOF_KERNEL_LONG_T > SIZEOF_LONG
      86  #  define CAST (unsigned long)
      87  # else
      88  #  define CAST
      89  # endif
      90  
      91  	int pid = fork();
      92  	if (pid < 0)
      93  		perror_func_msg_and_die("fork");
      94  
      95  	if (pid == 0) {
      96  		/* get the pid before PTRACE_TRACEME */
      97  		pid = getpid();
      98  		if (ptrace(PTRACE_TRACEME, 0L, 0L, 0L) < 0) {
      99  			/* exit with a nonzero exit status */
     100  			perror_func_msg_and_die("PTRACE_TRACEME");
     101  		}
     102  		kill(pid, SIGSTOP);
     103  		for (unsigned int i = 0; i < ARRAY_SIZE(args); ++i) {
     104  			syscall(args[i][0],
     105  				args[i][1], args[i][2], args[i][3],
     106  				args[i][4], args[i][5], args[i][6]);
     107  		}
     108  		/* unreachable */
     109  		_exit(1);
     110  	}
     111  
     112  	const struct {
     113  		unsigned int is_error;
     114  		int rval;
     115  	} *exp_param, exit_param[] = {
     116  		{ 1, -ENOENT },	/* chdir */
     117  		{ 0, pid }	/* gettid */
     118  	};
     119  
     120  	unsigned int ptrace_stop;
     121  
     122  	for (ptrace_stop = 0; ; ++ptrace_stop) {
     123  		struct_ptrace_syscall_info info = {
     124  			.op = 0xff	/* invalid PTRACE_SYSCALL_INFO_* op */
     125  		};
     126  		const size_t size = sizeof(info);
     127  		int status;
     128  		long rc = waitpid(pid, &status, 0);
     129  		if (rc != pid) {
     130  			/* cannot happen */
     131  			kill_tracee(pid);
     132  			perror_func_msg_and_die("#%d: unexpected wait result"
     133  						" %ld", ptrace_stop, rc);
     134  		}
     135  		if (WIFEXITED(status)) {
     136  			/* tracee is no more */
     137  			pid = 0;
     138  			if (WEXITSTATUS(status) == 0)
     139  				break;
     140  			debug_func_msg("#%d: unexpected exit status %u",
     141  				       ptrace_stop, WEXITSTATUS(status));
     142  			FAIL;
     143  		}
     144  		if (WIFSIGNALED(status)) {
     145  			/* tracee is no more */
     146  			pid = 0;
     147  			debug_func_msg("#%d: unexpected signal %u",
     148  				       ptrace_stop, WTERMSIG(status));
     149  			FAIL;
     150  		}
     151  		if (!WIFSTOPPED(status)) {
     152  			/* cannot happen */
     153  			kill_tracee(pid);
     154  			error_func_msg_and_die("#%d: unexpected wait status"
     155  					       " %#x", ptrace_stop, status);
     156  		}
     157  
     158  		switch (WSTOPSIG(status)) {
     159  		case SIGSTOP:
     160  			if (ptrace_stop) {
     161  				debug_func_msg("#%d: unexpected signal stop",
     162  					       ptrace_stop);
     163  				FAIL;
     164  			}
     165  			if (ptrace(PTRACE_SETOPTIONS, pid, 0L,
     166  				   PTRACE_O_TRACESYSGOOD) < 0) {
     167  				/* cannot happen */
     168  				kill_tracee(pid);
     169  				perror_func_msg_and_die("PTRACE_SETOPTIONS");
     170  			}
     171  			rc = ptrace(PTRACE_GET_SYSCALL_INFO, pid,
     172  				    (void *) size, &info);
     173  			if (rc < 0) {
     174  				debug_perror_msg("PTRACE_GET_SYSCALL_INFO");
     175  				FAIL;
     176  			}
     177  			if (rc < (long) expected_none_size
     178  			    || info.op != PTRACE_SYSCALL_INFO_NONE
     179  			    || !info.arch
     180  			    || !info.instruction_pointer
     181  			    || !info.stack_pointer) {
     182  				debug_func_msg("signal stop mismatch");
     183  				FAIL;
     184  			}
     185  			break;
     186  
     187  		case SIGTRAP | 0x80:
     188  			rc = ptrace(PTRACE_GET_SYSCALL_INFO, pid,
     189  				    (void *) size, &info);
     190  			if (rc < 0) {
     191  				debug_perror_msg("#%d: PTRACE_GET_SYSCALL_INFO",
     192  						 ptrace_stop);
     193  				FAIL;
     194  			}
     195  			switch (ptrace_stop) {
     196  			case 1: /* entering chdir */
     197  			case 3: /* entering gettid */
     198  			case 5: /* entering exit_group */
     199  				exp_args = args[ptrace_stop / 2];
     200  				if (rc < (long) expected_entry_size
     201  				    || info.op != PTRACE_SYSCALL_INFO_ENTRY
     202  				    || !info.arch
     203  				    || !info.instruction_pointer
     204  				    || !info.stack_pointer
     205  				    || (info.entry.nr != exp_args[0])
     206  				    || (CAST info.entry.args[0] != exp_args[1])
     207  				    || (CAST info.entry.args[1] != exp_args[2])
     208  				    || (CAST info.entry.args[2] != exp_args[3])
     209  				    || (CAST info.entry.args[3] != exp_args[4])
     210  				    || (CAST info.entry.args[4] != exp_args[5])
     211  				    || (CAST info.entry.args[5] != exp_args[6])) {
     212  					debug_func_msg("#%d: entry stop"
     213  						       " mismatch",
     214  						       ptrace_stop);
     215  					FAIL;
     216  				}
     217  				break;
     218  			case 2: /* exiting chdir */
     219  			case 4: /* exiting gettid */
     220  				exp_param = &exit_param[ptrace_stop / 2 - 1];
     221  				if (rc < (long) expected_exit_size
     222  				    || info.op != PTRACE_SYSCALL_INFO_EXIT
     223  				    || !info.arch
     224  				    || !info.instruction_pointer
     225  				    || !info.stack_pointer
     226  				    || info.exit.is_error != exp_param->is_error
     227  				    || info.exit.rval != exp_param->rval) {
     228  					debug_func_msg("#%d: exit stop"
     229  						       " mismatch",
     230  						       ptrace_stop);
     231  					FAIL;
     232  				}
     233  				break;
     234  			default:
     235  				debug_func_msg("#%d: unexpected syscall stop",
     236  					       ptrace_stop);
     237  				FAIL;
     238  			}
     239  			break;
     240  
     241  		default:
     242  			debug_func_msg("#%d: unexpected stop signal %#x",
     243  				       ptrace_stop, WSTOPSIG(status));
     244  			FAIL;
     245  		}
     246  
     247  		if (ptrace(PTRACE_SYSCALL, pid, 0L, 0L) < 0) {
     248  			/* cannot happen */
     249  			kill_tracee(pid);
     250  			perror_func_msg_and_die("PTRACE_SYSCALL");
     251  		}
     252  	}
     253  
     254  done:
     255  	if (pid) {
     256  		kill_tracee(pid);
     257  		waitpid(pid, NULL, 0);
     258  		ptrace_stop = -1U;
     259  	}
     260  
     261  	ptrace_get_syscall_info_supported =
     262  		ptrace_stop == ARRAY_SIZE(args) * 2;
     263  
     264  	if (ptrace_get_syscall_info_supported)
     265  		debug_msg("PTRACE_GET_SYSCALL_INFO works");
     266  	else
     267  		debug_msg("PTRACE_GET_SYSCALL_INFO does not work");
     268  #endif /* HAVE_FORK */
     269  
     270  	return ptrace_get_syscall_info_supported;
     271  }
     272  
     273  static void
     274  print_psi_entry(const typeof_field(struct_ptrace_syscall_info, entry) *const p,
     275  		const kernel_ulong_t fetch_size, struct tcb *const tcp,
     276  		unsigned int arch)
     277  {
     278  	tprint_struct_begin();
     279  	PRINT_FIELD_SYSCALL_NAME(*p, nr, arch);
     280  	const kernel_ulong_t nargs =
     281  		(fetch_size - offsetof(struct_ptrace_syscall_info, entry.args))
     282  		/ sizeof(p->args[0]);
     283  	if (nargs) {
     284  		tprint_struct_next();
     285  		PRINT_FIELD_ARRAY_UPTO(*p, args, nargs, tcp,
     286  				       print_xint_array_member);
     287  	}
     288  	tprint_struct_end();
     289  }
     290  
     291  static void
     292  print_psi_seccomp(const typeof_field(struct_ptrace_syscall_info, seccomp) *const p,
     293  		const kernel_ulong_t fetch_size, struct tcb *const tcp,
     294  		unsigned int arch)
     295  {
     296  	tprint_struct_begin();
     297  	PRINT_FIELD_SYSCALL_NAME(*p, nr, arch);
     298  	const kernel_ulong_t nargs =
     299  		(fetch_size - offsetof(struct_ptrace_syscall_info, seccomp.args))
     300  		/ sizeof(p->args[0]);
     301  	if (nargs) {
     302  		tprint_struct_next();
     303  		PRINT_FIELD_ARRAY_UPTO(*p, args, nargs, tcp,
     304  				       print_xint_array_member);
     305  	}
     306  	if (fetch_size >= expected_seccomp_size) {
     307  		tprint_struct_next();
     308  		PRINT_FIELD_U(*p, ret_data);
     309  	}
     310  	tprint_struct_end();
     311  }
     312  
     313  static void
     314  print_psi_exit(const typeof_field(struct_ptrace_syscall_info, exit) *const p,
     315  	       const kernel_ulong_t fetch_size, struct tcb *const tcp)
     316  {
     317  	tprint_struct_begin();
     318  	if (fetch_size >= expected_exit_size && p->is_error) {
     319  		PRINT_FIELD_ERR_D(*p, rval);
     320  	} else {
     321  		PRINT_FIELD_D(*p, rval);
     322  	}
     323  	if (fetch_size >= expected_exit_size) {
     324  		tprint_struct_next();
     325  		PRINT_FIELD_U(*p, is_error);
     326  	}
     327  	tprint_struct_end();
     328  }
     329  
     330  void
     331  print_ptrace_syscall_info(struct tcb *tcp, kernel_ulong_t addr,
     332  			  kernel_ulong_t user_len)
     333  {
     334  	struct_ptrace_syscall_info info;
     335  	kernel_ulong_t kernel_len = tcp->u_rval;
     336  	kernel_ulong_t ret_len = MIN(user_len, kernel_len);
     337  	kernel_ulong_t fetch_size = MIN(ret_len, expected_seccomp_size);
     338  
     339  	if (!fetch_size || !tfetch_mem(tcp, addr, fetch_size, &info)) {
     340  		printaddr(addr);
     341  		return;
     342  	}
     343  
     344  	tprint_struct_begin();
     345  	PRINT_FIELD_XVAL(info, op, ptrace_syscall_info_op,
     346  			 "PTRACE_SYSCALL_INFO_???");
     347  	if (fetch_size < offsetofend(struct_ptrace_syscall_info, arch))
     348  		goto printed;
     349  	tprint_struct_next();
     350  	PRINT_FIELD_XVAL(info, arch, audit_arch, "AUDIT_ARCH_???");
     351  
     352  	if (fetch_size < offsetofend(struct_ptrace_syscall_info,
     353  				     instruction_pointer))
     354  		goto printed;
     355  	tprint_struct_next();
     356  	PRINT_FIELD_ADDR64(info, instruction_pointer);
     357  
     358  	if (fetch_size < offsetofend(struct_ptrace_syscall_info, stack_pointer))
     359  		goto printed;
     360  	tprint_struct_next();
     361  	PRINT_FIELD_ADDR64(info, stack_pointer);
     362  
     363  	if (fetch_size < offsetofend(struct_ptrace_syscall_info, entry.nr))
     364  		goto printed;
     365  
     366  	switch(info.op) {
     367  		case PTRACE_SYSCALL_INFO_ENTRY:
     368  			tprint_struct_next();
     369  			PRINT_FIELD_OBJ_PTR(info, entry,
     370  					    print_psi_entry, fetch_size, tcp,
     371  					    info.arch);
     372  			break;
     373  		case PTRACE_SYSCALL_INFO_SECCOMP:
     374  			tprint_struct_next();
     375  			PRINT_FIELD_OBJ_PTR(info, seccomp,
     376  					    print_psi_seccomp, fetch_size, tcp,
     377  					    info.arch);
     378  			break;
     379  		case PTRACE_SYSCALL_INFO_EXIT:
     380  			tprint_struct_next();
     381  			PRINT_FIELD_OBJ_PTR(info, exit,
     382  					    print_psi_exit, fetch_size, tcp);
     383  			break;
     384  	}
     385  
     386  printed:
     387  	tprint_struct_end();
     388  }