(root)/
strace-6.5/
src/
disable_ptrace_request.c
       1  /*
       2   * A helper that executes the specified program
       3   * with the ptrace request disabled.
       4   *
       5   * Copyright (c) 2015-2021 The strace developers.
       6   * All rights reserved.
       7   *
       8   * SPDX-License-Identifier: GPL-2.0-or-later
       9   */
      10  
      11  #include "defs.h"
      12  #include "ptrace.h"
      13  #include "scno.h"
      14  #include <signal.h>
      15  #include <sys/prctl.h>
      16  #include <sys/wait.h>
      17  #include <linux/filter.h>
      18  #include <linux/seccomp.h>
      19  
      20  #ifndef HAVE_PROGRAM_INVOCATION_NAME
      21  char *program_invocation_name;
      22  #endif
      23  
      24  void ATTRIBUTE_NORETURN
      25  die(void)
      26  {
      27  	exit(1);
      28  }
      29  
      30  static void
      31  init(int argc, char **argv)
      32  {
      33  	if (!program_invocation_name || !*program_invocation_name) {
      34  		static char name[] = DEFAULT_PROGRAM_INVOCATION_NAME;
      35  		program_invocation_name =
      36  			(argc > 0 && argv[0] && *argv[0]) ? argv[0] : name;
      37  	}
      38  }
      39  
      40  #if defined DISABLE_PTRACE_REQUEST \
      41   && defined PR_SET_NO_NEW_PRIVS \
      42   && defined PR_SET_SECCOMP \
      43   && defined BPF_JUMP \
      44   && defined BPF_STMT \
      45   && defined HAVE_FORK
      46  
      47  static unsigned int
      48  get_arch(void)
      49  {
      50  	pid_t pid = fork();
      51  	if (pid < 0)
      52  		perror_msg_and_die("fork");
      53  
      54  	if (pid == 0) {
      55  		/* get the pid before PTRACE_TRACEME */
      56  		pid = getpid();
      57  		if (ptrace(PTRACE_TRACEME, 0, 0, 0))
      58  			perror_msg_and_die("PTRACE_TRACEME");
      59  		kill(pid, SIGSTOP);
      60  		/* unreachable */
      61  		_exit(1);
      62  	}
      63  
      64  	int status = 0;
      65  	if (waitpid(pid, &status, 0) != pid ||
      66  	    !WIFSTOPPED(status) ||
      67  	    WSTOPSIG(status) != SIGSTOP) {
      68  		/* cannot happen */
      69  		perror_msg_and_die("waitpid: status = %d", status);
      70  	}
      71  
      72  	static const unsigned int size =
      73  		offsetof(struct_ptrace_syscall_info, entry);
      74  	struct_ptrace_syscall_info psi = { .arch = 0 };
      75  
      76  	long rc = ptrace(PTRACE_GET_SYSCALL_INFO, pid, size, &psi);
      77  
      78  	int saved_errno = errno;
      79  	(void) kill(pid, SIGKILL);
      80  	(void) waitpid(pid, NULL, 0);
      81  	errno = saved_errno;
      82  
      83  	/*
      84  	 * Skip if PTRACE_GET_SYSCALL_INFO is not available
      85  	 * or behaves in an unexpected way.
      86  	 */
      87  	if (rc < (long) size ||
      88  	    psi.op != PTRACE_SYSCALL_INFO_NONE ||
      89  	    psi.arch == 0) {
      90  		perror_msg_and_die("PTRACE_GET_SYSCALL_INFO");
      91  	}
      92  
      93  	return psi.arch;
      94  }
      95  
      96  int
      97  main(int argc, char **argv)
      98  {
      99  	init(argc, argv);
     100  
     101  	if (argc < 2)
     102  		error_msg_and_die("Insufficient arguments");
     103  
     104  	if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0))
     105  		perror_msg_and_die("PR_SET_NO_NEW_PRIVS");
     106  
     107  	struct sock_filter filter[] = {
     108  		/* load the architecture */
     109  		BPF_STMT(BPF_LD | BPF_W | BPF_ABS,
     110  			 offsetof(struct seccomp_data, arch)),
     111  		/* jump to "allow" if the architecture does not match */
     112  		BPF_JUMP(BPF_JMP | BPF_K | BPF_JEQ, get_arch(), 0, 5),
     113  		/* load the syscall number */
     114  		BPF_STMT(BPF_LD | BPF_W | BPF_ABS, \
     115  			 offsetof(struct seccomp_data, nr)),
     116  		/* jump to "allow" if it is not equal to __NR_ptrace */
     117  		BPF_JUMP(BPF_JMP | BPF_K | BPF_JEQ, __NR_ptrace, 0, 3),
     118  		/* load the 1st syscall argument */
     119  		BPF_STMT(BPF_LD | BPF_W | BPF_ABS, \
     120  			 offsetof(struct seccomp_data, args[0])
     121  			 + (is_bigendian ? sizeof(uint32_t) : 0)),
     122  		/* jump to "allow" if it is not equal to DISABLE_PTRACE_REQUEST */
     123  		BPF_JUMP(BPF_JMP | BPF_K | BPF_JEQ, DISABLE_PTRACE_REQUEST, 0, 1),
     124  		/* reject */
     125  		BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ERRNO | EIO),
     126  		/* allow */
     127  		BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW)
     128  	};
     129  
     130  	const struct sock_fprog prog = {
     131  		.len = ARRAY_SIZE(filter),
     132  		.filter = filter,
     133  	};
     134  
     135  	if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog))
     136  		perror_msg_and_die("PR_SET_SECCOMP");
     137  
     138  	(void) execvp(argv[1], argv + 1);
     139  	perror_msg_and_die("execvp: %s", argv[1]);
     140  }
     141  
     142  #else
     143  
     144  int
     145  main(int argc, char **argv)
     146  {
     147  	init(argc, argv);
     148  	error_msg_and_die("Operation not supported");
     149  }
     150  
     151  #endif