[PATCH v2] Improve ptrace-error detection on Linux targets

Christian Biesinger via gdb-patches gdb-patches@sourceware.org
Mon Aug 26 18:35:00 GMT 2019


On Mon, Aug 26, 2019 at 1:32 PM Sergio Durigan Junior
<sergiodj@redhat.com> wrote:
> @@ -30,11 +32,70 @@
>     of 0 means there are no supported features.  */
>  static int supported_ptrace_options = -1;
>
> -/* Find all possible reasons we could fail to attach PID and return these
> -   as a string.  An empty string is returned if we didn't find any reason.  */
> +typedef int (*selinux_ftype) (const char *);
> +
> +/* Helper function which checks if ptrace is probably restricted
> +   (i.e., if ERR is either EACCES or EPERM), and returns a string with
> +   possible workarounds.  */
> +
> +static std::string
> +linux_ptrace_restricted_fail_reason (int err)
> +{
> +  if (err != EACCES && err != EPERM)
> +    {
> +      /* It just makes sense to perform the checks below if errno was
> +        either EACCES or EPERM.  */
> +      return {};
> +    }
> +
> +  std::string ret;
> +  gdb_dlhandle_up handle = gdb_dlopen ("libselinux.so", true);

I would dlopen libselinux.so.1 instead so that this works even without
the -dev package.

> +
> +  if (handle.get () != NULL)
> +    {
> +      selinux_ftype selinux_get_bool
> +       = (selinux_ftype) gdb_dlsym (handle, "security_get_boolean_active");
> +
> +      if (selinux_get_bool != NULL
> +         && (*selinux_get_bool) ("deny_ptrace") == 1)
> +       string_appendf (ret,
> +                       _("\n\
> +The SELinux 'deny_ptrace' option is enabled and preventing GDB\n\
> +from using 'ptrace'.  Please, disable it by executing (as root):\n\
> +\n\
> +  setsebool deny_ptrace off\n"));
> +    }
> +
> +  FILE *f = fopen ("/proc/sys/kernel/yama/ptrace_scope", "r");
> +
> +  if (f != NULL)
> +    {
> +      char yama_scope = fgetc (f);
> +
> +      fclose (f);
> +
> +      if (yama_scope != '0')
> +       string_appendf (ret,
> +                       _("\n\
> +The Linux kernel's Yama ptrace scope is in effect, which can prevent\n\
> +GDB from using 'ptrace'.  Please, disable it by executing (as root):\n\
> +\n\
> +  echo 0 > /proc/sys/kernel/yama/ptrace_scope\n"));
> +    }
> +
> +  if (ret.empty ())
> +    ret = _("\n\
> +There might be restrictions preventing ptrace from working.  Please see\n\
> +the appendix \"Linux kernel ptrace restrictions\" in the GDB documentation\n\
> +for more details.\n");
> +
> +  return ret;
> +}
> +
> +/* See declaration in linux-ptrace.h.  */
>
>  std::string
> -linux_ptrace_attach_fail_reason (pid_t pid)
> +linux_ptrace_attach_fail_reason (pid_t pid, int err)
>  {
>    pid_t tracerpid = linux_proc_get_tracerpid_nowarn (pid);
>    std::string result;
> @@ -50,6 +111,11 @@ linux_ptrace_attach_fail_reason (pid_t pid)
>                       "terminated"),
>                     (int) pid);
>
> +  std::string ptrace_restrict = linux_ptrace_restricted_fail_reason (err);
> +
> +  if (!ptrace_restrict.empty ())
> +    result += "\n" + ptrace_restrict;
> +
>    return result;
>  }
>
> @@ -68,6 +134,14 @@ linux_ptrace_attach_fail_reason_string (ptid_t ptid, int err)
>      return string_printf ("%s (%d)", safe_strerror (err), err);
>  }
>
> +/* See linux-ptrace.h.  */
> +
> +std::string
> +linux_ptrace_me_fail_reason (int err)
> +{
> +  return linux_ptrace_restricted_fail_reason (err);
> +}
> +
>  #if defined __i386__ || defined __x86_64__
>
>  /* Address of the 'ret' instruction in asm code block below.  */
> @@ -321,7 +395,11 @@ linux_grandchild_function (void *child_stack)
>  static int
>  linux_child_function (void *child_stack)
>  {
> -  ptrace (PTRACE_TRACEME, 0, (PTRACE_TYPE_ARG3) 0, (PTRACE_TYPE_ARG4) 0);
> +  if (ptrace (PTRACE_TRACEME, 0, (PTRACE_TYPE_ARG3) 0,
> +             (PTRACE_TYPE_ARG4) 0) != 0)
> +    trace_start_error_with_name ("ptrace",
> +                                linux_ptrace_me_fail_reason (errno).c_str ());
> +
>    kill (getpid (), SIGSTOP);
>
>    /* Fork a grandchild.  */
> diff --git a/gdb/nat/linux-ptrace.h b/gdb/nat/linux-ptrace.h
> index fd2f12a342..04ada53bf6 100644
> --- a/gdb/nat/linux-ptrace.h
> +++ b/gdb/nat/linux-ptrace.h
> @@ -176,13 +176,26 @@ struct buffer;
>  # define TRAP_HWBKPT 4
>  #endif
>
> -extern std::string linux_ptrace_attach_fail_reason (pid_t pid);
> +/* Find all possible reasons we could fail to attach PID and return
> +   these as a string.  An empty string is returned if we didn't find
> +   any reason.  If ERR is EACCES or EPERM, we also add a warning about
> +   possible restrictions to use ptrace.  */
> +extern std::string linux_ptrace_attach_fail_reason (pid_t pid, int err = -1);
>
>  /* Find all possible reasons we could have failed to attach to PTID
>     and return them as a string.  ERR is the error PTRACE_ATTACH failed
>     with (an errno).  */
>  extern std::string linux_ptrace_attach_fail_reason_string (ptid_t ptid, int err);
>
> +/* When the call to 'ptrace (PTRACE_TRACEME...' fails, and we have
> +   already forked, this function can be called in order to try to
> +   obtain the reason why ptrace failed.  ERR should be the ERRNO value
> +   returned by ptrace.
> +
> +   This function will return a 'std::string' containing the fail
> +   reason, or an empty string otherwise.  */
> +extern std::string linux_ptrace_me_fail_reason (int err);
> +
>  extern void linux_ptrace_init_warnings (void);
>  extern void linux_check_ptrace_features (void);
>  extern void linux_enable_event_reporting (pid_t pid, int attached);
> --
> 2.21.0
>



More information about the Gdb-patches mailing list