]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
libdwfl: Don't leak core Elf and core file descriptor from argp-std.
authorMark Wielaard <mjw@redhat.com>
Tue, 1 Dec 2015 21:16:00 +0000 (22:16 +0100)
committerMark Wielaard <mjw@redhat.com>
Sat, 2 Jan 2016 19:37:45 +0000 (20:37 +0100)
Our argp helper would leak the core Elf and core file descriptor when
given by the user. Store both in the Dwfl as a new Dwfl_User_Core so
they get cleaned up by dwfl_end.

Signed-off-by: Mark Wielaard <mjw@redhat.com>
libdwfl/ChangeLog
libdwfl/argp-std.c
libdwfl/core-file.c
libdwfl/dwfl_build_id_find_elf.c
libdwfl/dwfl_end.c
libdwfl/libdwflP.h
libdwfl/link_map.c

index 4d1abe19b00441429307145488976dad00f81b94..3916cbf5730f8712ab5dcea0a9875b065ccc23ca 100644 (file)
@@ -1,3 +1,17 @@
+2015-12-01  Mark Wielaard  <mjw@redhat.com>
+
+       * libdwflP.h (struct Dwfl_User_Core): New.
+       (struct DWfl): Replace executable_for_core with user_core.
+       * argp-std.c (parse_opt): Store core and fd in Dwfl user_core.
+       * core-file.c (dwfl_core_file_report): Check and store
+       executable_for_core in Dwfl user_core.
+       * dwfl_build_id_find_elf.c (dwfl_build_id_find_elf): Check and use
+       executable_for_core in Dwfl user_core.
+       * dwfl_end.c (dwfl_end): Release resources held in Dwfl user_core.
+       * link-map.c (report_r_debug): Check executable_for_core in Dwfl
+       user_core.
+       (dwfl_link_map_report): Likewise.
+
 2015-11-16  Chih-Hung Hsieh <chh@google.com>
 
        * dwfl_module_getdwarf.c (find_prelink_address_sync): Move nested
index 2bbf74fc5f53b26d18618eacbe331d4e887cbddc..501530a5b8acdb98f3a991b0e1b8b1a6974df73f 100644 (file)
@@ -1,5 +1,5 @@
 /* Standard argp argument parsers for tools using libdwfl.
-   Copyright (C) 2005-2010, 2012 Red Hat, Inc.
+   Copyright (C) 2005-2010, 2012, 2015 Red Hat, Inc.
    This file is part of elfutils.
 
    This file is free software; you can redistribute it and/or modify
@@ -303,7 +303,19 @@ parse_opt (int key, char *arg, struct argp_state *state)
            /* Non-fatal to not be able to attach to core, ignore error.  */
            INTUSE(dwfl_core_file_attach) (dwfl, core);
 
-           /* From now we leak FD and CORE.  */
+           /* Store core Elf and fd in Dwfl to expose with dwfl_end.  */
+           if (dwfl->user_core == NULL)
+             {
+               dwfl->user_core = calloc (1, sizeof (struct Dwfl_User_Core));
+               if (dwfl->user_core == NULL)
+                 {
+                   argp_failure (state, EXIT_FAILURE, 0,
+                                 _("Not enough memory"));
+                   return ENOMEM;
+                 }
+             }
+           dwfl->user_core->core = core;
+           dwfl->user_core->fd = fd;
 
            if (result == 0)
              {
index b317ecaa6e6c69e348b85477d9a9cd55523bc4c7..6ba38f7222fcbc243e62be57eeb16b2e8fea1f2d 100644 (file)
@@ -441,13 +441,27 @@ dwfl_core_file_report (Dwfl *dwfl, Elf *elf, const char *executable)
       return -1;
     }
 
-  free (dwfl->executable_for_core);
+  if (dwfl->user_core != NULL)
+    free (dwfl->user_core->executable_for_core);
   if (executable == NULL)
