summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Wielaard <mjw@redhat.com>2015-12-01 22:16:00 +0100
committerMark Wielaard <mjw@redhat.com>2016-01-02 20:37:45 +0100
commit355b408bb9aa49703544fa4086e1ae463737fcf6 (patch)
tree9ac6581d1cb66dc4b6c2328c715308db7cfc20af
parenta1372e06a04bad29e8c3c79d95497a8e381f823f (diff)
downloadelfutils-355b408bb9aa49703544fa4086e1ae463737fcf6.tar.gz
libdwfl: Don't leak core Elf and core file descriptor from argp-std.
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>
-rw-r--r--libdwfl/ChangeLog14
-rw-r--r--libdwfl/argp-std.c16
-rw-r--r--libdwfl/core-file.c22
-rw-r--r--libdwfl/dwfl_build_id_find_elf.c9
-rw-r--r--libdwfl/dwfl_end.c12
-rw-r--r--libdwfl/libdwflP.h14
-rw-r--r--libdwfl/link_map.c12
7 files changed, 82 insertions, 17 deletions
diff --git a/libdwfl/ChangeLog b/libdwfl/ChangeLog
index 4d1abe19..3916cbf5 100644
--- a/libdwfl/ChangeLog
+++ b/libdwfl/ChangeLog
@@ -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
diff --git a/libdwfl/argp-std.c b/libdwfl/argp-std.c
index 2bbf74fc..501530a5 100644
--- a/libdwfl/argp-std.c
+++ b/libdwfl/argp-std.c
@@ -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)
{
diff --git a/libdwfl/core-file.c b/libdwfl/core-file.c
index b317ecaa..6ba38f72 100644
--- a/libdwfl/core-file.c
+++ b/libdwfl/core-file.c
@@ -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;
diff --git a/libdwfl/dwfl_build_id_find_elf.c b/libdwfl/dwfl_build_id_find_elf.c
index 2e30b7ab..903e1931 100644
--- a/libdwfl/dwfl_build_id_find_elf.c
+++ b/libdwfl/dwfl_build_id_find_elf.c
@@ -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
diff --git a/libdwfl/dwfl_end.c b/libdwfl/dwfl_end.c
index 33cae48c..0b35bd28 100644
--- a/libdwfl/dwfl_end.c
+++ b/libdwfl/dwfl_end.c
@@ -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);
}
diff --git a/libdwfl/libdwflP.h b/libdwfl/libdwflP.h
index 63556d51..2a83646e 100644
--- a/libdwfl/libdwflP.h
+++ b/libdwfl/libdwflP.h
@@ -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
diff --git a/libdwfl/link_map.c b/libdwfl/link_map.c
index 13cac529..e73b2195 100644
--- a/libdwfl/link_map.c
+++ b/libdwfl/link_map.c
@@ -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)