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