diff options
author | Mark Wielaard <mjw@redhat.com> | 2015-12-01 22:16:00 +0100 |
---|---|---|
committer | Mark Wielaard <mjw@redhat.com> | 2016-01-02 20:37:45 +0100 |
commit | 355b408bb9aa49703544fa4086e1ae463737fcf6 (patch) | |
tree | 9ac6581d1cb66dc4b6c2328c715308db7cfc20af | |
parent | a1372e06a04bad29e8c3c79d95497a8e381f823f (diff) | |
download | elfutils-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/ChangeLog | 14 | ||||
-rw-r--r-- | libdwfl/argp-std.c | 16 | ||||
-rw-r--r-- | libdwfl/core-file.c | 22 | ||||
-rw-r--r-- | libdwfl/dwfl_build_id_find_elf.c | 9 | ||||
-rw-r--r-- | libdwfl/dwfl_end.c | 12 | ||||
-rw-r--r-- | libdwfl/libdwflP.h | 14 | ||||
-rw-r--r-- | libdwfl/link_map.c | 12 |
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) |