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