Home | History | Annotate | Line # | Download | only in nat
linux-ptrace.c revision 1.9
      1 /* Linux-specific ptrace manipulation routines.
      2    Copyright (C) 2012-2024 Free Software Foundation, Inc.
      3 
      4    This file is part of GDB.
      5 
      6    This program is free software; you can redistribute it and/or modify
      7    it under the terms of the GNU General Public License as published by
      8    the Free Software Foundation; either version 3 of the License, or
      9    (at your option) any later version.
     10 
     11    This program is distributed in the hope that it will be useful,
     12    but WITHOUT ANY WARRANTY; without even the implied warranty of
     13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14    GNU General Public License for more details.
     15 
     16    You should have received a copy of the GNU General Public License
     17    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
     18 
     19 #include "linux-ptrace.h"
     20 #include "linux-procfs.h"
     21 #include "linux-waitpid.h"
     22 #ifdef HAVE_SYS_PROCFS_H
     23 #include <sys/procfs.h>
     24 #endif
     25 
     26 /* Stores the ptrace options supported by the running kernel.
     27    A value of -1 means we did not check for features yet.  A value
     28    of 0 means there are no supported features.  */
     29 static int supported_ptrace_options = -1;
     30 
     31 /* Find all possible reasons we could fail to attach PID and return these
     32    as a string.  An empty string is returned if we didn't find any reason.  */
     33 
     34 std::string
     35 linux_ptrace_attach_fail_reason (pid_t pid)
     36 {
     37   pid_t tracerpid = linux_proc_get_tracerpid_nowarn (pid);
     38   std::string result;
     39 
     40   if (tracerpid > 0)
     41     string_appendf (result,
     42 		    _("process %d is already traced by process %d"),
     43 		    (int) pid, (int) tracerpid);
     44 
     45   if (linux_proc_pid_is_zombie_nowarn (pid))
     46     string_appendf (result,
     47 		    _("process %d is a zombie - the process has already "
     48 		      "terminated"),
     49 		    (int) pid);
     50 
     51   return result;
     52 }
     53 
     54 /* See linux-ptrace.h.  */
     55 
     56 std::string
     57 linux_ptrace_attach_fail_reason_string (ptid_t ptid, int err)
     58 {
     59   long lwpid = ptid.lwp ();
     60   std::string reason = linux_ptrace_attach_fail_reason (lwpid);
     61 
     62   if (!reason.empty ())
     63     return string_printf ("%s (%d), %s", safe_strerror (err), err,
     64 			  reason.c_str ());
     65   else
     66     return string_printf ("%s (%d)", safe_strerror (err), err);
     67 }
     68 
     69 #if defined __i386__ || defined __x86_64__
     70 
     71 /* Address of the 'ret' instruction in asm code block below.  */
     72 extern "C" void linux_ptrace_test_ret_to_nx_instr (void);
     73 
     74 #include <sys/reg.h>
     75 #include <sys/mman.h>
     76 #include <signal.h>
     77 
     78 #endif /* defined __i386__ || defined __x86_64__ */
     79 
     80 /* Kill CHILD.  WHO is used to report warnings.  */
     81 
     82 static void
     83 kill_child (pid_t child, const char *who)
     84 {
     85   pid_t got_pid;
     86   int kill_status;
     87 
     88   if (kill (child, SIGKILL) != 0)
     89     {
     90       warning (_("%s: failed to kill child pid %ld %s"),
     91 	       who, (long) child, safe_strerror (errno));
     92       return;
     93     }
     94 
     95   errno = 0;
     96   got_pid = my_waitpid (child, &kill_status, 0);
     97   if (got_pid != child)
     98     {
     99       warning (_("%s: "
    100 		 "kill waitpid returned %ld: %s"),
    101 	       who, (long) got_pid, safe_strerror (errno));
    102       return;
    103     }
    104   if (!WIFSIGNALED (kill_status))
    105     {
    106       warning (_("%s: "
    107 		 "kill status %d is not WIFSIGNALED!"),
    108 	       who, kill_status);
    109       return;
    110     }
    111 }
    112 
    113 /* Test broken off-trunk Linux kernel patchset for NX support on i386.  It was
    114    removed in Fedora kernel 88fa1f0332d188795ed73d7ac2b1564e11a0b4cd.
    115 
    116    Test also x86_64 arch for PaX support.  */
    117 
    118 static void
    119 linux_ptrace_test_ret_to_nx (void)
    120 {
    121 #if defined __i386__ || defined __x86_64__
    122   pid_t child, got_pid;
    123   gdb_byte *return_address, *pc;
    124   long l;
    125   int status;
    126   elf_gregset_t regs;
    127 
    128   return_address
    129     = (gdb_byte *) mmap (NULL, 2, PROT_READ | PROT_WRITE,
    130 			 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
    131   if (return_address == MAP_FAILED)
    132     {
    133       warning (_("linux_ptrace_test_ret_to_nx: Cannot mmap: %s"),
    134 	       safe_strerror (errno));
    135       return;
    136     }
    137 
    138   /* Put there 'int3'.  */
    139   *return_address = 0xcc;
    140 
    141   child = fork ();
    142   switch (child)
    143     {
    144     case -1:
    145       warning (_("linux_ptrace_test_ret_to_nx: Cannot fork: %s"),
    146 	       safe_strerror (errno));
    147       return;
    148 
    149     case 0:
    150       l = ptrace (PTRACE_TRACEME, 0, (PTRACE_TYPE_ARG3) NULL,
    151 		  (PTRACE_TYPE_ARG4) NULL);
    152       if (l != 0)
    153 	warning (_("linux_ptrace_test_ret_to_nx: Cannot PTRACE_TRACEME: %s"),
    154 		 safe_strerror (errno));
    155       else
    156 	{
    157 #if defined __i386__
    158 	  asm volatile ("pushl %0;"
    159 			".globl linux_ptrace_test_ret_to_nx_instr;"
    160 			"linux_ptrace_test_ret_to_nx_instr:"
    161 			"ret"
    162 			: : "r" (return_address) : "memory");
    163 #elif defined __x86_64__
    164 	  asm volatile ("pushq %0;"
    165 			".globl linux_ptrace_test_ret_to_nx_instr;"
    166 			"linux_ptrace_test_ret_to_nx_instr:"
    167 			"ret"
    168 			: : "r" ((uint64_t) (uintptr_t) return_address)
    169 			: "memory");
    170 #else
    171 # error "!__i386__ && !__x86_64__"
    172 #endif
    173 	  gdb_assert_not_reached ("asm block did not terminate");
    174 	}
    175 
    176       _exit (1);
    177     }
    178 
    179   errno = 0;
    180   got_pid = waitpid (child, &status, 0);
    181   if (got_pid != child)
    182     {
    183       warning (_("linux_ptrace_test_ret_to_nx: waitpid returned %ld: %s"),
    184 	       (long) got_pid, safe_strerror (errno));
    185       return;
    186     }
    187 
    188   if (WIFSIGNALED (status))
    189     {
    190       if (WTERMSIG (status) != SIGKILL)
    191 	warning (_("linux_ptrace_test_ret_to_nx: WTERMSIG %d is not SIGKILL!"),
    192 		 (int) WTERMSIG (status));
    193       else
    194 	warning (_("Cannot call inferior functions, Linux kernel PaX "
    195 		   "protection forbids return to non-executable pages!"));
    196       return;
    197     }
    198 
    199   if (!WIFSTOPPED (status))
    200     {
    201       warning (_("linux_ptrace_test_ret_to_nx: status %d is not WIFSTOPPED!"),
    202 	       status);
    203       kill_child (child, "linux_ptrace_test_ret_to_nx");
    204       return;
    205     }
    206 
    207   /* We may get SIGSEGV due to missing PROT_EXEC of the return_address.  */
    208   if (WSTOPSIG (status) != SIGTRAP && WSTOPSIG (status) != SIGSEGV)
    209     {
    210       warning (_("linux_ptrace_test_ret_to_nx: "
    211 		 "WSTOPSIG %d is neither SIGTRAP nor SIGSEGV!"),
    212 	       (int) WSTOPSIG (status));
    213       kill_child (child, "linux_ptrace_test_ret_to_nx");
    214       return;
    215     }
    216 
    217   if (ptrace (PTRACE_GETREGS, child, (PTRACE_TYPE_ARG3) 0,
    218 	      (PTRACE_TYPE_ARG4) &regs) < 0)
    219     {
    220       warning (_("linux_ptrace_test_ret_to_nx: Cannot PTRACE_GETREGS: %s"),
    221 	       safe_strerror (errno));
    222     }
    223 #if defined __i386__
    224   pc = (gdb_byte *) (uintptr_t) regs[EIP];
    225 #elif defined __x86_64__
    226   pc = (gdb_byte *) (uintptr_t) regs[RIP];
    227 #else
    228 # error "!__i386__ && !__x86_64__"
    229 #endif
    230 
    231   kill_child (child, "linux_ptrace_test_ret_to_nx");
    232 
    233   /* + 1 is there as x86* stops after the 'int3' instruction.  */
    234   if (WSTOPSIG (status) == SIGTRAP && pc == return_address + 1)
    235     {
    236       /* PASS */
    237       return;
    238     }
    239 
    240   /* We may get SIGSEGV due to missing PROT_EXEC of the RETURN_ADDRESS page.  */
    241   if (WSTOPSIG (status) == SIGSEGV && pc == return_address)
    242     {
    243       /* PASS */
    244       return;
    245     }
    246 
    247   if ((void (*) (void)) pc != &linux_ptrace_test_ret_to_nx_instr)
    248     warning (_("linux_ptrace_test_ret_to_nx: PC %p is neither near return "
    249 	       "address %p nor is the return instruction %p!"),
    250 	     pc, return_address, &linux_ptrace_test_ret_to_nx_instr);
    251   else
    252     warning (_("Cannot call inferior functions on this system - "
    253 	       "Linux kernel with broken i386 NX (non-executable pages) "
    254 	       "support detected!"));
    255 #endif /* defined __i386__ || defined __x86_64__ */
    256 }
    257 
    258 /* Helper function to fork a process and make the child process call
    259    the function FUNCTION, passing CHILD_STACK as parameter.
    260 
    261    For MMU-less targets, clone is used instead of fork, and
    262    CHILD_STACK is used as stack space for the cloned child.  If NULL,
    263    stack space is allocated via malloc (and subsequently passed to
    264    FUNCTION).  For MMU targets, CHILD_STACK is ignored.  */
    265 
    266 static int
    267 linux_fork_to_function (gdb_byte *child_stack, int (*function) (void *))
    268 {
    269   int child_pid;
    270 
    271   /* Sanity check the function pointer.  */
    272   gdb_assert (function != NULL);
    273 
    274 #if defined(__UCLIBC__) && defined(HAS_NOMMU)
    275 #define STACK_SIZE 4096
    276 
    277     if (child_stack == NULL)
    278       child_stack = (gdb_byte *) xmalloc (STACK_SIZE * 4);
    279 
    280     /* Use CLONE_VM instead of fork, to support uClinux (no MMU).  */
    281 #ifdef __ia64__
    282       child_pid = __clone2 (function, child_stack, STACK_SIZE,
    283 			    CLONE_VM | SIGCHLD, child_stack + STACK_SIZE * 2);
    284 #else /* !__ia64__ */
    285       child_pid = clone (function, child_stack + STACK_SIZE,
    286 			 CLONE_VM | SIGCHLD, child_stack + STACK_SIZE * 2);
    287 #endif /* !__ia64__ */
    288 #else /* !defined(__UCLIBC) && defined(HAS_NOMMU) */
    289   child_pid = fork ();
    290 
    291   if (child_pid == 0)
    292     function (NULL);
    293 #endif /* defined(__UCLIBC) && defined(HAS_NOMMU) */
    294 
    295   if (child_pid == -1)
    296     perror_with_name (("fork"));
    297 
    298   return child_pid;
    299 }
    300 
    301 /* A helper function for linux_check_ptrace_features, called after
    302    the parent process forks a child.  The child allows itself to
    303    be traced by its parent.  */
    304 
    305 static int
    306 linux_child_function (void *child_stack)
    307 {
    308   ptrace (PTRACE_TRACEME, 0, (PTRACE_TYPE_ARG3) 0, (PTRACE_TYPE_ARG4) 0);
    309   kill (getpid (), SIGSTOP);
    310 
    311   /* This code is only reachable by the child (grandchild's parent)
    312      process.  */
    313   _exit (0);
    314 }
    315 
    316 static void linux_test_for_exitkill (int child_pid);
    317 
    318 /* Determine ptrace features available on this target.  */
    319 
    320 void
    321 linux_check_ptrace_features (void)
    322 {
    323   int child_pid, ret, status;
    324 
    325   /* Initialize the options.  We consider that these options are always
    326      supported.  */
    327   supported_ptrace_options
    328     = (PTRACE_O_TRACESYSGOOD
    329        | PTRACE_O_TRACECLONE
    330        | PTRACE_O_TRACEFORK
    331        | PTRACE_O_TRACEVFORK
    332        | PTRACE_O_TRACEVFORKDONE
    333        | PTRACE_O_TRACEEXEC);
    334 
    335   /* Fork a child so we can do some testing.  The child will call
    336      linux_child_function and will get traced.  The child will
    337      eventually fork a grandchild so we can test fork event
    338      reporting.  */
    339   child_pid = linux_fork_to_function (NULL, linux_child_function);
    340 
    341   ret = my_waitpid (child_pid, &status, 0);
    342   if (ret == -1)
    343     perror_with_name (("waitpid"));
    344   else if (ret != child_pid)
    345     error (_("linux_check_ptrace_features: waitpid: unexpected result %d."),
    346 	   ret);
    347   if (! WIFSTOPPED (status))
    348     error (_("linux_check_ptrace_features: waitpid: unexpected status %d."),
    349 	   status);
    350 
    351   linux_test_for_exitkill (child_pid);
    352 
    353   /* Kill child_pid.  */
    354   kill_child (child_pid, "linux_check_ptrace_features");
    355 }
    356 
    357 /* Determine if PTRACE_O_EXITKILL can be used.  */
    358 
    359 static void
    360 linux_test_for_exitkill (int child_pid)
    361 {
    362   int ret;
    363 
    364   ret = ptrace (PTRACE_SETOPTIONS, child_pid, (PTRACE_TYPE_ARG3) 0,
    365 		(PTRACE_TYPE_ARG4) PTRACE_O_EXITKILL);
    366 
    367   if (ret == 0)
    368     supported_ptrace_options |= PTRACE_O_EXITKILL;
    369 }
    370 
    371 /* Enable reporting of all currently supported ptrace events.
    372    OPTIONS is a bit mask of extended features we want enabled,
    373    if supported by the kernel.  PTRACE_O_TRACECLONE is always
    374    enabled, if supported.  */
    375 
    376 void
    377 linux_enable_event_reporting (pid_t pid, int options)
    378 {
    379   /* Check if we have initialized the ptrace features for this
    380      target.  If not, do it now.  */
    381   if (supported_ptrace_options == -1)
    382     linux_check_ptrace_features ();
    383 
    384   /* We always want clone events.  */
    385   options |= PTRACE_O_TRACECLONE;
    386 
    387   /* Filter out unsupported options.  */
    388   options &= supported_ptrace_options;
    389 
    390   /* Set the options.  */
    391   ptrace (PTRACE_SETOPTIONS, pid, (PTRACE_TYPE_ARG3) 0,
    392 	  (PTRACE_TYPE_ARG4) (uintptr_t) options);
    393 }
    394 
    395 /* Disable reporting of all currently supported ptrace events.  */
    396 
    397 void
    398 linux_disable_event_reporting (pid_t pid)
    399 {
    400   /* Set the options.  */
    401   ptrace (PTRACE_SETOPTIONS, pid, (PTRACE_TYPE_ARG3) 0, 0);
    402 }
    403 
    404 /* Display possible problems on this system.  Display them only once per GDB
    405    execution.  */
    406 
    407 void
    408 linux_ptrace_init_warnings (void)
    409 {
    410   static int warned = 0;
    411 
    412   if (warned)
    413     return;
    414   warned = 1;
    415 
    416   linux_ptrace_test_ret_to_nx ();
    417 }
    418 
    419 /* Extract extended ptrace event from wait status.  */
    420 
    421 int
    422 linux_ptrace_get_extended_event (int wstat)
    423 {
    424   return (wstat >> 16);
    425 }
    426 
    427 /* Determine whether wait status denotes an extended event.  */
    428 
    429 int
    430 linux_is_extended_waitstatus (int wstat)
    431 {
    432   return (linux_ptrace_get_extended_event (wstat) != 0);
    433 }
    434 
    435 /* Return true if the event in LP may be caused by breakpoint.  */
    436 
    437 int
    438 linux_wstatus_maybe_breakpoint (int wstat)
    439 {
    440   return (WIFSTOPPED (wstat)
    441 	  && (WSTOPSIG (wstat) == SIGTRAP
    442 	      /* SIGILL and SIGSEGV are also treated as traps in case a
    443 		 breakpoint is inserted at the current PC.  */
    444 	      || WSTOPSIG (wstat) == SIGILL
    445 	      || WSTOPSIG (wstat) == SIGSEGV));
    446 }
    447