-    dwfl->executable_for_core = NULL;
+    {
+      if (dwfl->user_core != NULL)
+       dwfl->user_core->executable_for_core = NULL;
+    }
   else
     {
-      dwfl->executable_for_core = strdup (executable);
-      if (dwfl->executable_for_core == NULL)
+      if (dwfl->user_core == NULL)
+       {
+         dwfl->user_core = calloc (1, sizeof (struct Dwfl_User_Core));
+         if (dwfl->user_core == NULL)
+           {
+             __libdwfl_seterrno (DWFL_E_NOMEM);
+             return -1;
+           }
+         dwfl->user_core->fd = -1;
+       }
+      dwfl->user_core->executable_for_core = strdup (executable);
+      if (dwfl->user_core->executable_for_core == NULL)
        {
          __libdwfl_seterrno (DWFL_E_NOMEM);
          return -1;
index 2e30b7abb1c572531c6d88b51665a06e5d68382e..903e19319566f71a37060224abd5ea7c28a2857c 100644 (file)
@@ -140,16 +140,19 @@ dwfl_build_id_find_elf (Dwfl_Module *mod,
                        char **file_name, Elf **elfp)
 {
   *elfp = NULL;
-  if (mod->is_executable && mod->dwfl->executable_for_core != NULL)
+  if (mod->is_executable
+      && mod->dwfl->user_core != NULL
+      && mod->dwfl->user_core->executable_for_core != NULL)
     {
       /* When dwfl_core_file_report was called with a non-NULL executable file
         name this callback will replace the Dwfl_Module main.name with the
         recorded executable file when MOD was identified as main executable
         (which then triggers opening and reporting of the executable).  */
-      int fd = open (mod->dwfl->executable_for_core, O_RDONLY);
+      const char *executable = mod->dwfl->user_core->executable_for_core;
+      int fd = open (executable, O_RDONLY);
       if (fd >= 0)
        {
-         *file_name = strdup (mod->dwfl->executable_for_core);
+         *file_name = strdup (executable);
          if (*file_name != NULL)
            return fd;
          else
index 33cae48cd1aa9a6cb62ca89902cb4183269684d4..0b35bd28278cfb3ee40019fa9cf23bf9bc9f180d 100644 (file)
@@ -1,5 +1,5 @@
 /* Finish a session using libdwfl.
-   Copyright (C) 2005, 2008, 2012-2013 Red Hat, Inc.
+   Copyright (C) 2005, 2008, 2012-2013, 2015 Red Hat, Inc.
    This file is part of elfutils.
 
    This file is free software; you can redistribute it and/or modify
@@ -27,6 +27,7 @@
    not, see <http://www.gnu.org/licenses/>.  */
 
 #include "libdwflP.h"
+#include <unistd.h>
 
 void
 dwfl_end (Dwfl *dwfl)
@@ -49,6 +50,13 @@ dwfl_end (Dwfl *dwfl)
       __libdwfl_module_free (dead);
     }
 
-  free (dwfl->executable_for_core);
+  if (dwfl->user_core != NULL)
+    {
+      free (dwfl->user_core->executable_for_core);
+      elf_end (dwfl->user_core->core);
+      if (dwfl->user_core->fd != -1)
+       close (dwfl->user_core->fd);
+      free (dwfl->user_core);
+    }
   free (dwfl);
 }
index 63556d511b6ee7845373c79cdcaec86c8b952991..2a83646e3f603724a67a0f4c3a1d6ef4b43b394b 100644 (file)
@@ -1,5 +1,5 @@
 /* Internal definitions for libdwfl.
-   Copyright (C) 2005-2014 Red Hat, Inc.
+   Copyright (C) 2005-2015 Red Hat, Inc.
    This file is part of elfutils.
 
    This file is free software; you can redistribute it and/or modify
@@ -104,6 +104,16 @@ typedef enum { DWFL_ERRORS DWFL_E_NUM } Dwfl_Error;
 extern int __libdwfl_canon_error (Dwfl_Error) internal_function;
 extern void __libdwfl_seterrno (Dwfl_Error) internal_function;
 
+/* Resources we might keep for the user about the core file that the
+   Dwfl might have been created from.  Can currently only be set
+   through std-argp.  */
+struct Dwfl_User_Core
+{
+  char *executable_for_core;   /* --executable if --core was specified.  */
+  Elf *core;                    /* non-NULL if we need to free it.  */
+  int fd;                       /* close if >= 0.  */
+};
+
 struct Dwfl
 {
   const Dwfl_Callbacks *callbacks;
@@ -130,7 +140,7 @@ struct Dwfl
   GElf_Off lookup_tail_offset;
   int lookup_tail_ndx;
 
-  char *executable_for_core;   /* --executable if --core was specified.  */
+  struct Dwfl_User_Core *user_core;
 };
 
 #define OFFLINE_REDZONE                0x10000
index 13cac52912e377b933f7615b0d516296088dd36e..e73b21955fa57f9ab7bbea4ba7c42136a8bc9c70 100644 (file)
@@ -356,8 +356,10 @@ report_r_debug (uint_fast8_t elfclass, uint_fast8_t elfdata,
       if (name != NULL && name[0] == '\0')
        name = NULL;
 
-      if (iterations == 1 && dwfl->executable_for_core != NULL)
-       name = dwfl->executable_for_core;
+      if (iterations == 1
+         && dwfl->user_core != NULL
+         && dwfl->user_core->executable_for_core != NULL)
+       name = dwfl->user_core->executable_for_core;
 
       struct r_debug_info_module *r_debug_info_module = NULL;
       if (r_debug_info != NULL)
@@ -789,7 +791,9 @@ dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size,
          bool in_ok = (*memory_callback) (dwfl, phdr_segndx, &in.d_buf,
                                           &in.d_size, phdr, phnum * phent,
                                           memory_callback_arg);
-         if (! in_ok && dwfl->executable_for_core != NULL)
+         if (! in_ok
+             && dwfl->user_core != NULL
+             && dwfl->user_core->executable_for_core != NULL)
            {
              /* AUXV -> PHDR -> DYNAMIC
                 Both AUXV and DYNAMIC should be always present in a core file.
@@ -797,7 +801,7 @@ dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size,
                 EXECUTABLE_FOR_CORE to find where DYNAMIC is located in the
                 core file.  */
 
-             int fd = open (dwfl->executable_for_core, O_RDONLY);
+             int fd = open (dwfl->user_core->executable_for_core, O_RDONLY);
              Elf *elf;
              Dwfl_Error error = DWFL_E_ERRNO;
              if (fd != -1)